7154a0a49c
Stand up the WebSocket live-broadcast server inside the Processor process: - src/live/server.ts: createLiveServer factory with start/stop lifecycle, per-connection LiveConnection type, sendOutbound helper with back-pressure guard, 30s frame-level heartbeat via ws ping/pong, pluggable onMessage handler (stub returns error/not-implemented until 1.5.2/1.5.3). - src/live/protocol.ts: zod schemas for inbound subscribe/unsubscribe messages, all outbound types (subscribed/unsubscribed/position/error), WsCloseCodes. - src/shared/types.ts: extracted Metrics interface so src/live/ can import it without crossing the enforced src/live/ ↔ src/core/ ESLint boundary. - src/core/types.ts: re-exports Metrics from shared/types to keep Phase 1 call sites unchanged. - src/config/load.ts: LIVE_WS_PORT, LIVE_WS_HOST, LIVE_WS_PING_INTERVAL_MS, LIVE_WS_DRAIN_TIMEOUT_MS, LIVE_WS_BACKPRESSURE_THRESHOLD_BYTES, DIRECTUS_BASE_URL, DIRECTUS_AUTH_TIMEOUT_MS, DIRECTUS_AUTHZ_TIMEOUT_MS, LIVE_BROADCAST_GROUP_PREFIX, LIVE_BROADCAST_BATCH_SIZE, LIVE_BROADCAST_BATCH_BLOCK_MS, LIVE_DEVICE_EVENT_REFRESH_MS. - src/observability/metrics.ts: Phase 1.5 metrics inventory (connections, inbound/outbound counters, auth/authz histograms, subscription gauge, broadcast counters + lag histogram, snapshot histograms, device-event map). - src/main.ts: wires the live server alongside the durable-write consumer; shutdown order: live server → consumer → metrics → Redis → Postgres. - eslint.config.js: import/no-restricted-paths zones for src/live/ ↔ src/core/. - test/live-server.test.ts: 7 unit tests covering connect, ping, protocol violation, valid message dispatch, connections gauge, and stop() drain.
46 lines
1.3 KiB
JSON
46 lines
1.3 KiB
JSON
{
|
|
"name": "processor",
|
|
"version": "0.1.0",
|
|
"description": "Worker service that consumes Position records from Redis Streams and writes durable state to Postgres/TimescaleDB",
|
|
"type": "module",
|
|
"engines": {
|
|
"node": ">=22"
|
|
},
|
|
"scripts": {
|
|
"build": "tsc --project tsconfig.json && node scripts/copy-assets.mjs",
|
|
"dev": "tsx watch src/main.ts",
|
|
"start": "node dist/main.js",
|
|
"test": "vitest run",
|
|
"test:watch": "vitest",
|
|
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
"lint": "eslint .",
|
|
"format": "prettier --write .",
|
|
"typecheck": "tsc --noEmit"
|
|
},
|
|
"dependencies": {
|
|
"ioredis": "^5.3.2",
|
|
"pg": "^8.13.0",
|
|
"pino": "^9.5.0",
|
|
"prom-client": "^15.1.3",
|
|
"ws": "^8.20.0",
|
|
"zod": "^3.23.8"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^22.10.0",
|
|
"@types/pg": "^8.11.10",
|
|
"@types/ws": "^8.18.1",
|
|
"@typescript-eslint/eslint-plugin": "^8.19.0",
|
|
"@typescript-eslint/parser": "^8.19.0",
|
|
"@vitest/coverage-v8": "^2.1.8",
|
|
"eslint": "^9.17.0",
|
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
"eslint-plugin-import": "^2.31.0",
|
|
"pino-pretty": "^13.0.0",
|
|
"prettier": "^3.4.2",
|
|
"testcontainers": "^11.14.0",
|
|
"tsx": "^4.19.2",
|
|
"typescript": "^5.7.2",
|
|
"vitest": "^2.1.8"
|
|
}
|
|
}
|