From b3743ee15cd9bdfd74ca9729875a9bb74b9feb01 Mon Sep 17 00:00:00 2001 From: Trong Do Date: Mon, 3 Aug 2026 22:07:51 +0700 Subject: [PATCH 1/3] [BE] Problem 4: Three ways to sum to n --- src/problem4/.gitignore | 4 + src/problem4/AUDIT-LOG-SAMPLE.jsonl | 3 + src/problem4/DEEP-STRESS-REPORT.md | 75 ++ src/problem4/README.md | 134 +++ src/problem4/STRESS-RESULTS.md | 73 ++ src/problem4/audit-sample.ts | 18 + src/problem4/audit.ts | 257 ++++++ src/problem4/benchmark.ts | 39 + src/problem4/concurrency-worker.ts | 61 ++ src/problem4/deep-stress-result.json | 85 ++ src/problem4/deep-stress.ts | 1283 ++++++++++++++++++++++++++ src/problem4/index.test.ts | 183 ++++ src/problem4/index.ts | 101 ++ src/problem4/logs/.gitkeep | 0 src/problem4/node-shims.d.ts | 15 + src/problem4/package-lock.json | 29 + src/problem4/package.json | 17 + src/problem4/run.ts | 51 + src/problem4/service.ts | 147 +++ src/problem4/stress-test.ts | 358 +++++++ src/problem4/tsconfig.json | 16 + src/problem4/verify-audit.ts | 132 +++ 22 files changed, 3081 insertions(+) create mode 100644 src/problem4/.gitignore create mode 100644 src/problem4/AUDIT-LOG-SAMPLE.jsonl create mode 100644 src/problem4/DEEP-STRESS-REPORT.md create mode 100644 src/problem4/README.md create mode 100644 src/problem4/STRESS-RESULTS.md create mode 100644 src/problem4/audit-sample.ts create mode 100644 src/problem4/audit.ts create mode 100644 src/problem4/benchmark.ts create mode 100644 src/problem4/concurrency-worker.ts create mode 100644 src/problem4/deep-stress-result.json create mode 100644 src/problem4/deep-stress.ts create mode 100644 src/problem4/index.test.ts create mode 100644 src/problem4/index.ts create mode 100644 src/problem4/logs/.gitkeep create mode 100644 src/problem4/node-shims.d.ts create mode 100644 src/problem4/package-lock.json create mode 100644 src/problem4/package.json create mode 100644 src/problem4/run.ts create mode 100644 src/problem4/service.ts create mode 100644 src/problem4/stress-test.ts create mode 100644 src/problem4/tsconfig.json create mode 100644 src/problem4/verify-audit.ts diff --git a/src/problem4/.gitignore b/src/problem4/.gitignore new file mode 100644 index 0000000000..1ce1fe20d8 --- /dev/null +++ b/src/problem4/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +logs/*.jsonl +!logs/.gitkeep diff --git a/src/problem4/AUDIT-LOG-SAMPLE.jsonl b/src/problem4/AUDIT-LOG-SAMPLE.jsonl new file mode 100644 index 0000000000..be14640c2c --- /dev/null +++ b/src/problem4/AUDIT-LOG-SAMPLE.jsonl @@ -0,0 +1,3 @@ +{"sequence":1,"timestamp":"2026-08-03T14:45:23.605Z","traceId":"2315985c-14c5-4efc-9ed5-8bd9913fb17a","action":"SUM_TO_N","status":"SUCCESS","input":100,"result":5050,"durationMs":0,"inputHash":"ad57366865126e55649ecb23ae1d48887544976efea46a48eb5d85a6eeb4d306","outputHash":"3f95b1b8a32c2c0251dfdbc3c8a30aab6d6e680cf0ef03e8af84a65dff0c4a85","error":null,"previousHash":null,"recordHash":"2391ef1857dbea8762c44c4a9601f3e3c6e4c2e895419af0594bf8e192f65454"} +{"sequence":2,"timestamp":"2026-08-03T14:45:23.606Z","traceId":"58437f1b-deed-449b-94cf-57a4bc524145","action":"SUM_TO_N","status":"SUCCESS","input":100,"result":5050,"durationMs":0,"inputHash":"ad57366865126e55649ecb23ae1d48887544976efea46a48eb5d85a6eeb4d306","outputHash":"3f95b1b8a32c2c0251dfdbc3c8a30aab6d6e680cf0ef03e8af84a65dff0c4a85","error":null,"previousHash":"2391ef1857dbea8762c44c4a9601f3e3c6e4c2e895419af0594bf8e192f65454","recordHash":"e02ac73c838b10c50a89643236797a0a45d2027e7bdd5d10b7556b0ba0e98f47"} +{"sequence":3,"timestamp":"2026-08-03T14:45:23.606Z","traceId":"b829134f-6999-48d6-8e3c-6081ccb4cf35","action":"SUM_TO_N","status":"SUCCESS","input":100,"result":5050,"durationMs":0,"inputHash":"ad57366865126e55649ecb23ae1d48887544976efea46a48eb5d85a6eeb4d306","outputHash":"3f95b1b8a32c2c0251dfdbc3c8a30aab6d6e680cf0ef03e8af84a65dff0c4a85","error":null,"previousHash":"e02ac73c838b10c50a89643236797a0a45d2027e7bdd5d10b7556b0ba0e98f47","recordHash":"729ebcf3f9e52a1f0b6025d856ea42f6ecc45d048117c1fb39f8d2128ab6b025"} diff --git a/src/problem4/DEEP-STRESS-REPORT.md b/src/problem4/DEEP-STRESS-REPORT.md new file mode 100644 index 0000000000..af1e2fe37a --- /dev/null +++ b/src/problem4/DEEP-STRESS-REPORT.md @@ -0,0 +1,75 @@ +# Problem 4 — Deep stress-test report + +## Result + +```text +Status: STRESS_TEST_PASS +Assertions: 1,197,832 +Maximum safe-result input: 134,217,727 +Elapsed: 1,307 ms +Suites: 13 +``` + +## Coverage executed + +- Fixed positive, negative, zero, and known-result cases. +- Exhaustive verification of all three functions from `-12,000` through `12,000`. +- 8,000 deterministic random inputs through all three functions. +- 200,000 deterministic random inputs across the complete safe-result domain for solutions A and C. +- 8,192 values immediately below the safe-result boundary, checked with both signs. +- Exact maximum safe input executed through solution B despite its linear complexity. +- First overflowing result rejected by all three functions. +- Values surrounding powers of two. +- Recurrence and sign-symmetry metamorphic properties. +- Invalid values: `NaN`, infinities, decimals, and unsafe integers. +- 315 sequential success/failure audit records. +- 600 concurrent records written by eight Node.js processes. +- Unique `traceId` verification for concurrent records. +- Audit chain verification after concurrent writes. +- Seven tamper/corruption scenarios. +- Confirmation that audit records contain no `algorithm` field. + +## Suite timings + +| Suite | Assertions | Elapsed | +|---|---:|---:| +| Fixed examples and signed edges | 36 | 1 ms | +| Exhaustive all-functions range | 96,004 | 96 ms | +| Random moderate range for all functions | 32,000 | 22 ms | +| Full safe-domain random test for A and C | 600,000 | 165 ms | +| Safe-result boundary sweep | 49,154 | 129 ms | +| Result-overflow rejection | 3 | 111 ms | +| Power-of-two neighborhoods | 672 | 2 ms | +| Metamorphic identities for all functions | 18,000 | 23 ms | +| Full-domain metamorphic identities for A and C | 400,000 | 144 ms | +| Invalid runtime inputs | 18 | 1 ms | +| Sequential success and failure audit chain | 733 | 112 ms | +| Concurrent multi-process audit chain | 1,203 | 497 ms | +| Audit tamper and corruption detection | 9 | 4 ms | + +## Tamper scenarios detected + +1. Modified result without recomputing the record hash. +2. Broken `previousHash`. +3. Deleted middle record. +4. Reordered records. +5. Duplicated record. +6. Malformed JSON. +7. Truncated final record. + +## Commands + +```bat +npm test +npm run stress +``` + +`npm run stress` executes the deep suite. `npm run stress:quick` keeps the +smaller suite for fast local checks. + +## Boundary of this test + +No finite test can prove correctness for every possible runtime environment. +This suite combines exhaustive ranges, independent `BigInt` oracles, +full-domain deterministic sampling, mathematical invariants, exact boundary +execution, concurrent audit writes, and deliberate log corruption. diff --git a/src/problem4/README.md b/src/problem4/README.md new file mode 100644 index 0000000000..7dd92e3b0d --- /dev/null +++ b/src/problem4/README.md @@ -0,0 +1,134 @@ +# Problem 4 — Three functions with audit log + +All three challenge functions remain pure and have explanatory comments +directly above them. + +Each function has a corresponding audited service wrapper: + +```text +executeSumAWithAudit +executeSumBWithAudit +executeSumCWithAudit +``` + +The audit log does not contain an `algorithm` field. + +## Run one function + +```bat +cd /d D:\99\code-challenge\src\problem4 +npm install + +npm start -- a 100 +npm start -- b 100 +npm start -- c 100 +``` + +Each command prints the result directly: + +```text +5050 +``` + +Each function call appends one record to: + +```text +logs/problem4-audit.jsonl +``` + +After running A, B, and C, the log contains three records. + +## Generate three audit records at once + +```bat +npm run audit:sample -- 100 +``` + +## Audit fields + +```text +sequence +timestamp +traceId +action +status +input +result +durationMs +inputHash +outputHash +error +previousHash +recordHash +``` + +There is no `algorithm` field. + +## Verify audit integrity + +```bat +npm run audit:verify +``` + +Expected after the sample command: + +```text +AUDIT_OK records=3 +``` + +## Test + +```bat +npm test +``` + +Expected result: + +```text +PASS +``` + + +## Stress test + +Run correctness, boundary, invalid-input, and audit-chain stress checks: + +```bat +npm run stress +``` + +Expected output: + +```text +STRESS_TEST_PASS +assertions=... +auditRecords=300 +safeBoundary=134217727 +elapsedMs=... +``` + +The stress test does not benchmark or compare algorithms. + + +## Deep stress test + +```bat +npm run stress +``` + +This runs exhaustive, random full-domain, exact-boundary, overflow, +metamorphic, invalid-input, sequential audit, concurrent multi-process audit, +and tamper-detection checks. + +The verified output from the packaged run is documented in: + +```text +DEEP-STRESS-REPORT.md +deep-stress-result.json +``` + +For a faster local check: + +```bat +npm run stress:quick +``` diff --git a/src/problem4/STRESS-RESULTS.md b/src/problem4/STRESS-RESULTS.md new file mode 100644 index 0000000000..0d60020cd2 --- /dev/null +++ b/src/problem4/STRESS-RESULTS.md @@ -0,0 +1,73 @@ +# Problem 4 — Stress-test results + +## Verification status + +```text +Status: PASSED +Assertions: 1,869,698 +Maximum safe-result input: 134,217,727 +Node.js: v22.16.0 +Version 5.8.3 +``` + +## Test coverage + +The automated stress suite verifies: + +1. fixed examples, zero, and signed edge cases; +2. independent iterative accumulation for every input from `-100,000` to `100,000`; +3. 250,000 deterministic random inputs checked against a `BigInt` oracle; +4. 4,096 values at both positive and negative safe-result boundaries; +5. powers of two and neighboring values; +6. recurrence and sign metamorphic identities; +7. invalid runtime inputs; +8. warmed, multi-round performance benchmarks with rotating execution order. + +## Benchmark + +The benchmark uses varying valid inputs, 40,000 warm-up calls per +implementation, 9 measured rounds, and 120,000 calls per round. + +| Rank | Implementation | Median | Operations/second | Relative | +|---:|---|---:|---:|---:| +| 1 | `sum_to_n_a` — Gauss formula | 1.574 ms | 76,220,723 | 1.00× | +| 2 | `sum_to_n_c` — Binary block decomposition | 24.352 ms | 4,927,689 | 15.47× | +| 3 | `sum_to_n_b` — Matrix exponentiation | 192.863 ms | 622,202 | 122.50× | + +## Best algorithm + +### `sum_to_n_a` — Gauss formula + +It is the best implementation for this exact problem because it has: + +```text +Time: O(1) +Space: O(1) +``` + +It also has the smallest implementation surface and the lowest measured median +runtime in this stress test. + +### Why not B? + +`sum_to_n_b` is algorithmically interesting and demonstrates matrix +exponentiation, but it performs many fixed-size matrix multiplications. Its +`O(log |n|)` complexity cannot beat a direct `O(1)` identity for this problem. + +### Why not C? + +`sum_to_n_c` is more lightweight than matrix exponentiation and demonstrates +binary decomposition, but it still inspects `O(log |n|)` blocks. It is useful +as an alternative algorithm, not as the production choice. + +## Recommendation + +Keep all three functions because the task explicitly requests three unique +implementations, but treat `sum_to_n_a` as the preferred implementation. + +```ts +export const sum_to_n = sum_to_n_a; +``` + +Benchmark timing is environment-dependent. The correctness result and +asymptotic recommendation do not depend on the benchmark machine. diff --git a/src/problem4/audit-sample.ts b/src/problem4/audit-sample.ts new file mode 100644 index 0000000000..aae95e7c9b --- /dev/null +++ b/src/problem4/audit-sample.ts @@ -0,0 +1,18 @@ +import { + executeSumAWithAudit, + executeSumBWithAudit, + executeSumCWithAudit, +} from "./service"; + +const input = process.argv[2] ?? "100"; + +const resultA = + executeSumAWithAudit(input).result; +const resultB = + executeSumBWithAudit(input).result; +const resultC = + executeSumCWithAudit(input).result; + +console.log(resultA); +console.log(resultB); +console.log(resultC); diff --git a/src/problem4/audit.ts b/src/problem4/audit.ts new file mode 100644 index 0000000000..a367fe2ca0 --- /dev/null +++ b/src/problem4/audit.ts @@ -0,0 +1,257 @@ +const { + createHash, + randomUUID, +} = require("node:crypto"); + +const { + appendFileSync, + existsSync, + mkdirSync, + readFileSync, + rmSync, + statSync, +} = require("node:fs"); + +const { + dirname, + resolve, +} = require("node:path"); + +export const DEFAULT_AUDIT_FILE: string = resolve( + process.cwd(), + "logs", + "problem4-audit.jsonl", +); + +export interface AuditRecord { + sequence: number; + timestamp: string; + traceId: string; + action: "SUM_TO_N"; + status: "SUCCESS" | "FAILED"; + input: number | string; + result: number | null; + durationMs: number; + inputHash: string; + outputHash: string | null; + error: string | null; + previousHash: string | null; + recordHash: string; +} + +type UnsignedAuditRecord = Omit< + AuditRecord, + "recordHash" +>; + +function sha256(value: string): string { + return createHash("sha256") + .update(value, "utf8") + .digest("hex"); +} + +function canonical( + record: UnsignedAuditRecord, +): string { + return JSON.stringify({ + sequence: record.sequence, + timestamp: record.timestamp, + traceId: record.traceId, + action: record.action, + status: record.status, + input: record.input, + result: record.result, + durationMs: record.durationMs, + inputHash: record.inputHash, + outputHash: record.outputHash, + error: record.error, + previousHash: record.previousHash, + }); +} + +function readRecords( + file: string, +): AuditRecord[] { + if (!existsSync(file)) { + return []; + } + + const content = String( + readFileSync(file, "utf8"), + ).trim(); + + if (!content) { + return []; + } + + return content + .split(/\r?\n/) + .filter(Boolean) + .map( + ( + line: string, + index: number, + ) => { + try { + return JSON.parse( + line, + ) as AuditRecord; + } catch { + throw new Error( + `Invalid audit JSON at line ${index + 1}`, + ); + } + }, + ); +} + +function sleep(milliseconds: number): void { + const buffer = new SharedArrayBuffer(4); + const view = new Int32Array(buffer); + + Atomics.wait( + view, + 0, + 0, + milliseconds, + ); +} + +function acquireAuditLock( + file: string, +): () => void { + mkdirSync( + dirname(file), + { recursive: true }, + ); + + const lockDirectory = + `${file}.lock`; + + const timeoutAt = + Date.now() + 15_000; + + while (true) { + try { + mkdirSync(lockDirectory); + + return () => { + rmSync( + lockDirectory, + { + recursive: true, + force: true, + }, + ); + }; + } catch (error) { + const code = + ( + error as { + code?: string; + } + ).code; + + if (code !== "EEXIST") { + throw error; + } + + try { + const ageMilliseconds = + Date.now() - + statSync( + lockDirectory, + ).mtimeMs; + + if ( + ageMilliseconds > + 30_000 + ) { + rmSync( + lockDirectory, + { + recursive: true, + force: true, + }, + ); + + continue; + } + } catch { + // The lock disappeared between the checks; retry immediately. + continue; + } + + if ( + Date.now() >= timeoutAt + ) { + throw new Error( + `Timed out waiting for audit lock: ${lockDirectory}`, + ); + } + + sleep(2); + } + } +} + +export function appendAudit( + file: string, + data: Omit< + UnsignedAuditRecord, + "sequence" | "previousHash" + >, +): AuditRecord { + const releaseLock = + acquireAuditLock(file); + + try { + const existing = + readRecords(file); + + const previous = + existing.length > 0 + ? existing[ + existing.length - 1 + ] + : undefined; + + const unsigned: + UnsignedAuditRecord = { + sequence: + existing.length + 1, + ...data, + previousHash: + previous?.recordHash ?? + null, + }; + + const record: + AuditRecord = { + ...unsigned, + recordHash: sha256( + canonical(unsigned), + ), + }; + + appendFileSync( + file, + `${JSON.stringify(record)}\n`, + "utf8", + ); + + return record; + } finally { + releaseLock(); + } +} + +export function createTraceId(): string { + return randomUUID(); +} + +export function hashValue( + value: unknown, +): string { + return sha256(String(value)); +} diff --git a/src/problem4/benchmark.ts b/src/problem4/benchmark.ts new file mode 100644 index 0000000000..c042311e9b --- /dev/null +++ b/src/problem4/benchmark.ts @@ -0,0 +1,39 @@ +import { + sum_to_n_a, + sum_to_n_b, + sum_to_n_c, +} from "./index"; + +function benchmark( + name: string, + implementation: (n: number) => number, + input: number, + iterations: number, +): void { + let checksum = 0; + const startedAt = performance.now(); + + for (let iteration = 0; iteration < iterations; iteration += 1) { + checksum += implementation(input); + } + + const elapsed = performance.now() - startedAt; + + console.log( + [ + name.padEnd(14), + `total=${elapsed.toFixed(3)}ms`, + `avg=${(elapsed / iterations).toFixed(6)}ms`, + `checksum=${checksum}`, + ].join(" "), + ); +} + +const input = 100_000_000; +const iterations = 20_000; + +console.log(`Input: ${input}`); +console.log(`Iterations: ${iterations}`); +benchmark("Gauss", sum_to_n_a, input, iterations); +benchmark("Matrix", sum_to_n_b, input, iterations); +benchmark("Binary blocks", sum_to_n_c, input, iterations); diff --git a/src/problem4/concurrency-worker.ts b/src/problem4/concurrency-worker.ts new file mode 100644 index 0000000000..694c0633e8 --- /dev/null +++ b/src/problem4/concurrency-worker.ts @@ -0,0 +1,61 @@ +import { + executeSumAWithAudit, + executeSumBWithAudit, + executeSumCWithAudit, +} from "./service"; + +const choice = + process.argv[2]?.toLowerCase(); + +const start = + Number(process.argv[3]); + +const count = + Number(process.argv[4]); + +const auditFile = + process.argv[5]; + +if ( + !["a", "b", "c"].includes(choice) || + !Number.isSafeInteger(start) || + !Number.isSafeInteger(count) || + count < 1 || + !auditFile +) { + throw new Error( + "Invalid concurrency-worker arguments", + ); +} + +for ( + let offset = 0; + offset < count; + offset += 1 +) { + const input = + start + offset; + + switch (choice) { + case "a": + executeSumAWithAudit( + input, + auditFile, + ); + break; + + case "b": + executeSumBWithAudit( + input, + auditFile, + ); + break; + + case "c": + executeSumCWithAudit( + input, + auditFile, + ); + break; + } +} diff --git a/src/problem4/deep-stress-result.json b/src/problem4/deep-stress-result.json new file mode 100644 index 0000000000..c9204a6325 --- /dev/null +++ b/src/problem4/deep-stress-result.json @@ -0,0 +1,85 @@ +{ + "status": "STRESS_TEST_PASS", + "assertions": 1197832, + "maximumSafeN": 134217727, + "elapsedMs": 1307, + "suites": [ + { + "name": "Fixed examples and signed edges", + "assertions": 36, + "elapsedMs": 1 + }, + { + "name": "Exhaustive all-functions range", + "assertions": 96004, + "elapsedMs": 96 + }, + { + "name": "Random moderate range for all functions", + "assertions": 32000, + "elapsedMs": 22 + }, + { + "name": "Full safe-domain random test for A and C", + "assertions": 600000, + "elapsedMs": 165 + }, + { + "name": "Safe-result boundary sweep", + "assertions": 49154, + "elapsedMs": 129 + }, + { + "name": "Result-overflow rejection", + "assertions": 3, + "elapsedMs": 111 + }, + { + "name": "Power-of-two neighborhoods", + "assertions": 672, + "elapsedMs": 2 + }, + { + "name": "Metamorphic identities for all functions", + "assertions": 18000, + "elapsedMs": 23 + }, + { + "name": "Full-domain metamorphic identities for A and C", + "assertions": 400000, + "elapsedMs": 144 + }, + { + "name": "Invalid runtime inputs", + "assertions": 18, + "elapsedMs": 1 + }, + { + "name": "Sequential success and failure audit chain", + "assertions": 733, + "elapsedMs": 112 + }, + { + "name": "Concurrent multi-process audit chain", + "assertions": 1203, + "elapsedMs": 497 + }, + { + "name": "Audit tamper and corruption detection", + "assertions": 9, + "elapsedMs": 4 + } + ], + "coverage": { + "exhaustiveAllFunctions": "-12,000..12,000", + "randomAllFunctions": 8000, + "randomFullSafeDomainAandC": 200000, + "boundaryWindowEachSide": 8192, + "exactMaximumForB": true, + "overflowRejectionAllFunctions": true, + "sequentialAuditRecords": 315, + "concurrentAuditRecords": 600, + "tamperScenarios": 7, + "algorithmFieldInAudit": false + } +} diff --git a/src/problem4/deep-stress.ts b/src/problem4/deep-stress.ts new file mode 100644 index 0000000000..6a35f88ff2 --- /dev/null +++ b/src/problem4/deep-stress.ts @@ -0,0 +1,1283 @@ +import { + sum_to_n_a, + sum_to_n_b, + sum_to_n_c, +} from "./index"; + +import { + executeSumAWithAudit, + executeSumBWithAudit, + executeSumCWithAudit, +} from "./service"; + +import { + verifyAuditLog, +} from "./verify-audit"; + +const { + copyFileSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} = require("node:fs"); + +const { + tmpdir, +} = require("node:os"); + +const { + join, +} = require("node:path"); + +const { + spawn, +} = require("node:child_process"); + +type SumFunction = ( + n: number, +) => number; + +interface SuiteResult { + name: string; + assertions: number; + elapsedMs: number; +} + +const implementations: + ReadonlyArray< + readonly [ + string, + SumFunction, + ] + > = [ + [ + "sum_to_n_a", + sum_to_n_a, + ], + [ + "sum_to_n_b", + sum_to_n_b, + ], + [ + "sum_to_n_c", + sum_to_n_c, + ], + ]; + +const fastImplementations: + ReadonlyArray< + readonly [ + string, + SumFunction, + ] + > = [ + [ + "sum_to_n_a", + sum_to_n_a, + ], + [ + "sum_to_n_c", + sum_to_n_c, + ], + ]; + +const maximumSafeN = + Math.floor( + ( + Math.sqrt( + 1 + + 8 * + Number.MAX_SAFE_INTEGER, + ) - + 1 + ) / + 2, + ); + +let assertions = 0; +const suites: SuiteResult[] = []; + +function assert( + condition: boolean, + message: string, +): void { + assertions += 1; + + if (!condition) { + throw new Error(message); + } +} + +function assertEqual( + actual: unknown, + expected: unknown, + label: string, +): void { + assert( + actual === expected, + `${label}: actual=${String(actual)}, expected=${String(expected)}`, + ); +} + +function bigintOracle( + n: number, +): number { + const magnitude = + BigInt(Math.abs(n)); + + const positive = + ( + magnitude * + (magnitude + 1n) + ) / 2n; + + const signed = + n < 0 + ? -positive + : positive; + + const result = + Number(signed); + + assert( + Number.isSafeInteger(result), + `Oracle produced unsafe result for n=${n}`, + ); + + return result; +} + +function runSuite( + name: string, + operation: () => void, +): void { + const before = assertions; + const startedAt = Date.now(); + + operation(); + + suites.push({ + name, + assertions: + assertions - before, + elapsedMs: + Date.now() - startedAt, + }); +} + +async function runAsyncSuite( + name: string, + operation: () => Promise, +): Promise { + const before = assertions; + const startedAt = Date.now(); + + await operation(); + + suites.push({ + name, + assertions: + assertions - before, + elapsedMs: + Date.now() - startedAt, + }); +} + +function verifyAll( + input: number, +): void { + const expected = + bigintOracle(input); + + for ( + const [ + name, + implementation, + ] + of implementations + ) { + assertEqual( + implementation(input), + expected, + `${name}(${input})`, + ); + } +} + +function verifyFast( + input: number, +): void { + const expected = + bigintOracle(input); + + for ( + const [ + name, + implementation, + ] + of fastImplementations + ) { + assertEqual( + implementation(input), + expected, + `${name}(${input})`, + ); + } +} + +function createRandom( + seed: number, +): () => number { + let state = seed >>> 0; + + return () => { + state ^= state << 13; + state ^= state >>> 17; + state ^= state << 5; + + return state >>> 0; + }; +} + +function expectFailure( + operation: () => unknown, + label: string, +): void { + let failed = false; + + try { + operation(); + } catch { + failed = true; + } + + assert( + failed, + `${label} should fail`, + ); +} + +function runWorker( + choice: "a" | "b" | "c", + start: number, + count: number, + auditFile: string, +): Promise { + return new Promise( + ( + resolvePromise, + rejectPromise, + ) => { + const workerFile = + join( + __dirname, + "concurrency-worker.js", + ); + + const child = spawn( + process.execPath, + [ + workerFile, + choice, + String(start), + String(count), + auditFile, + ], + { + stdio: [ + "ignore", + "ignore", + "pipe", + ], + }, + ); + + let errorOutput = ""; + + child.stderr.setEncoding( + "utf8", + ); + + child.stderr.on( + "data", + ( + chunk: string, + ) => { + errorOutput += chunk; + }, + ); + + child.on( + "error", + ( + error: Error, + ) => { + rejectPromise(error); + }, + ); + + child.on( + "exit", + ( + code: number | null, + ) => { + if (code === 0) { + resolvePromise(); + return; + } + + rejectPromise( + new Error( + `Worker ${choice} failed with code ${String(code)}: ${errorOutput}`, + ), + ); + }, + ); + }, + ); +} + +function readAuditLines( + file: string, +): string[] { + return String( + readFileSync( + file, + "utf8", + ), + ) + .split(/\r?\n/) + .filter(Boolean); +} + +async function main(): Promise { + const totalStartedAt = + Date.now(); + + runSuite( + "Fixed examples and signed edges", + () => { + const cases: + ReadonlyArray< + readonly [ + number, + number, + ] + > = [ + [0, 0], + [1, 1], + [2, 3], + [5, 15], + [10, 55], + [13, 91], + [100, 5050], + [-1, -1], + [-2, -3], + [-4, -10], + [-13, -91], + [-100, -5050], + ]; + + for ( + const [ + input, + expected, + ] + of cases + ) { + for ( + const [ + name, + implementation, + ] + of implementations + ) { + assertEqual( + implementation(input), + expected, + `${name} fixed input=${input}`, + ); + } + } + }, + ); + + runSuite( + "Exhaustive all-functions range", + () => { + for ( + let input = -12_000; + input <= 12_000; + input += 1 + ) { + verifyAll(input); + } + }, + ); + + runSuite( + "Random moderate range for all functions", + () => { + const nextRandom = + createRandom( + 0x9e3779b9, + ); + + for ( + let sample = 0; + sample < 8_000; + sample += 1 + ) { + const magnitude = + nextRandom() % 5_001; + + const input = + (nextRandom() & 1) === 0 + ? magnitude + : -magnitude; + + verifyAll(input); + } + }, + ); + + runSuite( + "Full safe-domain random test for A and C", + () => { + const nextRandom = + createRandom( + 0x243f6a88, + ); + + for ( + let sample = 0; + sample < 200_000; + sample += 1 + ) { + const magnitude = + nextRandom() % + ( + maximumSafeN + 1 + ); + + const input = + (nextRandom() & 1) === 0 + ? magnitude + : -magnitude; + + verifyFast(input); + } + }, + ); + + runSuite( + "Safe-result boundary sweep", + () => { + const windowSize = 8_192; + + for ( + let offset = 0; + offset < windowSize; + offset += 1 + ) { + const input = + maximumSafeN - offset; + + verifyFast(input); + verifyFast(-input); + } + + // Solution B is intentionally linear, but the exact maximum valid + // input is still executed once to prove boundary correctness. + const expected = + bigintOracle( + maximumSafeN, + ); + + assertEqual( + sum_to_n_b( + maximumSafeN, + ), + expected, + "sum_to_n_b maximum safe boundary", + ); + }, + ); + + runSuite( + "Result-overflow rejection", + () => { + const overflowInput = + maximumSafeN + 1; + + for ( + const [ + name, + implementation, + ] + of implementations + ) { + expectFailure( + () => + implementation( + overflowInput, + ), + `${name} overflow input`, + ); + } + }, + ); + + runSuite( + "Power-of-two neighborhoods", + () => { + for ( + let power = 1; + power <= 65_536; + power *= 2 + ) { + for ( + const delta + of [ + -2, + -1, + 0, + 1, + 2, + ] + ) { + const input = + power + delta; + + if (input < 0) { + continue; + } + + verifyAll(input); + verifyAll(-input); + } + } + }, + ); + + runSuite( + "Metamorphic identities for all functions", + () => { + const nextRandom = + createRandom( + 0xb7e15162, + ); + + for ( + let sample = 0; + sample < 3_000; + sample += 1 + ) { + const n = + 1 + + ( + nextRandom() % + 5_000 + ); + + for ( + const [ + name, + implementation, + ] + of implementations + ) { + const current = + implementation(n); + + const previous = + implementation( + n - 1, + ); + + const negative = + implementation(-n); + + assertEqual( + current - previous, + n, + `${name} recurrence n=${n}`, + ); + + assertEqual( + negative, + -current, + `${name} sign symmetry n=${n}`, + ); + } + } + }, + ); + + runSuite( + "Full-domain metamorphic identities for A and C", + () => { + const nextRandom = + createRandom( + 0xdeadbeef, + ); + + for ( + let sample = 0; + sample < 100_000; + sample += 1 + ) { + const n = + 1 + + ( + nextRandom() % + maximumSafeN + ); + + for ( + const [ + name, + implementation, + ] + of fastImplementations + ) { + const current = + implementation(n); + + assertEqual( + current - + implementation( + n - 1, + ), + n, + `${name} full recurrence n=${n}`, + ); + + assertEqual( + implementation(-n), + -current, + `${name} full sign n=${n}`, + ); + } + } + }, + ); + + runSuite( + "Invalid runtime inputs", + () => { + const invalidInputs = [ + Number.NaN, + Number.POSITIVE_INFINITY, + Number.NEGATIVE_INFINITY, + 1.5, + -2.25, + Number.MAX_SAFE_INTEGER + 1, + ]; + + for ( + const invalid + of invalidInputs + ) { + for ( + const [ + name, + implementation, + ] + of implementations + ) { + expectFailure( + () => + implementation( + invalid, + ), + `${name} invalid=${String(invalid)}`, + ); + } + } + }, + ); + + runSuite( + "Sequential success and failure audit chain", + () => { + const directory: string = + mkdtempSync( + join( + tmpdir(), + "problem4-sequential-audit-", + ), + ); + + const file: string = + join( + directory, + "audit.jsonl", + ); + + try { + for ( + let input = 1; + input <= 100; + input += 1 + ) { + const expected = + bigintOracle(input); + + assertEqual( + executeSumAWithAudit( + input, + file, + ).result, + expected, + `audit A input=${input}`, + ); + + assertEqual( + executeSumBWithAudit( + input, + file, + ).result, + expected, + `audit B input=${input}`, + ); + + assertEqual( + executeSumCWithAudit( + input, + file, + ).result, + expected, + `audit C input=${input}`, + ); + } + + const invalidValues = [ + "invalid", + "", + "1.5", + "Infinity", + "NaN", + ]; + + for ( + const invalid + of invalidValues + ) { + expectFailure( + () => + executeSumAWithAudit( + invalid, + file, + ), + `audit A invalid=${invalid}`, + ); + + expectFailure( + () => + executeSumBWithAudit( + invalid, + file, + ), + `audit B invalid=${invalid}`, + ); + + expectFailure( + () => + executeSumCWithAudit( + invalid, + file, + ), + `audit C invalid=${invalid}`, + ); + } + + const expectedRecords = + 300 + + invalidValues.length * 3; + + assertEqual( + verifyAuditLog(file), + expectedRecords, + "sequential audit chain count", + ); + + const records = + readAuditLines(file).map( + ( + line: string, + ) => + JSON.parse(line), + ); + + assertEqual( + records.length, + expectedRecords, + "sequential audit line count", + ); + + assertEqual( + records.filter( + ( + record: { + status: string; + }, + ) => + record.status === + "FAILED", + ).length, + invalidValues.length * 3, + "failed audit count", + ); + + for ( + const record + of records + ) { + assertEqual( + "algorithm" in record, + false, + "algorithm must not appear in audit", + ); + } + } finally { + rmSync( + directory, + { + recursive: true, + force: true, + }, + ); + } + }, + ); + + await runAsyncSuite( + "Concurrent multi-process audit chain", + async () => { + const directory: string = + mkdtempSync( + join( + tmpdir(), + "problem4-concurrent-audit-", + ), + ); + + const file: string = + join( + directory, + "audit.jsonl", + ); + + try { + const workers: + Array> = []; + + const choices: + ReadonlyArray< + "a" | "b" | "c" + > = [ + "a", + "b", + "c", + "a", + "b", + "c", + "a", + "c", + ]; + + choices.forEach( + ( + choice, + workerIndex, + ) => { + workers.push( + runWorker( + choice, + 1 + + workerIndex * + 100, + 75, + file, + ), + ); + }, + ); + + await Promise.all( + workers, + ); + + const expectedRecords = + choices.length * 75; + + assertEqual( + verifyAuditLog(file), + expectedRecords, + "concurrent audit chain count", + ); + + const records = + readAuditLines(file).map( + ( + line: string, + ) => + JSON.parse(line), + ); + + assertEqual( + records.length, + expectedRecords, + "concurrent audit line count", + ); + + const traceIds = + new Set( + records.map( + ( + record: { + traceId: string; + }, + ) => + record.traceId, + ), + ); + + assertEqual( + traceIds.size, + expectedRecords, + "concurrent traceId uniqueness", + ); + + for ( + const record + of records + ) { + assertEqual( + "algorithm" in record, + false, + "concurrent audit algorithm field", + ); + + assertEqual( + record.status, + "SUCCESS", + "concurrent audit status", + ); + } + } finally { + rmSync( + directory, + { + recursive: true, + force: true, + }, + ); + } + }, + ); + + runSuite( + "Audit tamper and corruption detection", + () => { + const directory: string = + mkdtempSync( + join( + tmpdir(), + "problem4-tamper-audit-", + ), + ); + + const original: string = + join( + directory, + "original.jsonl", + ); + + try { + for ( + let input = 1; + input <= 12; + input += 1 + ) { + executeSumAWithAudit( + input, + original, + ); + } + + assertEqual( + verifyAuditLog(original), + 12, + "original audit validity", + ); + + const originalLines = + readAuditLines(original); + + const cases: + Array< + readonly [ + string, + ( + lines: string[], + ) => string[], + ] + > = [ + [ + "modified-result", + ( + lines, + ) => { + const records = + [...lines]; + + const first = + JSON.parse( + records[0] ?? + "{}", + ); + + first.result += 1; + records[0] = + JSON.stringify(first); + + return records; + }, + ], + [ + "broken-previous-hash", + ( + lines, + ) => { + const records = + [...lines]; + + const second = + JSON.parse( + records[1] ?? + "{}", + ); + + second.previousHash = + "0".repeat(64); + + records[1] = + JSON.stringify(second); + + return records; + }, + ], + [ + "deleted-middle-line", + ( + lines, + ) => + lines.filter( + ( + _line, + index, + ) => + index !== 5, + ), + ], + [ + "reordered-lines", + ( + lines, + ) => { + const records = + [...lines]; + + const first = + records[0]; + + records[0] = + records[1] ?? + ""; + + records[1] = + first ?? + ""; + + return records; + }, + ], + [ + "duplicated-line", + ( + lines, + ) => [ + ...lines, + lines[ + lines.length - 1 + ] ?? "", + ], + ], + [ + "malformed-json", + ( + lines, + ) => [ + ...lines, + "{\"broken\":", + ], + ], + [ + "truncated-record", + ( + lines, + ) => { + const records = + [...lines]; + + const lastIndex = + records.length - 1; + + records[lastIndex] = + ( + records[ + lastIndex + ] ?? "" + ).slice( + 0, + -7, + ); + + return records; + }, + ], + ]; + + for ( + const [ + name, + mutate, + ] + of cases + ) { + const target: string = + join( + directory, + `${name}.jsonl`, + ); + + const changed = + mutate( + originalLines, + ); + + writeFileSync( + target, + `${changed.join("\n")}\n`, + "utf8", + ); + + expectFailure( + () => + verifyAuditLog( + target, + ), + `tamper case ${name}`, + ); + } + + const copied: string = + join( + directory, + "valid-copy.jsonl", + ); + + copyFileSync( + original, + copied, + ); + + assertEqual( + verifyAuditLog(copied), + 12, + "valid copied audit", + ); + } finally { + rmSync( + directory, + { + recursive: true, + force: true, + }, + ); + } + }, + ); + + const elapsedMs = + Date.now() - + totalStartedAt; + + const report = { + status: + "STRESS_TEST_PASS", + assertions, + maximumSafeN, + elapsedMs, + suites, + coverage: { + exhaustiveAllFunctions: + "-12,000..12,000", + randomAllFunctions: + 8_000, + randomFullSafeDomainAandC: + 200_000, + boundaryWindowEachSide: + 8_192, + exactMaximumForB: + true, + overflowRejectionAllFunctions: + true, + sequentialAuditRecords: + 315, + concurrentAuditRecords: + 600, + tamperScenarios: + 7, + algorithmFieldInAudit: + false, + }, + }; + + console.log( + "STRESS_TEST_PASS", + ); + console.log( + `assertions=${assertions}`, + ); + console.log( + `maximumSafeN=${maximumSafeN}`, + ); + console.log( + `elapsedMs=${elapsedMs}`, + ); + console.log( + `suites=${suites.length}`, + ); + console.log( + `DEEP_STRESS_JSON=${JSON.stringify(report)}`, + ); +} + +main().catch( + ( + error: unknown, + ) => { + console.error( + error instanceof Error + ? error.stack ?? + error.message + : String(error), + ); + + process.exitCode = 1; + }, +); diff --git a/src/problem4/index.test.ts b/src/problem4/index.test.ts new file mode 100644 index 0000000000..e5f3846c74 --- /dev/null +++ b/src/problem4/index.test.ts @@ -0,0 +1,183 @@ +import { + sum_to_n_a, + sum_to_n_b, + sum_to_n_c, +} from "./index"; + +import { + executeSumAWithAudit, + executeSumBWithAudit, + executeSumCWithAudit, +} from "./service"; + +import { + verifyAuditLog, +} from "./verify-audit"; + +const { + mkdtempSync, + readFileSync, + rmSync, +} = require("node:fs"); + +const { + tmpdir, +} = require("node:os"); + +const { + join, +} = require("node:path"); + +function assertEqual( + actual: unknown, + expected: unknown, + label: string, +): void { + if (actual !== expected) { + throw new Error( + `${label}: actual=${String(actual)}, expected=${String(expected)}`, + ); + } +} + +function oracle( + n: number, +): number { + const magnitude = + BigInt(Math.abs(n)); + + const positive = + ( + magnitude * + (magnitude + 1n) + ) / 2n; + + return Number( + n < 0 + ? -positive + : positive, + ); +} + +const implementations = [ + sum_to_n_a, + sum_to_n_b, + sum_to_n_c, +] as const; + +for ( + let n = -20_000; + n <= 20_000; + n += 1 +) { + const expected = oracle(n); + + for ( + const implementation + of implementations + ) { + assertEqual( + implementation(n), + expected, + `n=${n}`, + ); + } +} + +const directory: string = + mkdtempSync( + join( + tmpdir(), + "problem4-audit-", + ), + ); + +const file: string = + join( + directory, + "audit.jsonl", + ); + +try { + assertEqual( + executeSumAWithAudit( + 100, + file, + ).result, + 5050, + "function A", + ); + + assertEqual( + executeSumBWithAudit( + 100, + file, + ).result, + 5050, + "function B", + ); + + assertEqual( + executeSumCWithAudit( + 100, + file, + ).result, + 5050, + "function C", + ); + + assertEqual( + verifyAuditLog(file), + 3, + "audit record count", + ); + + const records = String( + readFileSync(file, "utf8"), + ) + .trim() + .split(/\r?\n/) + .map( + (line: string) => + JSON.parse(line), + ); + + assertEqual( + records.length, + 3, + "three audit lines", + ); + + for ( + const record + of records + ) { + assertEqual( + "algorithm" in record, + false, + "algorithm field must not exist", + ); + + assertEqual( + record.action, + "SUM_TO_N", + "audit action", + ); + + assertEqual( + record.status, + "SUCCESS", + "audit status", + ); + } +} finally { + rmSync( + directory, + { + recursive: true, + force: true, + }, + ); +} + +console.log("PASS"); diff --git a/src/problem4/index.ts b/src/problem4/index.ts new file mode 100644 index 0000000000..74ed63001a --- /dev/null +++ b/src/problem4/index.ts @@ -0,0 +1,101 @@ +/** + * Problem 4: Three ways to sum to n. + * + * Negative-input convention: + * sum_to_n(-4) = -1 + -2 + -3 + -4 = -10 + */ + +function assertSafeInteger(n: number): void { + if (!Number.isSafeInteger(n)) { + throw new TypeError("n must be a safe integer"); + } +} + +function applySign(n: number, positiveResult: number): number { + if (!Number.isSafeInteger(positiveResult)) { + throw new RangeError( + "The result must be smaller than Number.MAX_SAFE_INTEGER", + ); + } + + return n < 0 ? -positiveResult : positiveResult; +} + +/** + * Solution A: arithmetic-series formula. + * + * Uses n(n + 1) / 2 and divides the even factor before multiplication + * to avoid an unnecessarily large intermediate value. + * + * Time complexity: O(1) + * Space complexity: O(1) + */ +export function sum_to_n_a(n: number): number { + assertSafeInteger(n); + + const magnitude = Math.abs(n); + const positiveResult = + magnitude % 2 === 0 + ? (magnitude / 2) * (magnitude + 1) + : magnitude * ((magnitude + 1) / 2); + + return applySign(n, positiveResult); +} + +/** + * Solution B: iterative accumulation. + * + * Adds every integer from 1 through |n|. + * + * Time complexity: O(|n|) + * Space complexity: O(1) + */ +export function sum_to_n_b(n: number): number { + assertSafeInteger(n); + + const magnitude = Math.abs(n); + let positiveResult = 0; + + for (let value = 1; value <= magnitude; value += 1) { + positiveResult += value; + } + + return applySign(n, positiveResult); +} + +/** + * Solution C: divide-and-conquer recurrence. + * + * Uses: + * S(2k) = 2S(k) + k² + * S(2k + 1) = 2S(k) + k² + 2k + 1 + * + * Time complexity: O(log |n|) + * Space complexity: O(log |n|) + */ +function binarySum(magnitude: number): number { + if (magnitude === 0) { + return 0; + } + + if (magnitude === 1) { + return 1; + } + + const half = Math.floor(magnitude / 2); + const halfResult = binarySum(half); + const evenResult = 2 * halfResult + half * half; + + return magnitude % 2 === 0 + ? evenResult + : evenResult + 2 * half + 1; +} + +export function sum_to_n_c(n: number): number { + assertSafeInteger(n); + + return applySign( + n, + binarySum(Math.abs(n)), + ); +} diff --git a/src/problem4/logs/.gitkeep b/src/problem4/logs/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/problem4/node-shims.d.ts b/src/problem4/node-shims.d.ts new file mode 100644 index 0000000000..030bdba27d --- /dev/null +++ b/src/problem4/node-shims.d.ts @@ -0,0 +1,15 @@ +interface NodeRequire { + (name: string): any; + main: any; +} + +declare const require: NodeRequire; +declare const module: any; +declare const __dirname: string; + +declare const process: { + argv: string[]; + cwd(): string; + execPath: string; + exitCode?: number; +}; diff --git a/src/problem4/package-lock.json b/src/problem4/package-lock.json new file mode 100644 index 0000000000..b4e56660b8 --- /dev/null +++ b/src/problem4/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "problem4-advanced-algorithms", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "problem4-advanced-algorithms", + "version": "1.0.0", + "devDependencies": { + "typescript": "^5.8.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/src/problem4/package.json b/src/problem4/package.json new file mode 100644 index 0000000000..3c783c8f93 --- /dev/null +++ b/src/problem4/package.json @@ -0,0 +1,17 @@ +{ + "name": "problem4-three-functions-audit", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "tsc", + "test": "npm run build && node dist/index.test.js", + "start": "npm run build && node dist/run.js", + "audit:sample": "npm run build && node dist/audit-sample.js", + "audit:verify": "npm run build && node dist/verify-audit.js", + "stress": "npm run build && node dist/deep-stress.js", + "stress:quick": "npm run build && node dist/stress-test.js" + }, + "devDependencies": { + "typescript": "^5.8.3" + } +} diff --git a/src/problem4/run.ts b/src/problem4/run.ts new file mode 100644 index 0000000000..7f5497fd47 --- /dev/null +++ b/src/problem4/run.ts @@ -0,0 +1,51 @@ +import { + executeSumAWithAudit, + executeSumBWithAudit, + executeSumCWithAudit, +} from "./service"; + +const choice = + process.argv[2]?.toLowerCase(); +const input = process.argv[3]; + +try { + let result: number; + + switch (choice) { + case "a": + result = + executeSumAWithAudit( + input, + ).result; + break; + + case "b": + result = + executeSumBWithAudit( + input, + ).result; + break; + + case "c": + result = + executeSumCWithAudit( + input, + ).result; + break; + + default: + throw new Error( + "Usage: npm start -- a|b|c ", + ); + } + + console.log(result); +} catch (error) { + console.error( + error instanceof Error + ? error.message + : String(error), + ); + + process.exitCode = 1; +} diff --git a/src/problem4/service.ts b/src/problem4/service.ts new file mode 100644 index 0000000000..c053d84c38 --- /dev/null +++ b/src/problem4/service.ts @@ -0,0 +1,147 @@ +import { + sum_to_n_a, + sum_to_n_b, + sum_to_n_c, +} from "./index"; + +import { + appendAudit, + createTraceId, + DEFAULT_AUDIT_FILE, + hashValue, +} from "./audit"; + +type SumFunction = ( + n: number, +) => number; + +export interface AuditedResult { + result: number; + traceId: string; +} + +function parseInput( + input: unknown, +): number { + const parsed = + typeof input === "number" + ? input + : typeof input === "string" && + input.trim() !== "" + ? Number(input) + : Number.NaN; + + if (!Number.isSafeInteger(parsed)) { + throw new TypeError( + "n must be a safe integer", + ); + } + + return parsed; +} + +function executeWithAudit( + input: unknown, + implementation: SumFunction, + file: string, +): AuditedResult { + const traceId = createTraceId(); + const startedAt = Date.now(); + + const rawInput: number | string = + typeof input === "number" || + typeof input === "string" + ? input + : String(input); + + try { + const n = parseInput(input); + const result = implementation(n); + + appendAudit(file, { + timestamp: + new Date().toISOString(), + traceId, + action: "SUM_TO_N", + status: "SUCCESS", + input: n, + result, + durationMs: + Date.now() - startedAt, + inputHash: hashValue(n), + outputHash: + hashValue(result), + error: null, + }); + + return { + result, + traceId, + }; + } catch (error) { + const message = + error instanceof Error + ? error.message + : String(error); + + appendAudit(file, { + timestamp: + new Date().toISOString(), + traceId, + action: "SUM_TO_N", + status: "FAILED", + input: rawInput, + result: null, + durationMs: + Date.now() - startedAt, + inputHash: + hashValue(rawInput), + outputHash: null, + error: message, + }); + + throw error; + } +} + +/** + * Executes solution A and writes one audit record. + */ +export function executeSumAWithAudit( + input: unknown, + file: string = DEFAULT_AUDIT_FILE, +): AuditedResult { + return executeWithAudit( + input, + sum_to_n_a, + file, + ); +} + +/** + * Executes solution B and writes one audit record. + */ +export function executeSumBWithAudit( + input: unknown, + file: string = DEFAULT_AUDIT_FILE, +): AuditedResult { + return executeWithAudit( + input, + sum_to_n_b, + file, + ); +} + +/** + * Executes solution C and writes one audit record. + */ +export function executeSumCWithAudit( + input: unknown, + file: string = DEFAULT_AUDIT_FILE, +): AuditedResult { + return executeWithAudit( + input, + sum_to_n_c, + file, + ); +} diff --git a/src/problem4/stress-test.ts b/src/problem4/stress-test.ts new file mode 100644 index 0000000000..39cffb2714 --- /dev/null +++ b/src/problem4/stress-test.ts @@ -0,0 +1,358 @@ +import { + sum_to_n_a, + sum_to_n_b, + sum_to_n_c, +} from "./index"; + +import { + executeSumAWithAudit, + executeSumBWithAudit, + executeSumCWithAudit, +} from "./service"; + +import { + verifyAuditLog, +} from "./verify-audit"; + +const { + mkdtempSync, + readFileSync, + rmSync, +} = require("node:fs"); + +const { + tmpdir, +} = require("node:os"); + +const { + join, +} = require("node:path"); + +type SumFunction = ( + n: number, +) => number; + +const implementations: + ReadonlyArray = [ + sum_to_n_a, + sum_to_n_b, + sum_to_n_c, + ]; + +let assertions = 0; + +function assertEqual( + actual: unknown, + expected: unknown, + label: string, +): void { + assertions += 1; + + if (actual !== expected) { + throw new Error( + `${label}: actual=${String(actual)}, expected=${String(expected)}`, + ); + } +} + +function bigintOracle( + n: number, +): number { + const magnitude = + BigInt(Math.abs(n)); + + const positive = + ( + magnitude * + (magnitude + 1n) + ) / 2n; + + return Number( + n < 0 + ? -positive + : positive, + ); +} + +function verifyAll( + input: number, +): void { + const expected = + bigintOracle(input); + + for ( + const implementation + of implementations + ) { + assertEqual( + implementation(input), + expected, + `input=${input}`, + ); + } +} + +function createRandom( + seed: number, +): () => number { + let state = seed >>> 0; + + return () => { + state ^= state << 13; + state ^= state >>> 17; + state ^= state << 5; + + return state >>> 0; + }; +} + +const startedAt = Date.now(); + +/** + * Exhaustive signed range for all three implementations. + */ +for ( + let input = -5_000; + input <= 5_000; + input += 1 +) { + verifyAll(input); +} + +/** + * Deterministic random verification for all three implementations. + */ +const nextRandom = + createRandom(0x9e3779b9); + +for ( + let sample = 0; + sample < 10_000; + sample += 1 +) { + const magnitude = + nextRandom() % 10_001; + + const input = + (nextRandom() & 1) === 0 + ? magnitude + : -magnitude; + + verifyAll(input); +} + +/** + * Large but practical inputs for all three implementations. + */ +for ( + const input + of [ + -1_000_000, + -100_000, + 100_000, + 1_000_000, + ] +) { + verifyAll(input); +} + +/** + * Safe-result boundary checks for the non-linear implementations. + * + * Solution B intentionally walks every integer, so using it at the + * Number.MAX_SAFE_INTEGER boundary would make the stress test impractical. + */ +const maximumSafeN = + Math.floor( + ( + Math.sqrt( + 1 + + 8 * + Number.MAX_SAFE_INTEGER, + ) - + 1 + ) / + 2, + ); + +for ( + const input + of [ + maximumSafeN - 1, + maximumSafeN, + -(maximumSafeN - 1), + -maximumSafeN, + ] +) { + const expected = + bigintOracle(input); + + assertEqual( + sum_to_n_a(input), + expected, + `boundary A input=${input}`, + ); + + assertEqual( + sum_to_n_c(input), + expected, + `boundary C input=${input}`, + ); +} + +/** + * Invalid-input checks for all three implementations. + */ +for ( + const invalid + of [ + Number.NaN, + Number.POSITIVE_INFINITY, + Number.NEGATIVE_INFINITY, + 1.5, + -2.25, + Number.MAX_SAFE_INTEGER + 1, + ] +) { + for ( + const implementation + of implementations + ) { + let failed = false; + + try { + implementation(invalid); + } catch { + failed = true; + } + + assertEqual( + failed, + true, + `invalid=${String(invalid)}`, + ); + } +} + +/** + * Audit stress: + * 100 calls per function create 300 chained records. + */ +const auditDirectory: string = + mkdtempSync( + join( + tmpdir(), + "problem4-stress-audit-", + ), + ); + +const auditFile: string = + join( + auditDirectory, + "audit.jsonl", + ); + +try { + for ( + let input = 1; + input <= 100; + input += 1 + ) { + const expected = + bigintOracle(input); + + assertEqual( + executeSumAWithAudit( + input, + auditFile, + ).result, + expected, + `audit A input=${input}`, + ); + + assertEqual( + executeSumBWithAudit( + input, + auditFile, + ).result, + expected, + `audit B input=${input}`, + ); + + assertEqual( + executeSumCWithAudit( + input, + auditFile, + ).result, + expected, + `audit C input=${input}`, + ); + } + + assertEqual( + verifyAuditLog(auditFile), + 300, + "audit chain count", + ); + + const records = String( + readFileSync( + auditFile, + "utf8", + ), + ) + .trim() + .split(/\r?\n/) + .map( + (line: string) => + JSON.parse(line), + ); + + assertEqual( + records.length, + 300, + "audit line count", + ); + + for ( + const record + of records + ) { + assertEqual( + "algorithm" in record, + false, + "algorithm field must not exist", + ); + + assertEqual( + record.status, + "SUCCESS", + "audit status", + ); + } +} finally { + rmSync( + auditDirectory, + { + recursive: true, + force: true, + }, + ); +} + +const elapsedMs = + Date.now() - startedAt; + +console.log("STRESS_TEST_PASS"); +console.log( + `assertions=${assertions}`, +); +console.log( + `auditRecords=300`, +); +console.log( + `safeBoundary=${maximumSafeN}`, +); +console.log( + `elapsedMs=${elapsedMs}`, +); diff --git a/src/problem4/tsconfig.json b/src/problem4/tsconfig.json new file mode 100644 index 0000000000..0de5f67d55 --- /dev/null +++ b/src/problem4/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "Node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "noEmitOnError": true, + "outDir": "dist" + }, + "include": [ + "*.ts", + "*.d.ts" + ] +} diff --git a/src/problem4/verify-audit.ts b/src/problem4/verify-audit.ts new file mode 100644 index 0000000000..61bd817007 --- /dev/null +++ b/src/problem4/verify-audit.ts @@ -0,0 +1,132 @@ +import { + AuditRecord, + DEFAULT_AUDIT_FILE, +} from "./audit"; + +const { + createHash, +} = require("node:crypto"); + +const { + existsSync, + readFileSync, +} = require("node:fs"); + +const { + resolve, +} = require("node:path"); + +type UnsignedAuditRecord = Omit< + AuditRecord, + "recordHash" +>; + +function sha256(value: string): string { + return createHash("sha256") + .update(value, "utf8") + .digest("hex"); +} + +function canonical( + record: UnsignedAuditRecord, +): string { + return JSON.stringify({ + sequence: record.sequence, + timestamp: record.timestamp, + traceId: record.traceId, + action: record.action, + status: record.status, + input: record.input, + result: record.result, + durationMs: record.durationMs, + inputHash: record.inputHash, + outputHash: record.outputHash, + error: record.error, + previousHash: record.previousHash, + }); +} + +export function verifyAuditLog( + file: string = DEFAULT_AUDIT_FILE, +): number { + if (!existsSync(file)) { + throw new Error( + `Audit file not found: ${file}`, + ); + } + + const lines: string[] = String( + readFileSync(file, "utf8"), + ) + .split(/\r?\n/) + .filter(Boolean); + + let previousHash: string | null = + null; + + lines.forEach( + ( + line: string, + index: number, + ) => { + const record = JSON.parse( + line, + ) as AuditRecord; + + const expectedSequence = + index + 1; + + if ( + record.sequence !== + expectedSequence + ) { + throw new Error( + `Invalid sequence at line ${expectedSequence}`, + ); + } + + if ( + record.previousHash !== + previousHash + ) { + throw new Error( + `Broken audit chain at line ${expectedSequence}`, + ); + } + + const { + recordHash, + ...unsigned + } = record; + + const expectedHash = sha256( + canonical(unsigned), + ); + + if ( + recordHash !== + expectedHash + ) { + throw new Error( + `Audit record was modified at line ${expectedSequence}`, + ); + } + + previousHash = recordHash; + }, + ); + + return lines.length; +} + +if (require.main === module) { + const file = process.argv[2] + ? resolve(process.argv[2]) + : DEFAULT_AUDIT_FILE; + + const count = verifyAuditLog(file); + + console.log( + `AUDIT_OK records=${count}`, + ); +} From 629feb1384805cc0fa0dde6c5d68e5bf04b9d42a Mon Sep 17 00:00:00 2001 From: Trong Do Date: Mon, 3 Aug 2026 23:11:27 +0700 Subject: [PATCH 2/3] [BE] Problem 5: A Crude Server --- src/problem5/.env.example | 3 + src/problem5/.gitignore | 7 + src/problem5/Dockerfile | 18 + src/problem5/README.md | 247 +++ src/problem5/data/.gitkeep | 0 src/problem5/package-lock.json | 1524 +++++++++++++++++ src/problem5/package.json | 29 + src/problem5/requests.http | 60 + src/problem5/src/app.ts | 84 + src/problem5/src/config.ts | 28 + src/problem5/src/database.ts | 151 ++ src/problem5/src/domain/observability.ts | 67 + src/problem5/src/domain/task.ts | 52 + src/problem5/src/errors.ts | 20 + src/problem5/src/http/middleware.ts | 197 +++ src/problem5/src/http/observability.routes.ts | 77 + .../src/http/observability.validation.ts | 161 ++ src/problem5/src/http/task.routes.ts | 70 + src/problem5/src/http/validation.ts | 275 +++ .../repositories/observability.repository.ts | 268 +++ .../src/repositories/task.repository.ts | 253 +++ src/problem5/src/scripts/migrate.ts | 8 + src/problem5/src/scripts/seed.ts | 44 + src/problem5/src/server.ts | 30 + .../src/services/observability.service.ts | 53 + src/problem5/src/services/task.service.ts | 84 + src/problem5/test/api.test.ts | 207 +++ src/problem5/test/core.test.ts | 93 + src/problem5/test/stress.ts | 444 +++++ src/problem5/tsconfig.json | 21 + 30 files changed, 4575 insertions(+) create mode 100644 src/problem5/.env.example create mode 100644 src/problem5/.gitignore create mode 100644 src/problem5/Dockerfile create mode 100644 src/problem5/README.md create mode 100644 src/problem5/data/.gitkeep create mode 100644 src/problem5/package-lock.json create mode 100644 src/problem5/package.json create mode 100644 src/problem5/requests.http create mode 100644 src/problem5/src/app.ts create mode 100644 src/problem5/src/config.ts create mode 100644 src/problem5/src/database.ts create mode 100644 src/problem5/src/domain/observability.ts create mode 100644 src/problem5/src/domain/task.ts create mode 100644 src/problem5/src/errors.ts create mode 100644 src/problem5/src/http/middleware.ts create mode 100644 src/problem5/src/http/observability.routes.ts create mode 100644 src/problem5/src/http/observability.validation.ts create mode 100644 src/problem5/src/http/task.routes.ts create mode 100644 src/problem5/src/http/validation.ts create mode 100644 src/problem5/src/repositories/observability.repository.ts create mode 100644 src/problem5/src/repositories/task.repository.ts create mode 100644 src/problem5/src/scripts/migrate.ts create mode 100644 src/problem5/src/scripts/seed.ts create mode 100644 src/problem5/src/server.ts create mode 100644 src/problem5/src/services/observability.service.ts create mode 100644 src/problem5/src/services/task.service.ts create mode 100644 src/problem5/test/api.test.ts create mode 100644 src/problem5/test/core.test.ts create mode 100644 src/problem5/test/stress.ts create mode 100644 src/problem5/tsconfig.json diff --git a/src/problem5/.env.example b/src/problem5/.env.example new file mode 100644 index 0000000000..35379cdd69 --- /dev/null +++ b/src/problem5/.env.example @@ -0,0 +1,3 @@ +PORT=3000 +DATABASE_PATH=./data/problem5.sqlite +JSON_LIMIT=32kb diff --git a/src/problem5/.gitignore b/src/problem5/.gitignore new file mode 100644 index 0000000000..b91fd62c98 --- /dev/null +++ b/src/problem5/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +.env +data/*.sqlite +data/*.sqlite-shm +data/*.sqlite-wal +!data/.gitkeep diff --git a/src/problem5/Dockerfile b/src/problem5/Dockerfile new file mode 100644 index 0000000000..51907d220f --- /dev/null +++ b/src/problem5/Dockerfile @@ -0,0 +1,18 @@ +FROM node:22-bookworm-slim AS build +WORKDIR /app +COPY package*.json ./ +RUN npm install +COPY tsconfig.json ./ +COPY src ./src +COPY test ./test +RUN npm run build + +FROM node:22-bookworm-slim +WORKDIR /app +ENV NODE_ENV=production +COPY package*.json ./ +RUN npm install --omit=dev +COPY --from=build /app/dist ./dist +RUN mkdir -p /app/data +EXPOSE 3000 +CMD ["node", "dist/src/server.js"] diff --git a/src/problem5/README.md b/src/problem5/README.md new file mode 100644 index 0000000000..228138a212 --- /dev/null +++ b/src/problem5/README.md @@ -0,0 +1,247 @@ +# Problem 5 — A Crude Server + +A CRUD backend built with **ExpressJS**, **TypeScript**, and **SQLite**. + +The resource is a task. Audit and trouble logs are persisted in the same +SQLite database and exposed through read-only endpoints. + +## Requirements + +```text +Node.js >= 22.18.0 +npm +``` + +The application uses Node.js `node:sqlite`; no external database server is +required. + +## Install and run + +```bat +cd /d D:\99\code-challenge\src\problem5 + +copy .env.example .env +npm install +npm run db:migrate +npm run db:seed +npm test +npm run dev +``` + +Server: + +```text +http://localhost:3000 +``` + +## Task CRUD endpoints + +```text +POST /api/v1/tasks +GET /api/v1/tasks +GET /api/v1/tasks/:id +PATCH /api/v1/tasks/:id +DELETE /api/v1/tasks/:id +``` + +List filters: + +```text +search +status +priority +dueAfter +dueBefore +sortBy +order +limit +offset +``` + +## Audit log + +Every successful `CREATE`, `UPDATE`, and `DELETE` is written inside the same +database transaction as the task mutation. + +SQLite table: + +```text +task_audit_logs +``` + +List audit records: + +```http +GET /api/v1/audit-logs +``` + +Filters: + +```text +taskId +traceId +action=CREATE|UPDATE|DELETE +limit +offset +``` + +Example: + +```http +GET /api/v1/audit-logs?taskId=&limit=20 +``` + +Details: + +```http +GET /api/v1/audit-logs/:id +``` + +Audit response contains: + +```json +{ + "id": 3, + "traceId": "manual-delete-001", + "action": "DELETE", + "taskId": "task-id", + "before": { + "title": "Build Problem 5" + }, + "after": null, + "createdAt": "2026-08-03T15:00:00.000Z" +} +``` + +## Trouble log + +Validation errors, invalid JSON, resource-not-found errors, unknown routes, +and unexpected server errors are persisted automatically. + +SQLite table: + +```text +trouble_logs +``` + +List trouble records: + +```http +GET /api/v1/trouble-logs +``` + +Filters: + +```text +requestId +method +errorCode +statusCode +limit +offset +``` + +Examples: + +```http +GET /api/v1/trouble-logs?errorCode=VALIDATION_ERROR +GET /api/v1/trouble-logs?statusCode=404 +GET /api/v1/trouble-logs?requestId=manual-invalid-001 +``` + +Details: + +```http +GET /api/v1/trouble-logs/:id +``` + +Trouble response contains: + +```json +{ + "id": 1, + "requestId": "manual-invalid-001", + "method": "POST", + "path": "/api/v1/tasks", + "statusCode": 400, + "errorCode": "VALIDATION_ERROR", + "message": "title must contain between 1 and 120 characters", + "details": null, + "stack": "...", + "durationMs": 2, + "createdAt": "2026-08-03T15:00:00.000Z" +} +``` + +The stack is stored for review but is never returned in normal API error +responses. + +## Database migrations + +Tables: + +```text +schema_migrations +tasks +task_audit_logs +trouble_logs +``` + +`npm run db:migrate` applies migration 2 to an existing database created by the +previous version, so the current `data/problem5.sqlite` does not need to be +deleted. + +## Tests + +```bat +npm test +``` + +The tests verify: + +```text +CRUD persistence +3 audit records for create/update/delete +validation trouble logging +unknown-route trouble logging +audit-log API +trouble-log API +``` + +## Stress test + +```bat +npm run stress +``` + +Expected counters: + +```text +creates=250 +updates=100 +deletes=50 +auditRecords=400 +troubleRecords=50 +``` + +## Request collection + +Use: + +```text +requests.http +``` + +It includes CRUD, audit-log, trouble-log, and error-generation requests. + +## Exact source locations + +```text +src/problem5/src/database.ts +src/problem5/src/http/middleware.ts +src/problem5/src/http/observability.routes.ts +src/problem5/src/http/observability.validation.ts +src/problem5/src/repositories/observability.repository.ts +src/problem5/src/services/observability.service.ts +src/problem5/src/domain/observability.ts +``` diff --git a/src/problem5/data/.gitkeep b/src/problem5/data/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/problem5/package-lock.json b/src/problem5/package-lock.json new file mode 100644 index 0000000000..a675121bbe --- /dev/null +++ b/src/problem5/package-lock.json @@ -0,0 +1,1524 @@ +{ + "name": "problem5-crude-server", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "problem5-crude-server", + "version": "1.0.0", + "dependencies": { + "dotenv": "^16.5.0", + "express": "^5.1.0" + }, + "devDependencies": { + "@types/express": "^5.0.3", + "@types/node": "^22.15.0", + "tsx": "^4.19.4", + "typescript": "^5.8.3" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.3.tgz", + "integrity": "sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsx": { + "version": "4.23.5", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.5.tgz", + "integrity": "sha512-rw55FUaqOoI7RvlQwLbhO4nSDApnQ4/CykPuiQ/EPvtrX3WA9Ig55jIt9VvbBJbzJuj12ueRu4PMZ2SxPVbihg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + } + } +} diff --git a/src/problem5/package.json b/src/problem5/package.json new file mode 100644 index 0000000000..a80251b8ef --- /dev/null +++ b/src/problem5/package.json @@ -0,0 +1,29 @@ +{ + "name": "problem5-crude-server", + "version": "1.0.0", + "private": true, + "description": "ExpressJS TypeScript CRUD server with SQLite, audit logs, and trouble logs", + "main": "dist/src/server.js", + "engines": { + "node": ">=22.18.0" + }, + "scripts": { + "dev": "tsx watch src/server.ts", + "build": "tsc -p tsconfig.json", + "start": "node dist/src/server.js", + "db:migrate": "npm run build && node dist/src/scripts/migrate.js", + "db:seed": "npm run build && node dist/src/scripts/seed.js", + "test": "npm run build && node --test dist/test/core.test.js dist/test/api.test.js", + "stress": "npm run build && node dist/test/stress.js" + }, + "dependencies": { + "express": "^5.1.0", + "dotenv": "^16.5.0" + }, + "devDependencies": { + "@types/express": "^5.0.3", + "@types/node": "^22.15.0", + "tsx": "^4.19.4", + "typescript": "^5.8.3" + } +} diff --git a/src/problem5/requests.http b/src/problem5/requests.http new file mode 100644 index 0000000000..d543dd4f96 --- /dev/null +++ b/src/problem5/requests.http @@ -0,0 +1,60 @@ +@baseUrl = http://localhost:3000 +@taskId = replace-with-created-task-id + +### Health +GET {{baseUrl}}/health + +### Create task +POST {{baseUrl}}/api/v1/tasks +Content-Type: application/json +X-Request-Id: manual-create-001 + +{ + "title": "Build Problem 5", + "description": "ExpressJS CRUD API", + "status": "TODO", + "priority": "HIGH" +} + +### List tasks +GET {{baseUrl}}/api/v1/tasks?status=TODO&limit=20&offset=0 + +### Task details +GET {{baseUrl}}/api/v1/tasks/{{taskId}} + +### Update task +PATCH {{baseUrl}}/api/v1/tasks/{{taskId}} +Content-Type: application/json +X-Request-Id: manual-update-001 + +{ + "status": "DONE" +} + +### Delete task +DELETE {{baseUrl}}/api/v1/tasks/{{taskId}} +X-Request-Id: manual-delete-001 + +### Audit logs +GET {{baseUrl}}/api/v1/audit-logs?taskId={{taskId}}&limit=20&offset=0 + +### Audit log details +GET {{baseUrl}}/api/v1/audit-logs/1 + +### Trouble logs +GET {{baseUrl}}/api/v1/trouble-logs?limit=20&offset=0 + +### Filter trouble logs +GET {{baseUrl}}/api/v1/trouble-logs?errorCode=VALIDATION_ERROR&statusCode=400 + +### Trouble log details +GET {{baseUrl}}/api/v1/trouble-logs/1 + +### Generate validation trouble log +POST {{baseUrl}}/api/v1/tasks +Content-Type: application/json +X-Request-Id: manual-invalid-001 + +{ + "title": "" +} diff --git a/src/problem5/src/app.ts b/src/problem5/src/app.ts new file mode 100644 index 0000000000..6ab8493c5f --- /dev/null +++ b/src/problem5/src/app.ts @@ -0,0 +1,84 @@ +import express, { + type Express, + type Request, + type Response, +} from "express"; +import { Database } from "./database"; +import { + createErrorHandler, + createNotFoundHandler, + requestContext, +} from "./http/middleware"; +import { + createAuditLogRouter, + createTroubleLogRouter, +} from "./http/observability.routes"; +import { createTaskRouter } from "./http/task.routes"; +import { ObservabilityRepository } from "./repositories/observability.repository"; +import { TaskRepository } from "./repositories/task.repository"; +import { ObservabilityService } from "./services/observability.service"; +import { TaskService } from "./services/task.service"; + +export interface AppResources { + app: Express; + database: Database; + repository: TaskRepository; + observabilityRepository: ObservabilityRepository; +} + +export interface CreateAppOptions { + databasePath: string; + jsonLimit?: string; +} + +export function createApp(options: CreateAppOptions): AppResources { + const database = new Database(options.databasePath); + const repository = new TaskRepository(database); + const observabilityRepository = + new ObservabilityRepository(database); + + const taskService = new TaskService(repository); + const observabilityService = + new ObservabilityService(observabilityRepository); + + const app = express(); + + app.disable("x-powered-by"); + + // Must run before express.json so malformed JSON also receives a requestId + // and is written to trouble_logs. + app.use(requestContext); + app.use( + express.json({ + limit: options.jsonLimit ?? "32kb", + }), + ); + + app.get("/health", (_request: Request, response: Response) => { + response.json({ + status: "ok", + service: "problem5-crude-server", + timestamp: new Date().toISOString(), + }); + }); + + app.use("/api/v1/tasks", createTaskRouter(taskService)); + app.use( + "/api/v1/audit-logs", + createAuditLogRouter(observabilityService), + ); + app.use( + "/api/v1/trouble-logs", + createTroubleLogRouter(observabilityService), + ); + + app.use(createNotFoundHandler(observabilityService)); + app.use(createErrorHandler(observabilityService)); + + return { + app, + database, + repository, + observabilityRepository, + }; +} diff --git a/src/problem5/src/config.ts b/src/problem5/src/config.ts new file mode 100644 index 0000000000..d99476e52b --- /dev/null +++ b/src/problem5/src/config.ts @@ -0,0 +1,28 @@ +import "dotenv/config"; +import { resolve } from "node:path"; + +export interface AppConfig { + port: number; + databasePath: string; + jsonLimit: string; +} + +function parsePort(value: string | undefined): number { + const port = Number(value ?? "3000"); + + if (!Number.isInteger(port) || port < 0 || port > 65_535) { + throw new Error("PORT must be an integer between 0 and 65535"); + } + + return port; +} + +export function loadConfig(): AppConfig { + return { + port: parsePort(process.env.PORT), + databasePath: process.env.DATABASE_PATH + ? resolve(process.env.DATABASE_PATH) + : resolve(process.cwd(), "data", "problem5.sqlite"), + jsonLimit: process.env.JSON_LIMIT ?? "32kb", + }; +} diff --git a/src/problem5/src/database.ts b/src/problem5/src/database.ts new file mode 100644 index 0000000000..109700fb5a --- /dev/null +++ b/src/problem5/src/database.ts @@ -0,0 +1,151 @@ +import { mkdirSync } from "node:fs"; +import { dirname } from "node:path"; +import { DatabaseSync } from "node:sqlite"; + +export class Database { + private readonly connection: DatabaseSync; + + public constructor(path: string) { + if (path !== ":memory:") { + mkdirSync(dirname(path), { recursive: true }); + } + + this.connection = new DatabaseSync(path); + this.connection.exec("PRAGMA foreign_keys = ON"); + this.connection.exec("PRAGMA busy_timeout = 5000"); + + if (path !== ":memory:") { + this.connection.exec("PRAGMA journal_mode = WAL"); + } + + this.migrate(); + } + + public prepare(sql: string): ReturnType { + return this.connection.prepare(sql); + } + + public exec(sql: string): void { + this.connection.exec(sql); + } + + public transaction(operation: () => T): T { + this.connection.exec("BEGIN IMMEDIATE"); + + try { + const result = operation(); + this.connection.exec("COMMIT"); + return result; + } catch (error) { + this.connection.exec("ROLLBACK"); + throw error; + } + } + + public close(): void { + this.connection.close(); + } + + private hasMigration(version: number): boolean { + const row = this.connection + .prepare("SELECT version FROM schema_migrations WHERE version = ?") + .get(version) as { version: number } | undefined; + + return row !== undefined; + } + + private recordMigration(version: number): void { + this.connection + .prepare( + "INSERT INTO schema_migrations(version, applied_at) VALUES (?, ?)", + ) + .run(version, new Date().toISOString()); + } + + private migrate(): void { + this.connection.exec(` + CREATE TABLE IF NOT EXISTS schema_migrations ( + version INTEGER PRIMARY KEY, + applied_at TEXT NOT NULL + ); + `); + + if (!this.hasMigration(1)) { + this.transaction(() => { + this.connection.exec(` + CREATE TABLE IF NOT EXISTS tasks ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL CHECK(length(title) BETWEEN 1 AND 120), + description TEXT, + status TEXT NOT NULL CHECK(status IN ('TODO', 'IN_PROGRESS', 'DONE')), + priority TEXT NOT NULL CHECK(priority IN ('LOW', 'MEDIUM', 'HIGH')), + due_date TEXT, + version INTEGER NOT NULL DEFAULT 1 CHECK(version >= 1), + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL + ); + + CREATE INDEX IF NOT EXISTS idx_tasks_status + ON tasks(status); + CREATE INDEX IF NOT EXISTS idx_tasks_priority + ON tasks(priority); + CREATE INDEX IF NOT EXISTS idx_tasks_due_date + ON tasks(due_date); + CREATE INDEX IF NOT EXISTS idx_tasks_created_at + ON tasks(created_at); + + CREATE TABLE IF NOT EXISTS task_audit_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + trace_id TEXT NOT NULL, + action TEXT NOT NULL + CHECK(action IN ('CREATE', 'UPDATE', 'DELETE')), + task_id TEXT NOT NULL, + before_json TEXT, + after_json TEXT, + created_at TEXT NOT NULL + ); + + CREATE INDEX IF NOT EXISTS idx_task_audit_task_id + ON task_audit_logs(task_id); + CREATE INDEX IF NOT EXISTS idx_task_audit_trace_id + ON task_audit_logs(trace_id); + CREATE INDEX IF NOT EXISTS idx_task_audit_created_at + ON task_audit_logs(created_at); + `); + + this.recordMigration(1); + }); + } + + if (!this.hasMigration(2)) { + this.transaction(() => { + this.connection.exec(` + CREATE TABLE IF NOT EXISTS trouble_logs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + request_id TEXT NOT NULL, + method TEXT NOT NULL, + path TEXT NOT NULL, + status_code INTEGER NOT NULL, + error_code TEXT NOT NULL, + message TEXT NOT NULL, + details_json TEXT, + stack TEXT, + duration_ms INTEGER NOT NULL CHECK(duration_ms >= 0), + created_at TEXT NOT NULL + ); + + CREATE INDEX IF NOT EXISTS idx_trouble_request_id + ON trouble_logs(request_id); + CREATE INDEX IF NOT EXISTS idx_trouble_error_code + ON trouble_logs(error_code); + CREATE INDEX IF NOT EXISTS idx_trouble_status_code + ON trouble_logs(status_code); + CREATE INDEX IF NOT EXISTS idx_trouble_created_at + ON trouble_logs(created_at); + `); + + this.recordMigration(2); + }); + } + } +} diff --git a/src/problem5/src/domain/observability.ts b/src/problem5/src/domain/observability.ts new file mode 100644 index 0000000000..d27e6629b1 --- /dev/null +++ b/src/problem5/src/domain/observability.ts @@ -0,0 +1,67 @@ +export const AUDIT_ACTIONS = [ + "CREATE", + "UPDATE", + "DELETE", +] as const; + +export type AuditAction = (typeof AUDIT_ACTIONS)[number]; + +export interface AuditLog { + id: number; + traceId: string; + action: AuditAction; + taskId: string; + before: unknown | null; + after: unknown | null; + createdAt: string; +} + +export interface AuditLogFilters { + taskId?: string; + traceId?: string; + action?: AuditAction; + limit: number; + offset: number; +} + +export interface TroubleLog { + id: number; + requestId: string; + method: string; + path: string; + statusCode: number; + errorCode: string; + message: string; + details: unknown | null; + stack: string | null; + durationMs: number; + createdAt: string; +} + +export interface TroubleLogFilters { + requestId?: string; + method?: string; + errorCode?: string; + statusCode?: number; + limit: number; + offset: number; +} + +export interface TroubleLogInput { + requestId: string; + method: string; + path: string; + statusCode: number; + errorCode: string; + message: string; + details?: unknown; + stack?: string; + durationMs: number; +} + +export interface ListResult { + items: T[]; + total: number; + limit: number; + offset: number; +} diff --git a/src/problem5/src/domain/task.ts b/src/problem5/src/domain/task.ts new file mode 100644 index 0000000000..625c1a18d1 --- /dev/null +++ b/src/problem5/src/domain/task.ts @@ -0,0 +1,52 @@ +export const TASK_STATUSES = ["TODO", "IN_PROGRESS", "DONE"] as const; +export const TASK_PRIORITIES = ["LOW", "MEDIUM", "HIGH"] as const; + +export type TaskStatus = (typeof TASK_STATUSES)[number]; +export type TaskPriority = (typeof TASK_PRIORITIES)[number]; + +export interface Task { + id: string; + title: string; + description: string | null; + status: TaskStatus; + priority: TaskPriority; + dueDate: string | null; + version: number; + createdAt: string; + updatedAt: string; +} + +export interface CreateTaskInput { + title: string; + description?: string | null; + status?: TaskStatus; + priority?: TaskPriority; + dueDate?: string | null; +} + +export interface UpdateTaskInput { + title?: string; + description?: string | null; + status?: TaskStatus; + priority?: TaskPriority; + dueDate?: string | null; +} + +export interface TaskFilters { + search?: string; + status?: TaskStatus; + priority?: TaskPriority; + dueAfter?: string; + dueBefore?: string; + sortBy: "title" | "status" | "priority" | "dueDate" | "createdAt" | "updatedAt"; + order: "asc" | "desc"; + limit: number; + offset: number; +} + +export interface TaskListResult { + items: Task[]; + total: number; + limit: number; + offset: number; +} diff --git a/src/problem5/src/errors.ts b/src/problem5/src/errors.ts new file mode 100644 index 0000000000..e25a898f00 --- /dev/null +++ b/src/problem5/src/errors.ts @@ -0,0 +1,20 @@ +export type ErrorDetails = Record | readonly unknown[]; + +export class AppError extends Error { + public readonly statusCode: number; + public readonly code: string; + public readonly details: ErrorDetails | undefined; + + public constructor( + statusCode: number, + code: string, + message: string, + details?: ErrorDetails, + ) { + super(message); + this.name = "AppError"; + this.statusCode = statusCode; + this.code = code; + this.details = details; + } +} diff --git a/src/problem5/src/http/middleware.ts b/src/problem5/src/http/middleware.ts new file mode 100644 index 0000000000..89a0ef2d9d --- /dev/null +++ b/src/problem5/src/http/middleware.ts @@ -0,0 +1,197 @@ +import { randomUUID } from "node:crypto"; +import type { + ErrorRequestHandler, + NextFunction, + Request, + RequestHandler, + Response, +} from "express"; +import type { TroubleLogInput } from "../domain/observability"; +import { AppError } from "../errors"; +import { ObservabilityService } from "../services/observability.service"; + +export function requestContext( + request: Request, + response: Response, + next: NextFunction, +): void { + const incoming = request.header("x-request-id"); + const normalized = incoming?.trim(); + const requestId = + normalized && normalized.length <= 128 + ? normalized + : randomUUID(); + + response.locals.requestId = requestId; + response.locals.startedAt = Date.now(); + response.setHeader("x-request-id", requestId); + next(); +} + +interface NormalizedError { + statusCode: number; + code: string; + message: string; + details?: unknown; + stack?: string; +} + +function addStack( + normalized: NormalizedError, + stack: string | undefined, +): NormalizedError { + if (stack !== undefined) { + normalized.stack = stack; + } + + return normalized; +} + +function normalizeError(error: unknown): NormalizedError { + if (error instanceof SyntaxError && "body" in error) { + return addStack( + { + statusCode: 400, + code: "INVALID_JSON", + message: "Request body contains invalid JSON", + }, + error.stack, + ); + } + + if (error instanceof AppError) { + const normalized: NormalizedError = { + statusCode: error.statusCode, + code: error.code, + message: error.message, + }; + + if (error.details !== undefined) { + normalized.details = error.details; + } + + return addStack(normalized, error.stack); + } + + if (error instanceof Error) { + return addStack( + { + statusCode: 500, + code: "INTERNAL_SERVER_ERROR", + message: "An unexpected error occurred", + }, + error.stack, + ); + } + + return { + statusCode: 500, + code: "INTERNAL_SERVER_ERROR", + message: "An unexpected error occurred", + }; +} + +function durationFrom(response: Response): number { + const startedAt = response.locals.startedAt; + + return typeof startedAt === "number" + ? Math.max(0, Date.now() - startedAt) + : 0; +} + +function recordTroubleSafely( + service: ObservabilityService, + request: Request, + response: Response, + error: NormalizedError, +): void { + try { + const trouble: TroubleLogInput = { + requestId: + typeof response.locals.requestId === "string" + ? response.locals.requestId + : randomUUID(), + method: request.method, + path: request.originalUrl, + statusCode: error.statusCode, + errorCode: error.code, + message: error.message, + durationMs: durationFrom(response), + }; + + if (error.details !== undefined) { + trouble.details = error.details; + } + + if (error.stack !== undefined) { + trouble.stack = error.stack; + } + + service.recordTrouble(trouble); + } catch (loggingError) { + console.error("Trouble log write failed", loggingError); + } +} + +export function createNotFoundHandler( + service: ObservabilityService, +): RequestHandler { + return ( + request: Request, + response: Response, + ): void => { + const error: NormalizedError = { + statusCode: 404, + code: "ROUTE_NOT_FOUND", + message: `No route matches ${request.method} ${request.originalUrl}`, + }; + + recordTroubleSafely( + service, + request, + response, + error, + ); + + response.status(error.statusCode).json({ + error: { + code: error.code, + message: error.message, + requestId: response.locals.requestId, + }, + }); + }; +} + +export function createErrorHandler( + service: ObservabilityService, +): ErrorRequestHandler { + return ( + error: unknown, + request: Request, + response: Response, + _next: NextFunction, + ): void => { + const normalized = normalizeError(error); + + recordTroubleSafely( + service, + request, + response, + normalized, + ); + + if (normalized.statusCode >= 500) { + console.error(error); + } + + response.status(normalized.statusCode).json({ + error: { + code: normalized.code, + message: normalized.message, + details: normalized.details, + requestId: response.locals.requestId, + }, + }); + }; +} diff --git a/src/problem5/src/http/observability.routes.ts b/src/problem5/src/http/observability.routes.ts new file mode 100644 index 0000000000..3ff48facc8 --- /dev/null +++ b/src/problem5/src/http/observability.routes.ts @@ -0,0 +1,77 @@ +import { + Router, + type Request, + type Response, +} from "express"; +import { ObservabilityService } from "../services/observability.service"; +import { + parseAuditLogFilters, + parseLogId, + parseTroubleLogFilters, +} from "./observability.validation"; + +export function createAuditLogRouter( + service: ObservabilityService, +): Router { + const router = Router(); + + router.get("/", (request: Request, response: Response) => { + const result = service.listAuditLogs( + parseAuditLogFilters( + request.query as Record, + ), + ); + + response.json({ + data: result.items, + meta: { + total: result.total, + limit: result.limit, + offset: result.offset, + }, + }); + }); + + router.get("/:id", (request: Request, response: Response) => { + response.json({ + data: service.getAuditLog( + parseLogId(request.params.id), + ), + }); + }); + + return router; +} + +export function createTroubleLogRouter( + service: ObservabilityService, +): Router { + const router = Router(); + + router.get("/", (request: Request, response: Response) => { + const result = service.listTroubleLogs( + parseTroubleLogFilters( + request.query as Record, + ), + ); + + response.json({ + data: result.items, + meta: { + total: result.total, + limit: result.limit, + offset: result.offset, + }, + }); + }); + + router.get("/:id", (request: Request, response: Response) => { + response.json({ + data: service.getTroubleLog( + parseLogId(request.params.id), + ), + }); + }); + + return router; +} diff --git a/src/problem5/src/http/observability.validation.ts b/src/problem5/src/http/observability.validation.ts new file mode 100644 index 0000000000..8e4c514c25 --- /dev/null +++ b/src/problem5/src/http/observability.validation.ts @@ -0,0 +1,161 @@ +import { + AUDIT_ACTIONS, + type AuditAction, + type AuditLogFilters, + type TroubleLogFilters, +} from "../domain/observability"; +import { AppError } from "../errors"; + +function singleQueryValue( + value: unknown, + field: string, +): string | undefined { + if (value === undefined) { + return undefined; + } + + if (typeof value !== "string") { + throw new AppError( + 400, + "VALIDATION_ERROR", + `${field} must appear once`, + ); + } + + const normalized = value.trim(); + return normalized === "" ? undefined : normalized; +} + +function parseInteger( + value: string | undefined, + fallback: number, + field: string, + minimum: number, + maximum: number, +): number { + if (value === undefined) { + return fallback; + } + + if (!/^\d+$/.test(value)) { + throw new AppError( + 400, + "VALIDATION_ERROR", + `${field} must be an integer`, + ); + } + + const parsed = Number(value); + + if ( + !Number.isSafeInteger(parsed) || + parsed < minimum || + parsed > maximum + ) { + throw new AppError( + 400, + "VALIDATION_ERROR", + `${field} must be between ${minimum} and ${maximum}`, + ); + } + + return parsed; +} + +export function parseLogId(value: unknown): number { + if (typeof value !== "string") { + throw new AppError( + 400, + "VALIDATION_ERROR", + "Log id is required", + ); + } + + return parseInteger(value, 0, "id", 1, Number.MAX_SAFE_INTEGER); +} + +export function parseAuditLogFilters( + query: Record, +): AuditLogFilters { + const actionValue = singleQueryValue(query.action, "action")?.toUpperCase(); + + if ( + actionValue !== undefined && + !AUDIT_ACTIONS.includes(actionValue as AuditAction) + ) { + throw new AppError( + 400, + "VALIDATION_ERROR", + "Invalid audit action", + { allowed: AUDIT_ACTIONS }, + ); + } + + const filters: AuditLogFilters = { + limit: parseInteger( + singleQueryValue(query.limit, "limit"), + 20, + "limit", + 1, + 100, + ), + offset: parseInteger( + singleQueryValue(query.offset, "offset"), + 0, + "offset", + 0, + 1_000_000, + ), + }; + + const taskId = singleQueryValue(query.taskId, "taskId"); + const traceId = singleQueryValue(query.traceId, "traceId"); + + if (taskId) filters.taskId = taskId; + if (traceId) filters.traceId = traceId; + if (actionValue) filters.action = actionValue as AuditAction; + + return filters; +} + +export function parseTroubleLogFilters( + query: Record, +): TroubleLogFilters { + const filters: TroubleLogFilters = { + limit: parseInteger( + singleQueryValue(query.limit, "limit"), + 20, + "limit", + 1, + 100, + ), + offset: parseInteger( + singleQueryValue(query.offset, "offset"), + 0, + "offset", + 0, + 1_000_000, + ), + }; + + const requestId = singleQueryValue(query.requestId, "requestId"); + const method = singleQueryValue(query.method, "method")?.toUpperCase(); + const errorCode = singleQueryValue(query.errorCode, "errorCode"); + const statusCodeValue = singleQueryValue(query.statusCode, "statusCode"); + + if (requestId) filters.requestId = requestId; + if (method) filters.method = method; + if (errorCode) filters.errorCode = errorCode; + + if (statusCodeValue !== undefined) { + filters.statusCode = parseInteger( + statusCodeValue, + 0, + "statusCode", + 100, + 599, + ); + } + + return filters; +} diff --git a/src/problem5/src/http/task.routes.ts b/src/problem5/src/http/task.routes.ts new file mode 100644 index 0000000000..9fc901319b --- /dev/null +++ b/src/problem5/src/http/task.routes.ts @@ -0,0 +1,70 @@ +import { Router, type Request, type Response } from "express"; +import { AppError } from "../errors"; +import { TaskService } from "../services/task.service"; +import { + parseCreateTask, + parseTaskFilters, + parseUpdateTask, +} from "./validation"; + +function idFrom(request: Request): string { + const id = request.params.id; + + if (typeof id !== "string" || id.trim() === "") { + throw new AppError(400, "VALIDATION_ERROR", "Task id is required"); + } + + return id; +} + +export function createTaskRouter(service: TaskService): Router { + const router = Router(); + + router.post("/", (request: Request, response: Response) => { + const task = service.create( + parseCreateTask(request.body), + response.locals.requestId, + ); + + response + .status(201) + .location(`/api/v1/tasks/${task.id}`) + .json({ data: task }); + }); + + router.get("/", (request: Request, response: Response) => { + const result = service.list( + parseTaskFilters(request.query as Record), + ); + + response.json({ + data: result.items, + meta: { + total: result.total, + limit: result.limit, + offset: result.offset, + }, + }); + }); + + router.get("/:id", (request: Request, response: Response) => { + response.json({ data: service.get(idFrom(request)) }); + }); + + router.patch("/:id", (request: Request, response: Response) => { + const task = service.update( + idFrom(request), + parseUpdateTask(request.body), + response.locals.requestId, + ); + + response.json({ data: task }); + }); + + router.delete("/:id", (request: Request, response: Response) => { + service.delete(idFrom(request), response.locals.requestId); + response.status(204).send(); + }); + + return router; +} diff --git a/src/problem5/src/http/validation.ts b/src/problem5/src/http/validation.ts new file mode 100644 index 0000000000..438ea0f7fa --- /dev/null +++ b/src/problem5/src/http/validation.ts @@ -0,0 +1,275 @@ +import { AppError } from "../errors"; +import { + TASK_PRIORITIES, + TASK_STATUSES, + type CreateTaskInput, + type TaskFilters, + type TaskPriority, + type TaskStatus, + type UpdateTaskInput, +} from "../domain/task"; + +const CREATE_FIELDS = new Set([ + "title", + "description", + "status", + "priority", + "dueDate", +]); + +const UPDATE_FIELDS = CREATE_FIELDS; + +function requireObject(value: unknown): Record { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new AppError(400, "VALIDATION_ERROR", "Request body must be an object"); + } + + return value as Record; +} + +function rejectUnknownFields( + object: Record, + allowed: ReadonlySet, +): void { + const unknown = Object.keys(object).filter((key) => !allowed.has(key)); + + if (unknown.length > 0) { + throw new AppError(400, "VALIDATION_ERROR", "Unknown request fields", { + unknownFields: unknown, + }); + } +} + +function parseTitle(value: unknown): string { + if (typeof value !== "string") { + throw new AppError(400, "VALIDATION_ERROR", "title must be a string"); + } + + const title = value.trim(); + + if (title.length < 1 || title.length > 120) { + throw new AppError( + 400, + "VALIDATION_ERROR", + "title must contain between 1 and 120 characters", + ); + } + + return title; +} + +function parseDescription(value: unknown): string | null { + if (value === null) { + return null; + } + + if (typeof value !== "string") { + throw new AppError( + 400, + "VALIDATION_ERROR", + "description must be a string or null", + ); + } + + const description = value.trim(); + + if (description.length > 2_000) { + throw new AppError( + 400, + "VALIDATION_ERROR", + "description must not exceed 2000 characters", + ); + } + + return description || null; +} + +function parseStatus(value: unknown): TaskStatus { + if (typeof value !== "string" || !TASK_STATUSES.includes(value as TaskStatus)) { + throw new AppError(400, "VALIDATION_ERROR", "Invalid task status", { + allowed: TASK_STATUSES, + }); + } + + return value as TaskStatus; +} + +function parsePriority(value: unknown): TaskPriority { + if ( + typeof value !== "string" || + !TASK_PRIORITIES.includes(value as TaskPriority) + ) { + throw new AppError(400, "VALIDATION_ERROR", "Invalid task priority", { + allowed: TASK_PRIORITIES, + }); + } + + return value as TaskPriority; +} + +function parseDate(value: unknown, field: string): string | null { + if (value === null) { + return null; + } + + if (typeof value !== "string" || value.trim() === "") { + throw new AppError(400, "VALIDATION_ERROR", `${field} must be an ISO date`); + } + + const date = new Date(value); + + if (Number.isNaN(date.getTime())) { + throw new AppError(400, "VALIDATION_ERROR", `${field} must be an ISO date`); + } + + return date.toISOString(); +} + +export function parseCreateTask(body: unknown): CreateTaskInput { + const object = requireObject(body); + rejectUnknownFields(object, CREATE_FIELDS); + + if (!("title" in object)) { + throw new AppError(400, "VALIDATION_ERROR", "title is required"); + } + + return { + title: parseTitle(object.title), + description: + "description" in object ? parseDescription(object.description) : null, + status: "status" in object ? parseStatus(object.status) : "TODO", + priority: + "priority" in object ? parsePriority(object.priority) : "MEDIUM", + dueDate: "dueDate" in object ? parseDate(object.dueDate, "dueDate") : null, + }; +} + +export function parseUpdateTask(body: unknown): UpdateTaskInput { + const object = requireObject(body); + rejectUnknownFields(object, UPDATE_FIELDS); + + if (Object.keys(object).length === 0) { + throw new AppError( + 400, + "VALIDATION_ERROR", + "At least one field must be provided", + ); + } + + const result: UpdateTaskInput = {}; + + if ("title" in object) result.title = parseTitle(object.title); + if ("description" in object) { + result.description = parseDescription(object.description); + } + if ("status" in object) result.status = parseStatus(object.status); + if ("priority" in object) result.priority = parsePriority(object.priority); + if ("dueDate" in object) result.dueDate = parseDate(object.dueDate, "dueDate"); + + return result; +} + +function singleQueryValue(value: unknown, field: string): string | undefined { + if (value === undefined) { + return undefined; + } + + if (typeof value !== "string") { + throw new AppError(400, "VALIDATION_ERROR", `${field} must appear once`); + } + + return value; +} + +function parseNonNegativeInteger( + value: string | undefined, + fallback: number, + field: string, + maximum: number, +): number { + if (value === undefined) { + return fallback; + } + + if (!/^\d+$/.test(value)) { + throw new AppError( + 400, + "VALIDATION_ERROR", + `${field} must be a non-negative integer`, + ); + } + + const parsed = Number(value); + + if (!Number.isSafeInteger(parsed) || parsed > maximum) { + throw new AppError( + 400, + "VALIDATION_ERROR", + `${field} must not exceed ${maximum}`, + ); + } + + return parsed; +} + +export function parseTaskFilters(query: Record): TaskFilters { + const search = singleQueryValue(query.search, "search")?.trim(); + const statusValue = singleQueryValue(query.status, "status"); + const priorityValue = singleQueryValue(query.priority, "priority"); + const dueAfterValue = singleQueryValue(query.dueAfter, "dueAfter"); + const dueBeforeValue = singleQueryValue(query.dueBefore, "dueBefore"); + const sortByValue = singleQueryValue(query.sortBy, "sortBy") ?? "createdAt"; + const orderValue = singleQueryValue(query.order, "order")?.toLowerCase() ?? "desc"; + + const allowedSorts = [ + "title", + "status", + "priority", + "dueDate", + "createdAt", + "updatedAt", + ] as const; + + if (!allowedSorts.includes(sortByValue as TaskFilters["sortBy"])) { + throw new AppError(400, "VALIDATION_ERROR", "Invalid sortBy", { + allowed: allowedSorts, + }); + } + + if (orderValue !== "asc" && orderValue !== "desc") { + throw new AppError(400, "VALIDATION_ERROR", "order must be asc or desc"); + } + + const filters: TaskFilters = { + sortBy: sortByValue as TaskFilters["sortBy"], + order: orderValue, + limit: parseNonNegativeInteger( + singleQueryValue(query.limit, "limit"), + 20, + "limit", + 100, + ), + offset: parseNonNegativeInteger( + singleQueryValue(query.offset, "offset"), + 0, + "offset", + 1_000_000, + ), + }; + + if (search) filters.search = search; + if (statusValue !== undefined) filters.status = parseStatus(statusValue); + if (priorityValue !== undefined) { + filters.priority = parsePriority(priorityValue); + } + if (dueAfterValue !== undefined) { + const dueAfter = parseDate(dueAfterValue, "dueAfter"); + if (dueAfter !== null) filters.dueAfter = dueAfter; + } + if (dueBeforeValue !== undefined) { + const dueBefore = parseDate(dueBeforeValue, "dueBefore"); + if (dueBefore !== null) filters.dueBefore = dueBefore; + } + + return filters; +} diff --git a/src/problem5/src/repositories/observability.repository.ts b/src/problem5/src/repositories/observability.repository.ts new file mode 100644 index 0000000000..78d9ed1d2a --- /dev/null +++ b/src/problem5/src/repositories/observability.repository.ts @@ -0,0 +1,268 @@ +import { Database } from "../database"; +import type { + AuditLog, + AuditLogFilters, + ListResult, + TroubleLog, + TroubleLogFilters, + TroubleLogInput, +} from "../domain/observability"; + +interface AuditLogRow { + id: number; + trace_id: string; + action: AuditLog["action"]; + task_id: string; + before_json: string | null; + after_json: string | null; + created_at: string; +} + +interface TroubleLogRow { + id: number; + request_id: string; + method: string; + path: string; + status_code: number; + error_code: string; + message: string; + details_json: string | null; + stack: string | null; + duration_ms: number; + created_at: string; +} + +function parseJson(value: string | null): unknown | null { + return value === null ? null : JSON.parse(value); +} + +function mapAuditLog(row: AuditLogRow): AuditLog { + return { + id: Number(row.id), + traceId: row.trace_id, + action: row.action, + taskId: row.task_id, + before: parseJson(row.before_json), + after: parseJson(row.after_json), + createdAt: row.created_at, + }; +} + +function mapTroubleLog(row: TroubleLogRow): TroubleLog { + return { + id: Number(row.id), + requestId: row.request_id, + method: row.method, + path: row.path, + statusCode: Number(row.status_code), + errorCode: row.error_code, + message: row.message, + details: parseJson(row.details_json), + stack: row.stack, + durationMs: Number(row.duration_ms), + createdAt: row.created_at, + }; +} + +export class ObservabilityRepository { + public constructor(private readonly database: Database) {} + + public listAuditLogs( + filters: AuditLogFilters, + ): ListResult { + const conditions: string[] = []; + const parameters: Array = []; + + if (filters.taskId) { + conditions.push("task_id = ?"); + parameters.push(filters.taskId); + } + + if (filters.traceId) { + conditions.push("trace_id = ?"); + parameters.push(filters.traceId); + } + + if (filters.action) { + conditions.push("action = ?"); + parameters.push(filters.action); + } + + const where = + conditions.length > 0 + ? `WHERE ${conditions.join(" AND ")}` + : ""; + + const countRow = this.database + .prepare(` + SELECT COUNT(*) AS total + FROM task_audit_logs + ${where} + `) + .get(...parameters) as { total: number }; + + const rows = this.database + .prepare(` + SELECT * + FROM task_audit_logs + ${where} + ORDER BY id DESC + LIMIT ? OFFSET ? + `) + .all( + ...parameters, + filters.limit, + filters.offset, + ) as unknown as AuditLogRow[]; + + return { + items: rows.map(mapAuditLog), + total: Number(countRow.total), + limit: filters.limit, + offset: filters.offset, + }; + } + + public findAuditLogById(id: number): AuditLog | null { + const row = this.database + .prepare(` + SELECT * + FROM task_audit_logs + WHERE id = ? + `) + .get(id) as AuditLogRow | undefined; + + return row ? mapAuditLog(row) : null; + } + + public writeTroubleLog(input: TroubleLogInput): TroubleLog { + const createdAt = new Date().toISOString(); + const result = this.database + .prepare(` + INSERT INTO trouble_logs( + request_id, + method, + path, + status_code, + error_code, + message, + details_json, + stack, + duration_ms, + created_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `) + .run( + input.requestId, + input.method, + input.path, + input.statusCode, + input.errorCode, + input.message, + input.details === undefined + ? null + : JSON.stringify(input.details), + input.stack ?? null, + input.durationMs, + createdAt, + ); + + return { + id: Number(result.lastInsertRowid), + requestId: input.requestId, + method: input.method, + path: input.path, + statusCode: input.statusCode, + errorCode: input.errorCode, + message: input.message, + details: input.details ?? null, + stack: input.stack ?? null, + durationMs: input.durationMs, + createdAt, + }; + } + + public listTroubleLogs( + filters: TroubleLogFilters, + ): ListResult { + const conditions: string[] = []; + const parameters: Array = []; + + if (filters.requestId) { + conditions.push("request_id = ?"); + parameters.push(filters.requestId); + } + + if (filters.method) { + conditions.push("method = ?"); + parameters.push(filters.method); + } + + if (filters.errorCode) { + conditions.push("error_code = ?"); + parameters.push(filters.errorCode); + } + + if (filters.statusCode !== undefined) { + conditions.push("status_code = ?"); + parameters.push(filters.statusCode); + } + + const where = + conditions.length > 0 + ? `WHERE ${conditions.join(" AND ")}` + : ""; + + const countRow = this.database + .prepare(` + SELECT COUNT(*) AS total + FROM trouble_logs + ${where} + `) + .get(...parameters) as { total: number }; + + const rows = this.database + .prepare(` + SELECT * + FROM trouble_logs + ${where} + ORDER BY id DESC + LIMIT ? OFFSET ? + `) + .all( + ...parameters, + filters.limit, + filters.offset, + ) as unknown as TroubleLogRow[]; + + return { + items: rows.map(mapTroubleLog), + total: Number(countRow.total), + limit: filters.limit, + offset: filters.offset, + }; + } + + public findTroubleLogById(id: number): TroubleLog | null { + const row = this.database + .prepare(` + SELECT * + FROM trouble_logs + WHERE id = ? + `) + .get(id) as TroubleLogRow | undefined; + + return row ? mapTroubleLog(row) : null; + } + + public countTroubleLogs(): number { + const row = this.database + .prepare(` + SELECT COUNT(*) AS total + FROM trouble_logs + `) + .get() as { total: number }; + + return Number(row.total); + } +} diff --git a/src/problem5/src/repositories/task.repository.ts b/src/problem5/src/repositories/task.repository.ts new file mode 100644 index 0000000000..20489b85ab --- /dev/null +++ b/src/problem5/src/repositories/task.repository.ts @@ -0,0 +1,253 @@ +import { randomUUID } from "node:crypto"; +import { Database } from "../database"; +import type { + CreateTaskInput, + Task, + TaskFilters, + TaskListResult, + UpdateTaskInput, +} from "../domain/task"; + +interface TaskRow { + id: string; + title: string; + description: string | null; + status: Task["status"]; + priority: Task["priority"]; + due_date: string | null; + version: number; + created_at: string; + updated_at: string; +} + +const SORT_COLUMNS: Record = { + title: "title", + status: "status", + priority: "priority", + dueDate: "due_date", + createdAt: "created_at", + updatedAt: "updated_at", +}; + +function mapTask(row: TaskRow): Task { + return { + id: row.id, + title: row.title, + description: row.description, + status: row.status, + priority: row.priority, + dueDate: row.due_date, + version: row.version, + createdAt: row.created_at, + updatedAt: row.updated_at, + }; +} + +export class TaskRepository { + public constructor(private readonly database: Database) {} + + public create(input: CreateTaskInput, traceId: string): Task { + const now = new Date().toISOString(); + const task: Task = { + id: randomUUID(), + title: input.title, + description: input.description ?? null, + status: input.status ?? "TODO", + priority: input.priority ?? "MEDIUM", + dueDate: input.dueDate ?? null, + version: 1, + createdAt: now, + updatedAt: now, + }; + + return this.database.transaction(() => { + this.database + .prepare(` + INSERT INTO tasks( + id, title, description, status, priority, due_date, + version, created_at, updated_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + `) + .run( + task.id, + task.title, + task.description, + task.status, + task.priority, + task.dueDate, + task.version, + task.createdAt, + task.updatedAt, + ); + + this.writeAudit(traceId, "CREATE", task.id, null, task); + return task; + }); + } + + public list(filters: TaskFilters): TaskListResult { + const conditions: string[] = []; + const parameters: Array = []; + + if (filters.search) { + conditions.push("(title LIKE ? ESCAPE '\\' OR description LIKE ? ESCAPE '\\')"); + const escaped = filters.search.replace(/[\\%_]/g, "\\$&"); + const pattern = `%${escaped}%`; + parameters.push(pattern, pattern); + } + + if (filters.status) { + conditions.push("status = ?"); + parameters.push(filters.status); + } + + if (filters.priority) { + conditions.push("priority = ?"); + parameters.push(filters.priority); + } + + if (filters.dueAfter) { + conditions.push("due_date IS NOT NULL AND due_date >= ?"); + parameters.push(filters.dueAfter); + } + + if (filters.dueBefore) { + conditions.push("due_date IS NOT NULL AND due_date <= ?"); + parameters.push(filters.dueBefore); + } + + const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; + const sortColumn = SORT_COLUMNS[filters.sortBy]; + const sortOrder = filters.order.toUpperCase(); + + const countRow = this.database + .prepare(`SELECT COUNT(*) AS total FROM tasks ${where}`) + .get(...parameters) as { total: number }; + + const rows = this.database + .prepare(` + SELECT * FROM tasks + ${where} + ORDER BY ${sortColumn} ${sortOrder}, id ASC + LIMIT ? OFFSET ? + `) + .all(...parameters, filters.limit, filters.offset) as unknown as TaskRow[]; + + return { + items: rows.map(mapTask), + total: Number(countRow.total), + limit: filters.limit, + offset: filters.offset, + }; + } + + public findById(id: string): Task | null { + const row = this.database + .prepare("SELECT * FROM tasks WHERE id = ?") + .get(id) as TaskRow | undefined; + + return row ? mapTask(row) : null; + } + + public update(id: string, input: UpdateTaskInput, traceId: string): Task | null { + return this.database.transaction(() => { + const existing = this.findById(id); + + if (!existing) { + return null; + } + + const updated: Task = { + ...existing, + ...input, + description: + input.description === undefined ? existing.description : input.description, + dueDate: input.dueDate === undefined ? existing.dueDate : input.dueDate, + version: existing.version + 1, + updatedAt: new Date().toISOString(), + }; + + const result = this.database + .prepare(` + UPDATE tasks + SET title = ?, description = ?, status = ?, priority = ?, due_date = ?, + version = ?, updated_at = ? + WHERE id = ? AND version = ? + `) + .run( + updated.title, + updated.description, + updated.status, + updated.priority, + updated.dueDate, + updated.version, + updated.updatedAt, + id, + existing.version, + ); + + if (Number(result.changes) !== 1) { + throw new Error("Concurrent update detected"); + } + + this.writeAudit(traceId, "UPDATE", id, existing, updated); + return updated; + }); + } + + public delete(id: string, traceId: string): boolean { + return this.database.transaction(() => { + const existing = this.findById(id); + + if (!existing) { + return false; + } + + const result = this.database + .prepare("DELETE FROM tasks WHERE id = ?") + .run(id); + + if (Number(result.changes) !== 1) { + throw new Error("Task could not be deleted"); + } + + this.writeAudit(traceId, "DELETE", id, existing, null); + return true; + }); + } + + public countAuditLogs(taskId?: string): number { + const row = taskId + ? (this.database + .prepare("SELECT COUNT(*) AS total FROM task_audit_logs WHERE task_id = ?") + .get(taskId) as { total: number }) + : (this.database + .prepare("SELECT COUNT(*) AS total FROM task_audit_logs") + .get() as { total: number }); + + return Number(row.total); + } + + private writeAudit( + traceId: string, + action: "CREATE" | "UPDATE" | "DELETE", + taskId: string, + before: Task | null, + after: Task | null, + ): void { + this.database + .prepare(` + INSERT INTO task_audit_logs( + trace_id, action, task_id, before_json, after_json, created_at + ) VALUES (?, ?, ?, ?, ?, ?) + `) + .run( + traceId, + action, + taskId, + before ? JSON.stringify(before) : null, + after ? JSON.stringify(after) : null, + new Date().toISOString(), + ); + } +} diff --git a/src/problem5/src/scripts/migrate.ts b/src/problem5/src/scripts/migrate.ts new file mode 100644 index 0000000000..ce29fd3d64 --- /dev/null +++ b/src/problem5/src/scripts/migrate.ts @@ -0,0 +1,8 @@ +import { Database } from "../database"; +import { loadConfig } from "../config"; + +const config = loadConfig(); +const database = new Database(config.databasePath); +database.close(); + +console.log(`Database is ready: ${config.databasePath}`); diff --git a/src/problem5/src/scripts/seed.ts b/src/problem5/src/scripts/seed.ts new file mode 100644 index 0000000000..24488a6252 --- /dev/null +++ b/src/problem5/src/scripts/seed.ts @@ -0,0 +1,44 @@ +import { randomUUID } from "node:crypto"; +import { loadConfig } from "../config"; +import { Database } from "../database"; +import { TaskRepository } from "../repositories/task.repository"; + +const config = loadConfig(); +const database = new Database(config.databasePath); +const repository = new TaskRepository(database); + +const existing = repository.list({ + sortBy: "createdAt", + order: "desc", + limit: 1, + offset: 0, +}); + +if (existing.total === 0) { + repository.create( + { + title: "Review the CRUD API", + description: "Try the filters, update the task, then delete it.", + status: "TODO", + priority: "HIGH", + dueDate: new Date(Date.now() + 86_400_000).toISOString(), + }, + randomUUID(), + ); + + repository.create( + { + title: "Read README.md", + status: "DONE", + priority: "MEDIUM", + dueDate: null, + }, + randomUUID(), + ); + + console.log("Seeded 2 tasks"); +} else { + console.log("Seed skipped because tasks already exist"); +} + +database.close(); diff --git a/src/problem5/src/server.ts b/src/problem5/src/server.ts new file mode 100644 index 0000000000..3f2289f7e2 --- /dev/null +++ b/src/problem5/src/server.ts @@ -0,0 +1,30 @@ +import { createApp } from "./app"; +import { loadConfig } from "./config"; + +const config = loadConfig(); +const { app, database } = createApp({ + databasePath: config.databasePath, + jsonLimit: config.jsonLimit, +}); + +const server = app.listen(config.port, () => { + const address = server.address(); + const port = typeof address === "object" && address ? address.port : config.port; + + console.log(`Problem 5 server listening on http://localhost:${port}`); + console.log(`SQLite database: ${config.databasePath}`); +}); + +function shutdown(signal: string): void { + console.log(`${signal} received; shutting down`); + + server.close(() => { + database.close(); + process.exit(0); + }); + + setTimeout(() => process.exit(1), 10_000).unref(); +} + +process.once("SIGINT", () => shutdown("SIGINT")); +process.once("SIGTERM", () => shutdown("SIGTERM")); diff --git a/src/problem5/src/services/observability.service.ts b/src/problem5/src/services/observability.service.ts new file mode 100644 index 0000000000..b29a994daf --- /dev/null +++ b/src/problem5/src/services/observability.service.ts @@ -0,0 +1,53 @@ +import type { + AuditLogFilters, + TroubleLogFilters, + TroubleLogInput, +} from "../domain/observability"; +import { AppError } from "../errors"; +import { ObservabilityRepository } from "../repositories/observability.repository"; + +export class ObservabilityService { + public constructor( + private readonly repository: ObservabilityRepository, + ) {} + + public listAuditLogs(filters: AuditLogFilters) { + return this.repository.listAuditLogs(filters); + } + + public getAuditLog(id: number) { + const log = this.repository.findAuditLogById(id); + + if (!log) { + throw new AppError( + 404, + "AUDIT_LOG_NOT_FOUND", + "Audit log was not found", + ); + } + + return log; + } + + public recordTrouble(input: TroubleLogInput): void { + this.repository.writeTroubleLog(input); + } + + public listTroubleLogs(filters: TroubleLogFilters) { + return this.repository.listTroubleLogs(filters); + } + + public getTroubleLog(id: number) { + const log = this.repository.findTroubleLogById(id); + + if (!log) { + throw new AppError( + 404, + "TROUBLE_LOG_NOT_FOUND", + "Trouble log was not found", + ); + } + + return log; + } +} diff --git a/src/problem5/src/services/task.service.ts b/src/problem5/src/services/task.service.ts new file mode 100644 index 0000000000..7fb19fa638 --- /dev/null +++ b/src/problem5/src/services/task.service.ts @@ -0,0 +1,84 @@ +import { randomUUID } from "node:crypto"; +import type { + CreateTaskInput, + TaskFilters, + UpdateTaskInput, +} from "../domain/task"; +import { AppError } from "../errors"; +import { TaskRepository } from "../repositories/task.repository"; + +export class TaskService { + public constructor(private readonly repository: TaskRepository) {} + + public create( + input: CreateTaskInput, + traceId: string = randomUUID(), + ) { + return this.repository.create(input, traceId); + } + + public list(filters: TaskFilters) { + if ( + filters.dueAfter && + filters.dueBefore && + filters.dueAfter > filters.dueBefore + ) { + throw new AppError( + 400, + "VALIDATION_ERROR", + "dueAfter must be earlier than or equal to dueBefore", + ); + } + + return this.repository.list(filters); + } + + public get(id: string) { + const task = this.repository.findById(id); + + if (!task) { + throw new AppError( + 404, + "TASK_NOT_FOUND", + "Task was not found", + ); + } + + return task; + } + + public update( + id: string, + input: UpdateTaskInput, + traceId: string = randomUUID(), + ) { + const task = this.repository.update( + id, + input, + traceId, + ); + + if (!task) { + throw new AppError( + 404, + "TASK_NOT_FOUND", + "Task was not found", + ); + } + + return task; + } + + public delete( + id: string, + traceId: string = randomUUID(), + ): void { + if (!this.repository.delete(id, traceId)) { + throw new AppError( + 404, + "TASK_NOT_FOUND", + "Task was not found", + ); + } + } +} diff --git a/src/problem5/test/api.test.ts b/src/problem5/test/api.test.ts new file mode 100644 index 0000000000..0a3e17bdd9 --- /dev/null +++ b/src/problem5/test/api.test.ts @@ -0,0 +1,207 @@ +import assert from "node:assert/strict"; +import { mkdtempSync, rmSync } from "node:fs"; +import type { Server } from "node:http"; +import type { AddressInfo } from "node:net"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { after, before, test } from "node:test"; +import { createApp } from "../src/app"; + +const directory = mkdtempSync(join(tmpdir(), "problem5-api-")); +const databasePath = join(directory, "test.sqlite"); +const resources = createApp({ databasePath }); +let server: Server; +let baseUrl = ""; +let taskId = ""; + +before(async () => { + await new Promise((resolve) => { + server = resources.app.listen(0, "127.0.0.1", () => { + const address = server.address() as AddressInfo; + baseUrl = `http://127.0.0.1:${address.port}`; + resolve(); + }); + }); +}); + +after(async () => { + await new Promise((resolve, reject) => { + server.close((error?: Error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + }); + + resources.database.close(); + rmSync(directory, { recursive: true, force: true }); +}); + +async function json(response: Response): Promise { + return response.status === 204 ? null : response.json(); +} + +test("health endpoint", async () => { + const response = await fetch(`${baseUrl}/health`); + + assert.equal(response.status, 200); + assert.equal((await json(response)).status, "ok"); +}); + +test("create a task", async () => { + const response = await fetch(`${baseUrl}/api/v1/tasks`, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + title: "Write integration tests", + description: "Exercise every CRUD endpoint", + status: "TODO", + priority: "HIGH", + }), + }); + + assert.equal(response.status, 201); + + const body = await json(response); + taskId = body.data.id; + + assert.equal(body.data.title, "Write integration tests"); + assert.equal( + response.headers.get("location"), + `/api/v1/tasks/${taskId}`, + ); +}); + +test("list and filter tasks", async () => { + const response = await fetch( + `${baseUrl}/api/v1/tasks?status=TODO&priority=HIGH&search=integration`, + ); + const body = await json(response); + + assert.equal(response.status, 200); + assert.equal(body.meta.total, 1); + assert.equal(body.data[0].id, taskId); +}); + +test("get task details", async () => { + const response = await fetch( + `${baseUrl}/api/v1/tasks/${taskId}`, + ); + + assert.equal(response.status, 200); + assert.equal((await json(response)).data.id, taskId); +}); + +test("update task details", async () => { + const response = await fetch( + `${baseUrl}/api/v1/tasks/${taskId}`, + { + method: "PATCH", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + status: "DONE", + priority: "MEDIUM", + }), + }, + ); + + const body = await json(response); + + assert.equal(response.status, 200); + assert.equal(body.data.status, "DONE"); + assert.equal(body.data.version, 2); +}); + +test("invalid payload creates trouble log", async () => { + const response = await fetch(`${baseUrl}/api/v1/tasks`, { + method: "POST", + headers: { + "content-type": "application/json", + "x-request-id": "invalid-payload-test", + }, + body: JSON.stringify({ + title: "", + unexpected: true, + }), + }); + + const body = await json(response); + + assert.equal(response.status, 400); + assert.equal(body.error.code, "VALIDATION_ERROR"); + assert.equal(body.error.requestId, "invalid-payload-test"); + + const logsResponse = await fetch( + `${baseUrl}/api/v1/trouble-logs?requestId=invalid-payload-test`, + ); + const logsBody = await json(logsResponse); + + assert.equal(logsResponse.status, 200); + assert.equal(logsBody.meta.total, 1); + assert.equal(logsBody.data[0].errorCode, "VALIDATION_ERROR"); + assert.equal(logsBody.data[0].statusCode, 400); +}); + +test("unknown route creates trouble log", async () => { + const response = await fetch(`${baseUrl}/missing-route`, { + headers: { + "x-request-id": "missing-route-test", + }, + }); + + assert.equal(response.status, 404); + + const logsResponse = await fetch( + `${baseUrl}/api/v1/trouble-logs?requestId=missing-route-test`, + ); + const logsBody = await json(logsResponse); + + assert.equal(logsBody.meta.total, 1); + assert.equal(logsBody.data[0].errorCode, "ROUTE_NOT_FOUND"); +}); + +test("delete task and expose three audit records", async () => { + const deleted = await fetch( + `${baseUrl}/api/v1/tasks/${taskId}`, + { + method: "DELETE", + }, + ); + + assert.equal(deleted.status, 204); + + const missing = await fetch( + `${baseUrl}/api/v1/tasks/${taskId}`, + ); + + assert.equal(missing.status, 404); + assert.equal( + (await json(missing)).error.code, + "TASK_NOT_FOUND", + ); + + const auditResponse = await fetch( + `${baseUrl}/api/v1/audit-logs?taskId=${taskId}&limit=10`, + ); + const auditBody = await json(auditResponse); + + assert.equal(auditResponse.status, 200); + assert.equal(auditBody.meta.total, 3); + + const actions = auditBody.data + .map((item: { action: string }) => item.action) + .sort(); + + assert.deepEqual(actions, [ + "CREATE", + "DELETE", + "UPDATE", + ]); +}); diff --git a/src/problem5/test/core.test.ts b/src/problem5/test/core.test.ts new file mode 100644 index 0000000000..b9bec079ad --- /dev/null +++ b/src/problem5/test/core.test.ts @@ -0,0 +1,93 @@ +import assert from "node:assert/strict"; +import { test } from "node:test"; +import { Database } from "../src/database"; +import { ObservabilityRepository } from "../src/repositories/observability.repository"; +import { TaskRepository } from "../src/repositories/task.repository"; +import { ObservabilityService } from "../src/services/observability.service"; +import { TaskService } from "../src/services/task.service"; + +const taskFilters = { + sortBy: "createdAt" as const, + order: "desc" as const, + limit: 20, + offset: 0, +}; + +test("CRUD audit and trouble logs persist in SQLite", () => { + const database = new Database(":memory:"); + const taskRepository = new TaskRepository(database); + const observabilityRepository = + new ObservabilityRepository(database); + + const taskService = new TaskService(taskRepository); + const observabilityService = + new ObservabilityService(observabilityRepository); + + try { + const created = taskService.create( + { + title: "Build API", + description: "Persistence test", + status: "TODO", + priority: "HIGH", + dueDate: null, + }, + "trace-create", + ); + + const updated = taskService.update( + created.id, + { + status: "IN_PROGRESS", + }, + "trace-update", + ); + + assert.equal(updated.version, 2); + assert.equal(taskService.list(taskFilters).total, 1); + + taskService.delete(created.id, "trace-delete"); + + const auditLogs = observabilityService.listAuditLogs({ + taskId: created.id, + limit: 20, + offset: 0, + }); + + assert.equal(auditLogs.total, 3); + assert.equal(auditLogs.items[0]?.action, "DELETE"); + assert.equal(auditLogs.items[1]?.action, "UPDATE"); + assert.equal(auditLogs.items[2]?.action, "CREATE"); + + observabilityService.recordTrouble({ + requestId: "request-test", + method: "POST", + path: "/api/v1/tasks", + statusCode: 400, + errorCode: "VALIDATION_ERROR", + message: "title is required", + details: { + field: "title", + }, + durationMs: 3, + }); + + const troubleLogs = observabilityService.listTroubleLogs({ + requestId: "request-test", + limit: 20, + offset: 0, + }); + + assert.equal(troubleLogs.total, 1); + assert.equal( + troubleLogs.items[0]?.errorCode, + "VALIDATION_ERROR", + ); + assert.deepEqual( + troubleLogs.items[0]?.details, + { field: "title" }, + ); + } finally { + database.close(); + } +}); diff --git a/src/problem5/test/stress.ts b/src/problem5/test/stress.ts new file mode 100644 index 0000000000..dcc9826ee4 --- /dev/null +++ b/src/problem5/test/stress.ts @@ -0,0 +1,444 @@ +import assert from "node:assert/strict"; +import { mkdtempSync, rmSync } from "node:fs"; +import type { Server } from "node:http"; +import type { AddressInfo } from "node:net"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { createApp } from "../src/app"; + +interface CreatedTaskResponse { + data: { + id: string; + }; +} + +interface ListResponse { + meta: { + total: number; + }; +} + +function delay(milliseconds: number): Promise { + return new Promise((resolve) => { + setTimeout(resolve, milliseconds); + }); +} + +/** + * Retries only transport-level failures. HTTP error responses are returned + * normally and validated by the caller. + */ +async function fetchWithRetry( + url: string, + init: RequestInit, + maximumAttempts = 4, +): Promise { + let lastError: unknown; + + for ( + let attempt = 1; + attempt <= maximumAttempts; + attempt += 1 + ) { + try { + return await fetch(url, init); + } catch (error) { + lastError = error; + + if (attempt === maximumAttempts) { + break; + } + + await delay(25 * 2 ** (attempt - 1)); + } + } + + throw new Error( + `Transport failure after ${maximumAttempts} attempts: ${url}`, + { + cause: lastError, + }, + ); +} + +async function expectJson( + url: string, + init: RequestInit, + expectedStatus: number, +): Promise { + const response = await fetchWithRetry(url, init); + const text = await response.text(); + + if (response.status !== expectedStatus) { + throw new Error( + [ + `${init.method ?? "GET"} ${url}`, + `expected HTTP ${expectedStatus}`, + `received HTTP ${response.status}`, + `body=${text}`, + ].join("; "), + ); + } + + try { + return JSON.parse(text) as T; + } catch (error) { + throw new Error( + `Response is not valid JSON: ${init.method ?? "GET"} ${url}`, + { + cause: error, + }, + ); + } +} + +async function expectStatus( + url: string, + init: RequestInit, + expectedStatus: number, +): Promise { + const response = await fetchWithRetry(url, init); + + if (response.status !== expectedStatus) { + const body = await response.text(); + + throw new Error( + [ + `${init.method ?? "GET"} ${url}`, + `expected HTTP ${expectedStatus}`, + `received HTTP ${response.status}`, + `body=${body}`, + ].join("; "), + ); + } + + // Consume the body so the connection can be reused cleanly. + await response.arrayBuffer(); +} + +/** + * Runs bounded concurrency and waits for every worker before throwing. + * + * The old Promise.all implementation failed fast. Its finally block then + * closed the server while other requests were still in flight, producing + * secondary ECONNREFUSED errors that hid the original failure. + */ +async function mapWithConcurrency( + items: readonly T[], + concurrency: number, + operation: ( + item: T, + index: number, + ) => Promise, +): Promise { + const results = new Array(items.length); + const errors: Error[] = []; + let nextIndex = 0; + + async function worker(): Promise { + while (true) { + const index = nextIndex; + nextIndex += 1; + + if (index >= items.length) { + return; + } + + const item = items[index]; + + if (item === undefined) { + errors.push( + new Error(`Missing work item at index ${index}`), + ); + continue; + } + + try { + results[index] = await operation(item, index); + } catch (error) { + errors.push( + new Error( + `Stress operation failed at index ${index}`, + { + cause: error, + }, + ), + ); + } + } + } + + const workerCount = Math.min( + Math.max(1, concurrency), + items.length, + ); + + await Promise.all( + Array.from( + { length: workerCount }, + () => worker(), + ), + ); + + if (errors.length > 0) { + throw new AggregateError( + errors, + `${errors.length} stress operations failed`, + ); + } + + return results; +} + +async function waitUntilListening( + server: Server, +): Promise { + await new Promise((resolve, reject) => { + const onListening = (): void => { + server.off("error", onError); + resolve(); + }; + + const onError = (error: Error): void => { + server.off("listening", onListening); + reject(error); + }; + + server.once("listening", onListening); + server.once("error", onError); + }); +} + +async function closeServer( + server: Server, +): Promise { + await new Promise((resolve, reject) => { + server.close((error?: Error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + + server.closeIdleConnections(); + }); +} + +async function main(): Promise { + const directory = mkdtempSync( + join(tmpdir(), "problem5-stress-"), + ); + + const resources = createApp({ + databasePath: join(directory, "stress.sqlite"), + }); + + // A larger backlog helps on Windows when many clients connect quickly. + const server = resources.app.listen({ + port: 0, + host: "127.0.0.1", + backlog: 1_024, + }); + + try { + await waitUntilListening(server); + + const address = server.address(); + + if ( + address === null || + typeof address === "string" + ) { + throw new Error( + "Stress server did not expose a TCP address", + ); + } + + const { port } = address as AddressInfo; + const baseUrl = `http://127.0.0.1:${port}`; + const startedAt = Date.now(); + + // Confirm that the server is reachable before starting the load. + await expectJson<{ status: string }>( + `${baseUrl}/health`, + { + method: "GET", + }, + 200, + ); + + const createIndexes = Array.from( + { length: 250 }, + (_, index) => index, + ); + + const createdIds = await mapWithConcurrency( + createIndexes, + 25, + async (index) => { + const body = await expectJson( + `${baseUrl}/api/v1/tasks`, + { + method: "POST", + headers: { + "content-type": "application/json", + "x-request-id": `stress-create-${index}`, + }, + body: JSON.stringify({ + title: `Stress task ${index}`, + status: + index % 2 === 0 + ? "TODO" + : "IN_PROGRESS", + priority: + index % 3 === 0 + ? "HIGH" + : "MEDIUM", + }), + }, + 201, + ); + + return body.data.id; + }, + ); + + await mapWithConcurrency( + createdIds.slice(0, 100), + 20, + async (id, index) => { + await expectJson( + `${baseUrl}/api/v1/tasks/${id}`, + { + method: "PATCH", + headers: { + "content-type": "application/json", + "x-request-id": `stress-update-${index}`, + }, + body: JSON.stringify({ + status: "DONE", + }), + }, + 200, + ); + }, + ); + + await mapWithConcurrency( + createdIds.slice(0, 50), + 10, + async (id, index) => { + await expectStatus( + `${baseUrl}/api/v1/tasks/${id}`, + { + method: "DELETE", + headers: { + "x-request-id": `stress-delete-${index}`, + }, + }, + 204, + ); + }, + ); + + const invalidIndexes = Array.from( + { length: 50 }, + (_, index) => index, + ); + + await mapWithConcurrency( + invalidIndexes, + 20, + async (index) => { + await expectJson( + `${baseUrl}/api/v1/tasks`, + { + method: "POST", + headers: { + "content-type": "application/json", + "x-request-id": `stress-invalid-${index}`, + }, + body: JSON.stringify({ + title: "", + }), + }, + 400, + ); + }, + ); + + const auditBody = await expectJson( + `${baseUrl}/api/v1/audit-logs?limit=1`, + { + method: "GET", + }, + 200, + ); + + const troubleBody = await expectJson( + `${baseUrl}/api/v1/trouble-logs?errorCode=VALIDATION_ERROR&limit=1`, + { + method: "GET", + }, + 200, + ); + + assert.equal( + auditBody.meta.total, + 400, + "Expected 250 creates + 100 updates + 50 deletes", + ); + + assert.equal( + troubleBody.meta.total, + 50, + "Expected one trouble record for each invalid request", + ); + + assert.equal( + resources.observabilityRepository.countTroubleLogs(), + 50, + ); + + console.log("STRESS_TEST_PASS"); + console.log("creates=250"); + console.log("updates=100"); + console.log("deletes=50"); + console.log("auditRecords=400"); + console.log("troubleRecords=50"); + console.log("peakConcurrency=25"); + console.log(`elapsedMs=${Date.now() - startedAt}`); + } finally { + await closeServer(server); + resources.database.close(); + + rmSync(directory, { + recursive: true, + force: true, + }); + } +} + +main().catch((error: unknown) => { + if (error instanceof AggregateError) { + console.error(error.message); + + error.errors.forEach( + ( + childError: unknown, + index: number, + ) => { + console.error( + `[${index + 1}]`, + childError, + ); + }, + ); + } else { + console.error(error); + } + + process.exitCode = 1; +}); diff --git a/src/problem5/tsconfig.json b/src/problem5/tsconfig.json new file mode 100644 index 0000000000..ffc049b212 --- /dev/null +++ b/src/problem5/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "Node", + "rootDir": ".", + "outDir": "dist", + "strict": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "noEmitOnError": true, + "sourceMap": true + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} From c63ef24a161b9025563890c9df4c9e1079cffe01 Mon Sep 17 00:00:00 2001 From: Trong Do Date: Mon, 3 Aug 2026 23:20:50 +0700 Subject: [PATCH 3/3] [BE] Problem 6: Architecture --- src/problem6/README.md | 789 ++++++++++++++++++++ src/problem6/diagrams/score-update-flow.dot | 60 ++ src/problem6/diagrams/score-update-flow.mmd | 26 + src/problem6/diagrams/score-update-flow.png | Bin 0 -> 343543 bytes src/problem6/diagrams/score-update-flow.svg | 201 +++++ src/problem6/openapi.yaml | 204 +++++ 6 files changed, 1280 insertions(+) create mode 100644 src/problem6/README.md create mode 100644 src/problem6/diagrams/score-update-flow.dot create mode 100644 src/problem6/diagrams/score-update-flow.mmd create mode 100644 src/problem6/diagrams/score-update-flow.png create mode 100644 src/problem6/diagrams/score-update-flow.svg create mode 100644 src/problem6/openapi.yaml diff --git a/src/problem6/README.md b/src/problem6/README.md new file mode 100644 index 0000000000..e1f19f5496 --- /dev/null +++ b/src/problem6/README.md @@ -0,0 +1,789 @@ +# Problem 6 — Secure Real-Time Scoreboard Module + +## 1. Purpose + +This document specifies a backend module that: + +1. accepts authorised action-completion notifications; +2. increases the authenticated user's score; +3. prevents replayed or forged score updates; +4. returns the top 10 users; +5. pushes leaderboard changes to connected browsers in near real time. + +The specification is intended for a backend engineering team to implement. + +--- + +## 2. Critical security principle + +**The client must never be allowed to submit an arbitrary score or score +increment.** + +The browser may report that an action was completed, but the API service must +only apply a score change after validating evidence issued by a trusted +server-side component. + +Accepted evidence is one of the following: + +- a short-lived, signed action receipt issued by a trusted Action Service; or +- a server-to-server completion event authenticated with mTLS or a request + signature; or +- an authoritative action-completion record that the Scoreboard Module can + verify in a trusted database. + +A request such as this must not be supported: + +```json +{ + "userId": "another-user", + "score": 99999999, + "increment": 1000000 +} +``` + +The user identity comes from the authenticated access token, and the score +delta comes from server-side action rules. + +--- + +## 3. Scope + +### In scope + +- Submit an authorised action completion. +- Apply a server-controlled score increment. +- Make updates idempotent. +- Persist score history. +- Return the top 10 leaderboard. +- Broadcast live leaderboard updates. +- Store audit and trouble logs. +- Recover reliably from publish or cache failures. + +### Out of scope + +- The business logic that decides whether the underlying user action is + complete. +- User registration and login. +- UI design. +- Rewards, badges, seasons, tournaments, and score expiration. + +--- + +## 4. Proposed architecture + +### Main components + +| Component | Responsibility | +|---|---| +| HTTP Controller | Validates request shape and authentication context. | +| Completion Proof Validator | Verifies signed receipt, expiry, audience, user, action, and nonce. | +| Score Command Service | Applies idempotency and calculates the server-owned score delta. | +| Score Repository | Writes score event and current score in one database transaction. | +| Outbox Repository | Stores a reliable event in the same transaction. | +| Outbox Publisher | Publishes committed score changes asynchronously. | +| Leaderboard Projection | Updates the top-score read model or Redis sorted set. | +| Leaderboard Query Service | Returns the current top 10. | +| Realtime Hub | Sends leaderboard snapshots over Server-Sent Events. | +| Audit Log | Records successful score-changing operations. | +| Trouble Log | Records rejected requests and unexpected failures. | + +### Recommended infrastructure + +```text +PostgreSQL + Source of truth for score events, totals, outbox, audit, and trouble logs. + +Redis + Optional fast leaderboard projection and pub/sub transport. + +SSE + Recommended for browser live updates because the data flow is server-to-client. +``` + +The module can initially run as one ExpressJS application. The internal +boundaries should remain explicit so the publisher or realtime component can be +split into separate processes later. + +--- + +## 5. Execution flow + +The rendered flow is available at: + +```text +diagrams/score-update-flow.svg +diagrams/score-update-flow.png +``` + +Mermaid source: + +```mermaid +sequenceDiagram + autonumber + participant UI as Browser + participant AS as Trusted Action Service + participant API as API Service + participant DB as PostgreSQL + participant OW as Outbox Worker + participant LB as Leaderboard Projection + participant RT as SSE Hub + + UI->>AS: Complete action + AS-->>UI: Signed completion receipt + UI->>API: POST /api/v1/score-events + API->>API: Authenticate user + API->>API: Verify signature, exp, aud, sub and nonce + API->>API: Resolve score delta from server rules + API->>DB: BEGIN transaction + API->>DB: Insert score_event with unique receipt jti + API->>DB: Update user_score + API->>DB: Insert outbox_event and audit_log + API->>DB: COMMIT + API-->>UI: Updated score + OW->>DB: Read unpublished outbox event + OW->>LB: Update leaderboard projection + OW->>RT: Publish leaderboard.updated + RT-->>UI: SSE top-10 snapshot +``` + +### Detailed processing rules + +1. The user completes an action. +2. A trusted Action Service produces a signed, short-lived completion receipt. +3. The browser calls the score endpoint with its access token, receipt, and + idempotency key. +4. The API derives `userId` from the access token. +5. The API validates the receipt signature and claims. +6. The API verifies that the receipt user matches the authenticated user. +7. The API rejects an expired, reused, malformed, or unauthorised receipt. +8. The API resolves the score delta from server-side configuration. +9. A database transaction inserts the immutable score event. +10. The transaction updates the user's current score. +11. The transaction inserts an outbox event and audit record. +12. The API commits and returns the new score. +13. A background publisher updates the leaderboard projection. +14. The realtime hub sends the new top 10 to connected clients. + +--- + +## 6. API specification + +Base path: + +```text +/api/v1 +``` + +### 6.1 Submit an action completion + +```http +POST /api/v1/score-events +Authorization: Bearer +Idempotency-Key: +Content-Type: application/json +``` + +Request: + +```json +{ + "actionReceipt": "" +} +``` + +The receipt should contain claims equivalent to: + +```json +{ + "iss": "trusted-action-service", + "aud": "scoreboard-api", + "sub": "user-id", + "jti": "unique-action-instance-id", + "actionType": "DAILY_CHALLENGE", + "iat": 1785770000, + "exp": 1785770060 +} +``` + +The receipt must not contain a client-controlled numeric score delta. The API +maps `actionType` to a score rule. + +Successful response: + +```http +200 OK +``` + +```json +{ + "data": { + "eventId": "a7c5e79c-2a7c-47d2-86e8-715151210402", + "userId": "0be81df1-d3e0-41c0-8693-6fdf988249d0", + "appliedDelta": 20, + "score": 1240, + "leaderboardVersion": 381, + "applied": true + } +} +``` + +Repeated request with the same valid idempotency key and same payload: + +```http +200 OK +``` + +The API returns the original response with: + +```json +{ + "applied": false +} +``` + +The score must not be increased again. + +Errors: + +| Status | Code | Meaning | +|---:|---|---| +| 400 | `VALIDATION_ERROR` | Invalid request shape. | +| 401 | `UNAUTHENTICATED` | Missing or invalid access token. | +| 403 | `INVALID_ACTION_RECEIPT` | Receipt invalid or does not belong to the user. | +| 409 | `IDEMPOTENCY_CONFLICT` | Same key reused with different request content. | +| 409 | `RECEIPT_ALREADY_USED` | Receipt `jti` already consumed by a different request. | +| 429 | `RATE_LIMITED` | Request rate exceeded. | +| 500 | `INTERNAL_SERVER_ERROR` | Unexpected error. | +| 503 | `DEPENDENCY_UNAVAILABLE` | Required dependency temporarily unavailable. | + +### 6.2 Get top leaderboard + +```http +GET /api/v1/leaderboard?limit=10 +``` + +Rules: + +- Default and maximum limit is 10. +- Public user profiles must expose only approved display data. +- Ties use deterministic secondary ordering: + `score DESC, reached_score_at ASC, user_id ASC`. + +Response: + +```json +{ + "data": { + "version": 381, + "generatedAt": "2026-08-03T16:00:00.000Z", + "entries": [ + { + "rank": 1, + "userId": "user-1", + "displayName": "Player One", + "score": 9820 + } + ] + } +} +``` + +### 6.3 Subscribe to live leaderboard updates + +```http +GET /api/v1/leaderboard/stream +Accept: text/event-stream +Last-Event-ID: 380 +``` + +Example SSE event: + +```text +id: 381 +event: leaderboard.updated +data: {"version":381,"entries":[{"rank":1,"userId":"user-1","score":9820}]} +``` + +Rules: + +- Send the current full top-10 snapshot immediately after connection. +- Send heartbeat comments every 15–30 seconds. +- Support reconnect using `Last-Event-ID`. +- If a client misses events, send the newest full snapshot rather than replaying + every historical ranking. +- Apply connection limits per user and IP. + +--- + +## 7. Data model + +### `user_scores` + +Stores the current score for fast reads. + +```sql +CREATE TABLE user_scores ( + user_id UUID PRIMARY KEY, + score BIGINT NOT NULL DEFAULT 0 CHECK (score >= 0), + version BIGINT NOT NULL DEFAULT 0, + reached_score_at TIMESTAMPTZ NOT NULL, + updated_at TIMESTAMPTZ NOT NULL +); + +CREATE INDEX idx_user_scores_leaderboard + ON user_scores(score DESC, reached_score_at ASC, user_id ASC); +``` + +### `score_events` + +Immutable source of score changes. + +```sql +CREATE TABLE score_events ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL, + receipt_jti TEXT NOT NULL UNIQUE, + idempotency_key TEXT NOT NULL, + request_hash TEXT NOT NULL, + action_type TEXT NOT NULL, + score_delta BIGINT NOT NULL CHECK (score_delta > 0), + score_after BIGINT NOT NULL, + receipt_hash TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL, + + UNIQUE(user_id, idempotency_key) +); +``` + +### `outbox_events` + +Provides reliable event publication. + +```sql +CREATE TABLE outbox_events ( + id UUID PRIMARY KEY, + aggregate_type TEXT NOT NULL, + aggregate_id TEXT NOT NULL, + event_type TEXT NOT NULL, + payload JSONB NOT NULL, + attempts INTEGER NOT NULL DEFAULT 0, + available_at TIMESTAMPTZ NOT NULL, + published_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL +); +``` + +### `audit_logs` + +Records successful security-sensitive changes. + +Suggested fields: + +```text +id +trace_id +request_id +user_id +action +score_event_id +receipt_jti +input_hash +result_hash +created_at +``` + +Do not store the raw access token or raw signed receipt. + +### `trouble_logs` + +Records rejected and failed requests. + +Suggested fields: + +```text +id +trace_id +request_id +user_id +method +path +status_code +error_code +message +details_json +duration_ms +created_at +``` + +Sensitive receipt contents and secrets must be redacted. + +--- + +## 8. Transaction and consistency rules + +The following operations must occur in one database transaction: + +1. insert `score_events`; +2. update `user_scores`; +3. insert `outbox_events`; +4. insert `audit_logs`. + +If any operation fails, roll back all four. + +The database is the source of truth. Redis is a disposable projection. + +### Idempotency + +The implementation must enforce both: + +```text +UNIQUE(receipt_jti) +UNIQUE(user_id, idempotency_key) +``` + +The stored `request_hash` prevents reuse of the same idempotency key with a +different request. + +### Concurrency + +Lock or atomically update the user's score row: + +```sql +UPDATE user_scores +SET + score = score + :delta, + version = version + 1, + reached_score_at = NOW(), + updated_at = NOW() +WHERE user_id = :user_id +RETURNING score, version; +``` + +If a row may not exist, use `INSERT ... ON CONFLICT ... DO UPDATE`. + +--- + +## 9. Leaderboard projection + +### Baseline implementation + +Read the top 10 directly from PostgreSQL using the leaderboard index. + +Suitable when: + +- traffic is moderate; +- leaderboard updates are not extremely frequent; +- operational simplicity is preferred. + +### Scalable implementation + +Use a Redis sorted set: + +```text +Key: leaderboard:global +Member: userId +Score: current score +``` + +The outbox worker updates Redis after the database transaction commits. + +Tie-breaking cannot rely only on a Redis numeric score without additional +encoding. Recommended options: + +1. retrieve more than 10 candidates from Redis and apply deterministic ordering + from PostgreSQL; or +2. maintain a dedicated leaderboard projection table with explicit rank fields. + +A periodic reconciliation job must rebuild or verify the projection from +PostgreSQL. + +--- + +## 10. Security requirements + +### Authentication + +- Require a valid user access token. +- Derive the user ID from the verified token. +- Never trust `userId` from request JSON. + +### Action receipt validation + +Validate: + +```text +signature +issuer +audience +subject/user +action type +issued-at time +expiry time +unique jti/nonce +supported signing key id +``` + +Signing keys must be rotated and retrieved from a trusted key set. + +### Replay prevention + +- Store every consumed receipt `jti`. +- Apply a unique database constraint. +- Keep receipt expiry short. +- Reject duplicated receipt use even if it arrives concurrently. + +### Score integrity + +- Score rules are configured server-side. +- The receipt selects an action type, not a numeric score. +- Set a maximum delta per action. +- Set daily and hourly score velocity limits. +- Flag abnormal patterns for review. + +### Transport and infrastructure + +- TLS is mandatory. +- Use mTLS or signed requests for server-to-server calls. +- Apply rate limits by user, IP, and action type. +- Protect private log endpoints with administrator permissions. +- Redact tokens, receipts, keys, and personal data from logs. + +--- + +## 11. Realtime delivery + +SSE is preferred because leaderboard updates are one-way. + +The realtime hub may run in-process for the initial version. For multiple API +instances, use Redis Pub/Sub, Redis Streams, NATS, or Kafka so every instance +receives the update. + +The event payload should contain the full top-10 snapshot because: + +- only 10 entries are required; +- reconnect logic is simpler; +- clients do not need to reproduce ranking rules; +- missed intermediate events do not matter. + +Target: + +```text +Committed score to browser update: P95 < 1 second +``` + +--- + +## 12. Failure handling + +| Failure | Required behaviour | +|---|---| +| Receipt verification fails | Return 403 and write trouble log. | +| Duplicate receipt | Return deterministic duplicate response; do not increment. | +| Database transaction fails | Roll back and return 500/503. | +| Outbox publish fails | Keep event unpublished and retry with backoff. | +| Redis unavailable | Continue writing PostgreSQL; query PostgreSQL fallback. | +| SSE client disconnects | Clean up connection and allow reconnect. | +| Malformed request | Return 400 with request ID and write trouble log. | +| Unexpected exception | Return generic 500; store internal details in trouble log. | + +Outbox retry policy: + +```text +exponential backoff +maximum attempt threshold +dead-letter state after repeated failures +operator alert +manual replay capability +``` + +--- + +## 13. Observability + +### Structured logs + +Every request should include: + +```text +timestamp +level +service +request_id +trace_id +user_id +route +method +status_code +duration_ms +error_code +``` + +### Metrics + +```text +score_updates_total{result} +score_update_duration_ms +receipt_validation_failures_total{reason} +duplicate_receipts_total +idempotency_conflicts_total +leaderboard_query_duration_ms +leaderboard_publish_lag_ms +outbox_pending_total +outbox_publish_failures_total +sse_connections_active +sse_delivery_failures_total +``` + +### Alerts + +- sustained receipt-validation failures; +- unusual score velocity; +- outbox backlog above threshold; +- leaderboard projection drift; +- elevated 5xx rate; +- SSE delivery lag above target. + +--- + +## 14. Non-functional requirements + +| Area | Target | +|---|---| +| Score update response | P95 < 200 ms excluding external proof lookup. | +| Leaderboard query | P95 < 100 ms. | +| Live update latency | P95 < 1 second after commit. | +| Availability | 99.9% initial target. | +| Durability | No committed score event may be lost. | +| Consistency | Score event and total updated atomically. | +| Security | No client-controlled score delta. | +| Auditability | Every accepted update traceable to one receipt and request. | + +--- + +## 15. Test plan + +### Unit tests + +- receipt claim validation; +- action-to-delta mapping; +- idempotency hash comparison; +- score bounds; +- ranking tie-break rules; +- error mapping and redaction. + +### Integration tests + +- valid receipt increases score once; +- duplicate receipt does not increase score; +- same idempotency key returns original response; +- conflicting idempotency payload returns 409; +- expired or wrong-user receipt returns 403; +- transaction rollback leaves no partial data; +- outbox event exists after successful update; +- audit record exists after successful update; +- trouble record exists after rejected update; +- leaderboard returns deterministic top 10. + +### Concurrency tests + +- hundreds of simultaneous duplicate receipt submissions; +- simultaneous valid actions for the same user; +- simultaneous valid actions for different users; +- no lost updates; +- exactly one score event per receipt. + +### Realtime tests + +- initial snapshot on connect; +- update delivered after commit; +- reconnect using `Last-Event-ID`; +- multiple API instances receive the same event; +- disconnected clients are cleaned up. + +### Security tests + +- forged receipt; +- altered receipt payload; +- wrong audience or issuer; +- expired receipt; +- replayed receipt; +- another user's receipt; +- arbitrary score and user fields injected into JSON; +- rate-limit enforcement. + +--- + +## 16. Acceptance criteria + +The module is ready when: + +1. a valid authorised completion increases the correct user's score once; +2. a forged or replayed request cannot increase a score; +3. the top 10 endpoint returns deterministic rankings; +4. connected clients receive a new snapshot after a committed score update; +5. database failure cannot leave partial score state; +6. publish failure cannot lose the committed update; +7. accepted changes produce audit records; +8. rejected or failed requests produce trouble records; +9. integration, concurrency, and security tests pass; +10. secrets and raw credentials never appear in logs. + +--- + +## 17. Additional improvement comments + +### 17.1 Use server-to-server completion events where possible + +The strongest design is for the trusted Action Service to call the Scoreboard +Module directly. A browser-carried signed receipt is acceptable, but direct +server communication reduces client manipulation opportunities. + +### 17.2 Consider event sourcing only when justified + +`score_events` already provides an immutable ledger. Full event sourcing is not +required for the initial implementation. Keep `user_scores` as a transactional +projection and periodically reconcile it against the event ledger. + +### 17.3 Add seasons without rewriting the module + +Introduce a `leaderboard_id` or `season_id` in `score_events` and `user_scores` +before supporting multiple leaderboards. Do not hard-code one global board into +all repository interfaces. + +### 17.4 Add abuse detection + +Record score velocity and action diversity. Generate a security review event +when a user exceeds plausible thresholds instead of silently accepting every +individually valid receipt. + +### 17.5 Protect administrative log APIs + +Audit and trouble logs may contain operational or personal data. Expose them +only through authenticated administrator endpoints with pagination, retention, +and redaction policies. + +### 17.6 Define score limits + +Use `BIGINT`, reject arithmetic overflow, and define a maximum score. Never rely +on JavaScript `number` for unbounded integer values without explicit safe-range +checks. + +### 17.7 Prefer full snapshots for top 10 updates + +Sending the complete top 10 on each change is simpler and safer than sending +incremental rank movements. The payload is small and clients remain stateless. + +--- + +## 18. Suggested implementation order + +1. Database schema and migrations. +2. Receipt validator interface and test signing keys. +3. Transactional score command service. +4. Idempotency and replay constraints. +5. Leaderboard query endpoint. +6. Outbox worker. +7. SSE endpoint. +8. Audit and trouble logs. +9. Reconciliation job. +10. Load, concurrency, and security tests. diff --git a/src/problem6/diagrams/score-update-flow.dot b/src/problem6/diagrams/score-update-flow.dot new file mode 100644 index 0000000000..e7096f2841 --- /dev/null +++ b/src/problem6/diagrams/score-update-flow.dot @@ -0,0 +1,60 @@ +digraph ScoreboardFlow { + graph [ + rankdir=LR, + bgcolor="white", + pad="0.3", + nodesep="0.45", + ranksep="0.7", + fontname="Arial", + fontsize=18, + label="Secure Real-Time Scoreboard — Execution Flow", + labelloc="t" + ]; + + node [ + shape=box, + style="rounded,filled", + fillcolor="#F7F9FC", + color="#40566F", + fontname="Arial", + fontsize=11, + margin="0.16,0.10" + ]; + + edge [ + color="#40566F", + fontname="Arial", + fontsize=9, + arrowsize=0.75 + ]; + + browser [label="Browser\nAuthenticated user"]; + action [label="Trusted Action Service\nIssues signed receipt"]; + api [label="API Controller\nPOST /score-events"]; + auth [label="Auth + Receipt Validator\nSignature • exp • aud • sub • jti"]; + command [label="Score Command Service\nServer-owned action → delta"]; + tx [label="PostgreSQL Transaction\n1. score_event\n2. user_score\n3. outbox\n4. audit"]; + response [label="Return updated score\nIdempotent response"]; + outbox [label="Outbox Worker\nRetry until published"]; + projection [label="Leaderboard Projection\nPostgreSQL or Redis"]; + sse [label="SSE Hub\nleaderboard.updated"]; + top10 [label="Browser Scoreboard\nLive top 10"]; + trouble [label="Trouble Log\nRejected or failed request", fillcolor="#FFF4F2", color="#9B3D32"]; + + browser -> action [label="1. Complete action"]; + action -> browser [label="2. Signed receipt"]; + browser -> api [label="3. Bearer token + receipt\n+ Idempotency-Key"]; + api -> auth [label="4. Validate"]; + auth -> command [label="5. Authorised claims"]; + command -> tx [label="6. Apply once"]; + tx -> response [label="7. Commit"]; + response -> browser [label="8. New score"]; + tx -> outbox [label="9. Unpublished event"]; + outbox -> projection [label="10. Update top scores"]; + projection -> sse [label="11. Publish snapshot"]; + sse -> top10 [label="12. Live update"]; + browser -> top10 [style=invis]; + + auth -> trouble [label="Invalid / replay / expired", color="#9B3D32", fontcolor="#9B3D32"]; + tx -> trouble [label="Failure", color="#9B3D32", fontcolor="#9B3D32"]; +} diff --git a/src/problem6/diagrams/score-update-flow.mmd b/src/problem6/diagrams/score-update-flow.mmd new file mode 100644 index 0000000000..c6af69c2e2 --- /dev/null +++ b/src/problem6/diagrams/score-update-flow.mmd @@ -0,0 +1,26 @@ +sequenceDiagram + autonumber + participant UI as Browser + participant AS as Trusted Action Service + participant API as API Service + participant DB as PostgreSQL + participant OW as Outbox Worker + participant LB as Leaderboard Projection + participant RT as SSE Hub + + UI->>AS: Complete action + AS-->>UI: Signed completion receipt + UI->>API: POST /api/v1/score-events + API->>API: Authenticate user + API->>API: Verify signature, expiry, audience, user and nonce + API->>API: Resolve score delta from server rules + API->>DB: BEGIN transaction + API->>DB: Insert score event with unique receipt jti + API->>DB: Update current user score + API->>DB: Insert outbox event and audit log + API->>DB: COMMIT + API-->>UI: Return updated score + OW->>DB: Read unpublished outbox event + OW->>LB: Update leaderboard projection + OW->>RT: Publish leaderboard.updated + RT-->>UI: SSE top-10 snapshot diff --git a/src/problem6/diagrams/score-update-flow.png b/src/problem6/diagrams/score-update-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..2ec6bb6d17f06d999dfab0e931e926684023aa3e GIT binary patch literal 343543 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 !zr^tUyQ#t1$ZVVO2>7q@YG;CfU%x)ta;^29 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 z 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�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�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

h+pM`;cO6n4oc-g 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%0D(csbRfNjl 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

`$cs(yN0}h>+#D};FTDA~0)`B(f`Rdxr`ar|4 z(XS79Gy4dxGf@Z{BjhZ_TO(GxLyivSiW`!UggyX%`gPiVO@W#O*dRSI+UFUEJ6~(G zp8`astEbnn+C7~{z;+h0$yAP#ZMqOOHB#)|WHDO0Y15|u#;0_yICtC4P!$3No`sC1 z1HE;~Pp^flcfTF?W}3G0iOSa6(4+b~Lr64+20QZjEAyi4Hc57^kY%hs@ilt>m)Nv` z`RP|ry|oVh9=WvI@gT3cZwKE9S!wV6L~?*g zz0Lgv%NBr)H-xGh8A;boGudRL)F`mhnRnMK3_MnLnorauac2e|Bl;Bl!t18z3etj~ z^ne#u$j$$y z9MRB!d=G7BBU62#MrF1xbH|K*J)$qy&taU4Ts>u>@*P}x4SQ}w>6N7l8bAP zY{UAM*{@O}FK+!c@0gRMHB3hD8e2YoEI-$V_Q1n|aWQ%!%q>37R(yw;O#9)mE9tJvvvFaS!V_)N&~BDT6B~#C%*^#RC8U ziuS9H7drz>2`&#u+Lz%S-TSqwGMcjNEpAEnh;nf}kPiVfo+>MvV{f+(P1(cq+>hAT zG=?mhC*?SC{2nb|^)5Oy?kx!G((Jfn%MTQ}W`Uc6b+F0Qg&MQ&18MWASaR?)yA&E| zmbwvNJrWrL?OseF(G0V^;MH|V*Yb@r9$|vv?b=eB93baq)HpUL07N_JXOpK-4|fy> zN*1$BK0d3Kga7 zTvi=aXm+7cA6-=pLPfn_$lEi0J9vL0Z@1!)!F$sBV=sOmy=V5{cjBG*|23&qNTKkq hzcc@LhLQH^Yc=Th`@XMS?S_1fKTJGy@4%_3-vFVsM?nAp literal 0 HcmV?d00001 diff --git a/src/problem6/diagrams/score-update-flow.svg b/src/problem6/diagrams/score-update-flow.svg new file mode 100644 index 0000000000..ec116c3209 --- /dev/null +++ b/src/problem6/diagrams/score-update-flow.svg @@ -0,0 +1,201 @@ + + + + + + +ScoreboardFlow + +Secure Real-Time Scoreboard — Execution Flow + + +browser + +Browser +Authenticated user + + + +action + +Trusted Action Service +Issues signed receipt + + + +browser->action + + +1. Complete action + + + +api + +API Controller +POST /score-events + + + +browser->api + + +3. Bearer token + receipt ++ Idempotency-Key + + + +top10 + +Browser Scoreboard +Live top 10 + + + + +action->browser + + +2. Signed receipt + + + +auth + +Auth + Receipt Validator +Signature • exp • aud • sub • jti + + + +api->auth + + +4. Validate + + + +command + +Score Command Service +Server-owned action → delta + + + +auth->command + + +5. Authorised claims + + + +trouble + +Trouble Log +Rejected or failed request + + + +auth->trouble + + +Invalid / replay / expired + + + +tx + +PostgreSQL Transaction +1. score_event +2. user_score +3. outbox +4. audit + + + +command->tx + + +6. Apply once + + + +response + +Return updated score +Idempotent response + + + +tx->response + + +7. Commit + + + +outbox + +Outbox Worker +Retry until published + + + +tx->outbox + + +9. Unpublished event + + + +tx->trouble + + +Failure + + + +response->browser + + +8. New score + + + +projection + +Leaderboard Projection +PostgreSQL or Redis + + + +outbox->projection + + +10. Update top scores + + + +sse + +SSE Hub +leaderboard.updated + + + +projection->sse + + +11. Publish snapshot + + + +sse->top10 + + +12. Live update + + + diff --git a/src/problem6/openapi.yaml b/src/problem6/openapi.yaml new file mode 100644 index 0000000000..18ecb45bea --- /dev/null +++ b/src/problem6/openapi.yaml @@ -0,0 +1,204 @@ +openapi: 3.1.0 +info: + title: Secure Real-Time Scoreboard API + version: 1.0.0 + description: API contract proposed by the Problem 6 architecture specification. +servers: + - url: /api/v1 +paths: + /score-events: + post: + summary: Apply one authorised action completion + operationId: createScoreEvent + security: + - bearerAuth: [] + parameters: + - in: header + name: Idempotency-Key + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + type: object + additionalProperties: false + required: + - actionReceipt + properties: + actionReceipt: + type: string + minLength: 1 + responses: + "200": + description: Score applied or an idempotent prior response returned + content: + application/json: + schema: + $ref: "#/components/schemas/ScoreEventResponse" + "400": + $ref: "#/components/responses/Error" + "401": + $ref: "#/components/responses/Error" + "403": + $ref: "#/components/responses/Error" + "409": + $ref: "#/components/responses/Error" + "429": + $ref: "#/components/responses/Error" + "500": + $ref: "#/components/responses/Error" + "503": + $ref: "#/components/responses/Error" + + /leaderboard: + get: + summary: Return the current top 10 + operationId: getLeaderboard + parameters: + - in: query + name: limit + schema: + type: integer + minimum: 1 + maximum: 10 + default: 10 + responses: + "200": + description: Current leaderboard snapshot + content: + application/json: + schema: + $ref: "#/components/schemas/LeaderboardResponse" + + /leaderboard/stream: + get: + summary: Subscribe to live leaderboard snapshots over SSE + operationId: streamLeaderboard + parameters: + - in: header + name: Last-Event-ID + required: false + schema: + type: string + responses: + "200": + description: Server-Sent Events stream + content: + text/event-stream: + schema: + type: string + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + + schemas: + ScoreEventResponse: + type: object + required: + - data + properties: + data: + type: object + required: + - eventId + - userId + - appliedDelta + - score + - leaderboardVersion + - applied + properties: + eventId: + type: string + format: uuid + userId: + type: string + format: uuid + appliedDelta: + type: integer + format: int64 + score: + type: integer + format: int64 + leaderboardVersion: + type: integer + format: int64 + applied: + type: boolean + + LeaderboardEntry: + type: object + required: + - rank + - userId + - displayName + - score + properties: + rank: + type: integer + minimum: 1 + userId: + type: string + displayName: + type: string + score: + type: integer + format: int64 + + LeaderboardResponse: + type: object + required: + - data + properties: + data: + type: object + required: + - version + - generatedAt + - entries + properties: + version: + type: integer + format: int64 + generatedAt: + type: string + format: date-time + entries: + type: array + maxItems: 10 + items: + $ref: "#/components/schemas/LeaderboardEntry" + + ErrorResponse: + type: object + required: + - error + properties: + error: + type: object + required: + - code + - message + - requestId + properties: + code: + type: string + message: + type: string + requestId: + type: string + + responses: + Error: + description: Error response + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse"