build(ts): day 2 — shared/types.ts + server.ts rename (no behavior
change)
Creates the wire-protocol contract every route and every client
component will import from. Renames server.js → server.ts as a pure
rename (zero bytes of logic changed) so the entry point becomes the
first file tsc type-checks against the real compilerOptions.
shared/types.ts — what's in it and why
- ApiResponse<T> envelope: (ApiOk<T> & T) | ApiErr. Every route
returns one of these; client code narrows on `r.success`.
- One typed "Ok" shape per endpoint, keyed by the actual res.json()
call in the current handler. Walked every src/routes/*.js file
and transcribed the literal keys: hpi, soap, note, hospitalCourse,
review, refined, shortened, questions, narrative+summary, etc.
No inventive renaming — wire stays identical, only the types are
new.
- Critical mismatches the types now prevent at compile time:
/api/refine returns `refined` (not `content` — a past bug)
/api/sick-visit/note (not /api/generate-sick-visit — past bug)
/api/generate-hospital-course returns `hospitalCourse` (not
`narrative` — past bug)
All three were caught and fixed earlier in Playwright; with the
shared types they become compile errors for any future regression.
server.ts
- Pure rename via `git mv`. Body unchanged.
- Compiled dist/server.js diffs against the original server.js by
two lines (TypeScript prepends `"use strict"` and the CommonJS
export marker). No semantic drift.
tsconfig.json tweak
- Include list adds server.ts alongside server.js so tsc doesn't
silently skip the entry point during the intermediate state
where `.js` entries might reappear.
- baseUrl removed (deprecated in TS 6); paths now uses './shared/*'.
package.json
- main: dist/server.js (post-compile entry)
- start: node dist/server.js
- prebuild: rm -rf dist (clean emit every time)
- dev: ts-node-dev for fast TS-aware reloads
The Dockerfile is still unchanged. The deployed prod and e2e
containers still run their baked-in server.js from the previous
image — this migration day has no effect on either until the final
rebuild at the end of day 7.
Next: day 3 renames the 29 route files one-by-one, each adding the
ApiResponse<T> type parameter to its res.json() calls.
This commit is contained in:
parent
b89d08e886
commit
a2fe1b38d1
4 changed files with 238 additions and 2 deletions
|
|
@ -2,9 +2,10 @@
|
|||
"name": "pediatric-ai-scribe",
|
||||
"version": "6.21.0",
|
||||
"description": "AI-powered pediatric clinical documentation platform",
|
||||
"main": "server.js",
|
||||
"main": "dist/server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"start": "node dist/server.js",
|
||||
"prebuild": "rm -rf dist",
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "ts-node-dev --respawn --transpile-only server.ts",
|
||||
|
|
|
|||
234
shared/types.ts
Normal file
234
shared/types.ts
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
// ============================================================
|
||||
// SHARED TYPES — consumed by both server (src/routes/*.ts) and
|
||||
// client (client/src/*). A response-shape change here breaks the
|
||||
// build on both sides until they agree.
|
||||
//
|
||||
// This is the single most important file in the TypeScript
|
||||
// migration. Three of the bugs we hit before this point were
|
||||
// response-shape mismatches (refine returned `content` vs
|
||||
// `refined`, sick-visit endpoint path mismatch, hospital-course
|
||||
// key mismatch). Typing the wire protocol makes them compile-time
|
||||
// errors.
|
||||
//
|
||||
// Keep this file strictly about wire protocol — no DB row shapes,
|
||||
// no server-internal helpers. Anything that crosses the network.
|
||||
// ============================================================
|
||||
|
||||
// ── Envelope ─────────────────────────────────────────────────
|
||||
// Every route returns either `{success: true, ...extraFields}` or
|
||||
// `{success: false, error: string}`. The generic `T` is the shape
|
||||
// of the extra fields on success. Client code does:
|
||||
// const r: ApiResponse<HpiOk> = await fetch(...).then(r => r.json());
|
||||
// if (r.success) console.log(r.hpi);
|
||||
// else showToast(r.error);
|
||||
export interface ApiErr {
|
||||
success: false;
|
||||
error: string;
|
||||
}
|
||||
export type ApiResponse<T> = ({ success: true } & T) | ApiErr;
|
||||
|
||||
// Model tag accompanies every AI response — LiteLLM pass-through.
|
||||
export interface WithModel {
|
||||
model: string;
|
||||
}
|
||||
|
||||
// ── AI generation responses ──────────────────────────────────
|
||||
// Keys match exactly what each route returns today. Do not rename
|
||||
// without updating the server-side res.json() call in the same commit.
|
||||
|
||||
// /api/generate-hpi-encounter
|
||||
// /api/generate-hpi-dictation
|
||||
export interface HpiOk extends WithModel {
|
||||
hpi: string;
|
||||
}
|
||||
|
||||
// /api/generate-soap
|
||||
export interface SoapOk extends WithModel {
|
||||
soap: string;
|
||||
}
|
||||
|
||||
// /api/sick-visit/note (NOT /api/generate-sick-visit — that path does not exist)
|
||||
// /api/well-visit/note
|
||||
export interface VisitNoteOk extends WithModel {
|
||||
note: string;
|
||||
}
|
||||
|
||||
// /api/generate-hospital-course
|
||||
export interface HospitalCourseOk extends WithModel {
|
||||
hospitalCourse: string;
|
||||
format?: string;
|
||||
}
|
||||
|
||||
// /api/generate-chart-review
|
||||
export interface ChartReviewOk extends WithModel {
|
||||
review: string;
|
||||
}
|
||||
|
||||
// /api/generate-pe-narrative
|
||||
export interface PeNarrativeOk extends WithModel {
|
||||
narrative: string;
|
||||
summary: {
|
||||
normal: number;
|
||||
abnormal: number;
|
||||
notAssessed: number;
|
||||
};
|
||||
}
|
||||
|
||||
// /api/generate-milestone-narrative
|
||||
export interface MilestoneNarrativeOk extends WithModel {
|
||||
narrative: string;
|
||||
summary: {
|
||||
achieved: number;
|
||||
notAchieved: number;
|
||||
notAssessed: number;
|
||||
};
|
||||
}
|
||||
|
||||
// /api/generate-milestone-summary
|
||||
export interface MilestoneSummaryOk extends WithModel {
|
||||
summary: string;
|
||||
}
|
||||
|
||||
// /api/well-visit/shadess
|
||||
export interface ShadessOk extends WithModel {
|
||||
assessment: string;
|
||||
}
|
||||
|
||||
// /api/refine
|
||||
export interface RefineOk extends WithModel {
|
||||
refined: string;
|
||||
}
|
||||
|
||||
// /api/shorten (via refine.js router)
|
||||
export interface ShortenOk extends WithModel {
|
||||
shortened: string;
|
||||
}
|
||||
|
||||
// /api/clarify and /hospital-course/clarify
|
||||
export interface ClarifyOk extends WithModel {
|
||||
questions: string;
|
||||
}
|
||||
|
||||
// /api/suggest-billing-codes
|
||||
export interface BillingCodesOk extends WithModel {
|
||||
icd10: Array<{ code: string; description: string; reason?: string }>;
|
||||
cpt: Array<{ code: string; description: string; reason?: string }>;
|
||||
}
|
||||
|
||||
// /api/transcribe
|
||||
export interface TranscribeOk {
|
||||
text: string;
|
||||
provider: string;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
// /api/tts
|
||||
export interface TtsOk {
|
||||
audioBase64: string;
|
||||
}
|
||||
|
||||
// /api/models
|
||||
export interface ModelsOk {
|
||||
models: Array<{ id: string; label?: string }>;
|
||||
}
|
||||
|
||||
// ── Auth ─────────────────────────────────────────────────────
|
||||
export interface AuthUser {
|
||||
id: number;
|
||||
email: string;
|
||||
name: string;
|
||||
role?: string;
|
||||
isVerified?: boolean;
|
||||
has2FA?: boolean;
|
||||
}
|
||||
|
||||
// /api/auth/login (two-phase: may also return requires2FA / needsVerification)
|
||||
export interface LoginOk {
|
||||
token: string;
|
||||
user: AuthUser;
|
||||
sessionId?: string;
|
||||
}
|
||||
|
||||
export interface LoginRequires2FA {
|
||||
success: true;
|
||||
requires2FA: true;
|
||||
}
|
||||
|
||||
export interface LoginNeedsVerification {
|
||||
success: true;
|
||||
needsVerification: true;
|
||||
}
|
||||
|
||||
// /api/auth/me
|
||||
export interface MeOk {
|
||||
user: AuthUser;
|
||||
}
|
||||
|
||||
// ── Sessions ─────────────────────────────────────────────────
|
||||
export interface SessionRow {
|
||||
id: string;
|
||||
userAgent?: string;
|
||||
ipAddress?: string;
|
||||
createdAt: string;
|
||||
lastUsedAt?: string;
|
||||
}
|
||||
export interface SessionsOk {
|
||||
sessions: SessionRow[];
|
||||
currentSessionId: string | null;
|
||||
}
|
||||
|
||||
// ── Extensions (pagers/directory) ────────────────────────────
|
||||
export interface Extension {
|
||||
id: number;
|
||||
location: string;
|
||||
name: string;
|
||||
number: string;
|
||||
type: 'extension' | 'pager';
|
||||
notes?: string;
|
||||
deletedAt?: string | null;
|
||||
}
|
||||
export interface ExtensionsListOk {
|
||||
items: Extension[];
|
||||
}
|
||||
|
||||
// ── Memories (saved templates / style hints) ─────────────────
|
||||
export interface Memory {
|
||||
id: number;
|
||||
category: string;
|
||||
name: string;
|
||||
content: string;
|
||||
}
|
||||
export interface MemoriesListOk {
|
||||
items: Memory[];
|
||||
}
|
||||
|
||||
// ── Learning hub ─────────────────────────────────────────────
|
||||
export interface LearningContentItem {
|
||||
id: number | string;
|
||||
slug?: string;
|
||||
title: string;
|
||||
category?: string;
|
||||
excerpt?: string;
|
||||
body?: string;
|
||||
}
|
||||
export interface LearningFeedOk {
|
||||
content: LearningContentItem[];
|
||||
total?: number;
|
||||
}
|
||||
|
||||
// ── Encounters (saved drafts) ────────────────────────────────
|
||||
export interface EncounterSummary {
|
||||
id: number;
|
||||
label: string;
|
||||
type: 'encounter' | 'dictation' | 'hospital' | 'chart' | 'wellvisit' | 'sickvisit' | 'soap';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
export interface EncountersListOk {
|
||||
items: EncounterSummary[];
|
||||
}
|
||||
|
||||
// ── Health ───────────────────────────────────────────────────
|
||||
export interface HealthOk {
|
||||
ok: boolean;
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
}
|
||||
},
|
||||
"include": [
|
||||
"server.ts",
|
||||
"server.js",
|
||||
"src/**/*.js",
|
||||
"src/**/*.ts",
|
||||
|
|
|
|||
Loading…
Reference in a new issue