@validation-os/api 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Benji Fisher
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,64 @@
1
+ import { AnyRecord, DataProvider } from '@validation-os/core';
2
+
3
+ /**
4
+ * Derive-on-write — the API runs the shared derivation module server-side so
5
+ * stored derived values are always authoritative, whatever the client sent.
6
+ *
7
+ * Two layers:
8
+ * - `deriveReadingFields`: a reading's own Source quality + Strength are pure
9
+ * functions of the record itself — stamped inline on every reading write.
10
+ * - `recomputeAllDerived`: the cross-record pass (Confidence, Derived Impact,
11
+ * Risk over the whole assumptions register) — the backstop the spec keeps
12
+ * for non-dashboard writes, run after any assumption/reading/decision write.
13
+ */
14
+
15
+ /** Stamp Source quality + Strength onto a reading's `derived` field. */
16
+ declare function deriveReadingFields(data: Partial<AnyRecord>): Partial<AnyRecord>;
17
+ /**
18
+ * Recompute Confidence / Derived Impact / Risk for every assumption and write
19
+ * back only those whose derived tuple actually changed (so unrelated rows
20
+ * don't churn their version). Returns the number of rows updated.
21
+ */
22
+ declare function recomputeAllDerived(provider: DataProvider): Promise<number>;
23
+
24
+ /**
25
+ * @validation-os/api — framework-neutral route-handler logic.
26
+ *
27
+ * Handlers operate on the Web `Request`/`Response` types (what Next.js app-
28
+ * router route handlers receive), so the same functions drop into a Next app
29
+ * or any Web-standard runtime. Authentication is injected — the deployed app
30
+ * supplies a Clerk-verifying `authenticate`, so this package stays free of any
31
+ * auth-vendor dependency. Every write runs the derivation module server-side.
32
+ */
33
+
34
+ interface AuthResult {
35
+ userId: string;
36
+ }
37
+ interface CreateApiOptions {
38
+ provider: DataProvider;
39
+ /** Return the authenticated principal, or null to reject with 401. */
40
+ authenticate: (req: Request) => Promise<AuthResult | null> | AuthResult | null;
41
+ /** Run derive-on-write after writes (default true). */
42
+ deriveOnWrite?: boolean;
43
+ }
44
+ type Params = Record<string, string | undefined>;
45
+ interface RouteContext {
46
+ params: Params | Promise<Params>;
47
+ }
48
+ interface ValidationOsApi {
49
+ /** GET /api/[register] — list every row of a register. */
50
+ list(req: Request, ctx: RouteContext): Promise<Response>;
51
+ /** GET /api/[register]/[id] — one record. */
52
+ get(req: Request, ctx: RouteContext): Promise<Response>;
53
+ /** POST /api/[register] — create; body is the record fields. */
54
+ create(req: Request, ctx: RouteContext): Promise<Response>;
55
+ /** PATCH /api/[register]/[id] — body { version, ...patch }. */
56
+ update(req: Request, ctx: RouteContext): Promise<Response>;
57
+ /** GET /api/counts — per-register row counts (the walking-skeleton value). */
58
+ counts(req: Request): Promise<Response>;
59
+ /** POST /api/recompute — run the derived-fields backstop pass. */
60
+ recompute(req: Request): Promise<Response>;
61
+ }
62
+ declare function createApi(options: CreateApiOptions): ValidationOsApi;
63
+
64
+ export { type AuthResult, type CreateApiOptions, type RouteContext, type ValidationOsApi, createApi, deriveReadingFields, recomputeAllDerived };
package/dist/index.js ADDED
@@ -0,0 +1,193 @@
1
+ // src/index.ts
2
+ import {
3
+ REGISTERS,
4
+ isNotFoundError,
5
+ isStaleVersionError
6
+ } from "@validation-os/core";
7
+
8
+ // src/derive-on-write.ts
9
+ import {
10
+ recomputeDerived,
11
+ recomputeSourceQuality,
12
+ recomputeStrength
13
+ } from "@validation-os/core";
14
+ function deriveReadingFields(data) {
15
+ const r = data;
16
+ if (r.Rung == null || r.Result == null) return data;
17
+ const sourceQuality = recomputeSourceQuality(
18
+ Number(r.Representativeness ?? 0),
19
+ Number(r.Credibility ?? 0)
20
+ );
21
+ const strength = recomputeStrength({
22
+ rung: r.Rung,
23
+ result: r.Result,
24
+ magnitudeBand: r.magnitudeBand
25
+ });
26
+ return { ...data, derived: { sourceQuality, strength } };
27
+ }
28
+ async function recomputeAllDerived(provider) {
29
+ const [assumptions, readings, decisions] = await Promise.all([
30
+ provider.list("assumptions"),
31
+ provider.list("readings"),
32
+ provider.list("decisions")
33
+ ]);
34
+ const derived = recomputeDerived({
35
+ assumptions,
36
+ readings,
37
+ decisions
38
+ });
39
+ let updated = 0;
40
+ for (const a of assumptions) {
41
+ const next = derived.get(a.id);
42
+ if (!next) continue;
43
+ const cur = a.derived ?? {};
44
+ if (cur.confidence === next.confidence && cur.risk === next.risk && cur.derivedImpact === next.derivedImpact) {
45
+ continue;
46
+ }
47
+ await provider.update("assumptions", a.id, { derived: next }, a.version);
48
+ updated += 1;
49
+ }
50
+ return updated;
51
+ }
52
+
53
+ // src/index.ts
54
+ var COLLECTIONS = /* @__PURE__ */ new Set([...REGISTERS, "people"]);
55
+ var DERIVED_TRIGGERS = /* @__PURE__ */ new Set(["assumptions", "readings", "decisions"]);
56
+ function json(body, status = 200) {
57
+ return new Response(JSON.stringify(body), {
58
+ status,
59
+ headers: { "content-type": "application/json" }
60
+ });
61
+ }
62
+ async function resolveParams(ctx) {
63
+ return await ctx.params;
64
+ }
65
+ function assertRegister(value) {
66
+ if (!value || !COLLECTIONS.has(value)) {
67
+ throw new BadRequest(`Unknown register: ${String(value)}`);
68
+ }
69
+ return value;
70
+ }
71
+ var BadRequest = class extends Error {
72
+ };
73
+ function toErrorResponse(e) {
74
+ if (e instanceof BadRequest) return json({ error: e.message }, 400);
75
+ if (isNotFoundError(e)) return json({ error: e.message }, 404);
76
+ if (isStaleVersionError(e)) {
77
+ return json(
78
+ {
79
+ error: "conflict",
80
+ // Plain-language copy — never version jargon (spec user story 12).
81
+ message: "Someone edited this while you had it open \u2014 your changes are safe, take a look before saving again."
82
+ },
83
+ 409
84
+ );
85
+ }
86
+ return json({ error: "internal", message: "Something went wrong." }, 500);
87
+ }
88
+ function createApi(options) {
89
+ const { provider } = options;
90
+ const deriveOn = options.deriveOnWrite ?? true;
91
+ async function guard(req) {
92
+ const auth = await options.authenticate(req);
93
+ if (!auth) throw new Unauthorized();
94
+ return auth;
95
+ }
96
+ async function maybeRecompute(register) {
97
+ if (deriveOn && DERIVED_TRIGGERS.has(register)) {
98
+ await recomputeAllDerived(provider);
99
+ }
100
+ }
101
+ return {
102
+ async list(req, ctx) {
103
+ try {
104
+ await guard(req);
105
+ const register = assertRegister((await resolveParams(ctx)).register);
106
+ return json({ data: await provider.list(register) });
107
+ } catch (e) {
108
+ return handle(e);
109
+ }
110
+ },
111
+ async get(req, ctx) {
112
+ try {
113
+ await guard(req);
114
+ const p = await resolveParams(ctx);
115
+ const register = assertRegister(p.register);
116
+ if (!p.id) throw new BadRequest("Missing id");
117
+ return json({ data: await provider.get(register, p.id) });
118
+ } catch (e) {
119
+ return handle(e);
120
+ }
121
+ },
122
+ async create(req, ctx) {
123
+ try {
124
+ await guard(req);
125
+ const register = assertRegister((await resolveParams(ctx)).register);
126
+ let data = await req.json();
127
+ if (register === "readings") data = deriveReadingFields(data);
128
+ const created = await provider.create(register, data);
129
+ await maybeRecompute(register);
130
+ return json({ data: created }, 201);
131
+ } catch (e) {
132
+ return handle(e);
133
+ }
134
+ },
135
+ async update(req, ctx) {
136
+ try {
137
+ await guard(req);
138
+ const p = await resolveParams(ctx);
139
+ const register = assertRegister(p.register);
140
+ if (!p.id) throw new BadRequest("Missing id");
141
+ const body = await req.json();
142
+ const { version, ...rawPatch } = body;
143
+ if (typeof version !== "number") {
144
+ throw new BadRequest("A numeric `version` is required for updates.");
145
+ }
146
+ const patch = register === "readings" ? deriveReadingFields(rawPatch) : rawPatch;
147
+ const updated = await provider.update(register, p.id, patch, version);
148
+ await maybeRecompute(register);
149
+ return json({ data: updated });
150
+ } catch (e) {
151
+ return handle(e);
152
+ }
153
+ },
154
+ async counts(req) {
155
+ try {
156
+ await guard(req);
157
+ const registers = [...COLLECTIONS];
158
+ const counts = {};
159
+ await Promise.all(
160
+ registers.map(async (r) => {
161
+ counts[r] = (await provider.list(r)).length;
162
+ })
163
+ );
164
+ return json({ counts });
165
+ } catch (e) {
166
+ return handle(e);
167
+ }
168
+ },
169
+ async recompute(req) {
170
+ try {
171
+ await guard(req);
172
+ const updated = await recomputeAllDerived(provider);
173
+ return json({ updated });
174
+ } catch (e) {
175
+ return handle(e);
176
+ }
177
+ }
178
+ };
179
+ }
180
+ var Unauthorized = class extends Error {
181
+ };
182
+ function handle(e) {
183
+ if (e instanceof Unauthorized) {
184
+ return json({ error: "unauthorized" }, 401);
185
+ }
186
+ return toErrorResponse(e);
187
+ }
188
+ export {
189
+ createApi,
190
+ deriveReadingFields,
191
+ recomputeAllDerived
192
+ };
193
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/derive-on-write.ts"],"sourcesContent":["/**\n * @validation-os/api — framework-neutral route-handler logic.\n *\n * Handlers operate on the Web `Request`/`Response` types (what Next.js app-\n * router route handlers receive), so the same functions drop into a Next app\n * or any Web-standard runtime. Authentication is injected — the deployed app\n * supplies a Clerk-verifying `authenticate`, so this package stays free of any\n * auth-vendor dependency. Every write runs the derivation module server-side.\n */\nimport {\n REGISTERS,\n isNotFoundError,\n isStaleVersionError,\n type Collection,\n type DataProvider,\n} from \"@validation-os/core\";\nimport {\n deriveReadingFields,\n recomputeAllDerived,\n} from \"./derive-on-write.js\";\n\nexport { deriveReadingFields, recomputeAllDerived };\n\nconst COLLECTIONS = new Set<string>([...REGISTERS, \"people\"]);\n/** Writes to these trigger the cross-record derived recompute pass. */\nconst DERIVED_TRIGGERS = new Set<string>([\"assumptions\", \"readings\", \"decisions\"]);\n\nexport interface AuthResult {\n userId: string;\n}\n\nexport interface CreateApiOptions {\n provider: DataProvider;\n /** Return the authenticated principal, or null to reject with 401. */\n authenticate: (req: Request) => Promise<AuthResult | null> | AuthResult | null;\n /** Run derive-on-write after writes (default true). */\n deriveOnWrite?: boolean;\n}\n\ntype Params = Record<string, string | undefined>;\nexport interface RouteContext {\n params: Params | Promise<Params>;\n}\n\nfunction json(body: unknown, status = 200): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json\" },\n });\n}\n\nasync function resolveParams(ctx: RouteContext): Promise<Params> {\n return await ctx.params;\n}\n\nfunction assertRegister(value: string | undefined): Collection {\n if (!value || !COLLECTIONS.has(value)) {\n throw new BadRequest(`Unknown register: ${String(value)}`);\n }\n return value as Collection;\n}\n\nclass BadRequest extends Error {}\n\n/** Turn a thrown error into the right HTTP response, in plain language. */\nfunction toErrorResponse(e: unknown): Response {\n if (e instanceof BadRequest) return json({ error: e.message }, 400);\n if (isNotFoundError(e)) return json({ error: e.message }, 404);\n if (isStaleVersionError(e)) {\n return json(\n {\n error: \"conflict\",\n // Plain-language copy — never version jargon (spec user story 12).\n message:\n \"Someone edited this while you had it open — your changes are \" +\n \"safe, take a look before saving again.\",\n },\n 409,\n );\n }\n return json({ error: \"internal\", message: \"Something went wrong.\" }, 500);\n}\n\nexport interface ValidationOsApi {\n /** GET /api/[register] — list every row of a register. */\n list(req: Request, ctx: RouteContext): Promise<Response>;\n /** GET /api/[register]/[id] — one record. */\n get(req: Request, ctx: RouteContext): Promise<Response>;\n /** POST /api/[register] — create; body is the record fields. */\n create(req: Request, ctx: RouteContext): Promise<Response>;\n /** PATCH /api/[register]/[id] — body { version, ...patch }. */\n update(req: Request, ctx: RouteContext): Promise<Response>;\n /** GET /api/counts — per-register row counts (the walking-skeleton value). */\n counts(req: Request): Promise<Response>;\n /** POST /api/recompute — run the derived-fields backstop pass. */\n recompute(req: Request): Promise<Response>;\n}\n\nexport function createApi(options: CreateApiOptions): ValidationOsApi {\n const { provider } = options;\n const deriveOn = options.deriveOnWrite ?? true;\n\n async function guard(req: Request): Promise<AuthResult> {\n const auth = await options.authenticate(req);\n if (!auth) throw new Unauthorized();\n return auth;\n }\n\n async function maybeRecompute(register: Collection): Promise<void> {\n if (deriveOn && DERIVED_TRIGGERS.has(register)) {\n await recomputeAllDerived(provider);\n }\n }\n\n return {\n async list(req, ctx) {\n try {\n await guard(req);\n const register = assertRegister((await resolveParams(ctx)).register);\n return json({ data: await provider.list(register) });\n } catch (e) {\n return handle(e);\n }\n },\n\n async get(req, ctx) {\n try {\n await guard(req);\n const p = await resolveParams(ctx);\n const register = assertRegister(p.register);\n if (!p.id) throw new BadRequest(\"Missing id\");\n return json({ data: await provider.get(register, p.id) });\n } catch (e) {\n return handle(e);\n }\n },\n\n async create(req, ctx) {\n try {\n await guard(req);\n const register = assertRegister((await resolveParams(ctx)).register);\n let data = (await req.json()) as Record<string, unknown>;\n if (register === \"readings\") data = deriveReadingFields(data);\n const created = await provider.create(register, data);\n await maybeRecompute(register);\n return json({ data: created }, 201);\n } catch (e) {\n return handle(e);\n }\n },\n\n async update(req, ctx) {\n try {\n await guard(req);\n const p = await resolveParams(ctx);\n const register = assertRegister(p.register);\n if (!p.id) throw new BadRequest(\"Missing id\");\n const body = (await req.json()) as Record<string, unknown>;\n const { version, ...rawPatch } = body;\n if (typeof version !== \"number\") {\n throw new BadRequest(\"A numeric `version` is required for updates.\");\n }\n const patch =\n register === \"readings\" ? deriveReadingFields(rawPatch) : rawPatch;\n const updated = await provider.update(register, p.id, patch, version);\n await maybeRecompute(register);\n return json({ data: updated });\n } catch (e) {\n return handle(e);\n }\n },\n\n async counts(req) {\n try {\n await guard(req);\n const registers = [...COLLECTIONS] as Collection[];\n const counts: Record<string, number> = {};\n await Promise.all(\n registers.map(async (r) => {\n counts[r] = (await provider.list(r)).length;\n }),\n );\n return json({ counts });\n } catch (e) {\n return handle(e);\n }\n },\n\n async recompute(req) {\n try {\n await guard(req);\n const updated = await recomputeAllDerived(provider);\n return json({ updated });\n } catch (e) {\n return handle(e);\n }\n },\n };\n}\n\nclass Unauthorized extends Error {}\n\nfunction handle(e: unknown): Response {\n if (e instanceof Unauthorized) {\n return json({ error: \"unauthorized\" }, 401);\n }\n return toErrorResponse(e);\n}\n","/**\n * Derive-on-write — the API runs the shared derivation module server-side so\n * stored derived values are always authoritative, whatever the client sent.\n *\n * Two layers:\n * - `deriveReadingFields`: a reading's own Source quality + Strength are pure\n * functions of the record itself — stamped inline on every reading write.\n * - `recomputeAllDerived`: the cross-record pass (Confidence, Derived Impact,\n * Risk over the whole assumptions register) — the backstop the spec keeps\n * for non-dashboard writes, run after any assumption/reading/decision write.\n */\nimport {\n recomputeDerived,\n recomputeSourceQuality,\n recomputeStrength,\n type AnyRecord,\n type AssumptionRecord,\n type DataProvider,\n type DecisionRecord,\n type ReadingRecord,\n} from \"@validation-os/core\";\n\n/** Stamp Source quality + Strength onto a reading's `derived` field. */\nexport function deriveReadingFields(data: Partial<AnyRecord>): Partial<AnyRecord> {\n const r = data as Partial<ReadingRecord>;\n if (r.Rung == null || r.Result == null) return data; // not enough to derive\n const sourceQuality = recomputeSourceQuality(\n Number(r.Representativeness ?? 0),\n Number(r.Credibility ?? 0),\n );\n const strength = recomputeStrength({\n rung: r.Rung,\n result: r.Result,\n magnitudeBand: r.magnitudeBand,\n });\n return { ...data, derived: { sourceQuality, strength } };\n}\n\n/**\n * Recompute Confidence / Derived Impact / Risk for every assumption and write\n * back only those whose derived tuple actually changed (so unrelated rows\n * don't churn their version). Returns the number of rows updated.\n */\nexport async function recomputeAllDerived(\n provider: DataProvider,\n): Promise<number> {\n const [assumptions, readings, decisions] = await Promise.all([\n provider.list(\"assumptions\"),\n provider.list(\"readings\"),\n provider.list(\"decisions\"),\n ]);\n\n const derived = recomputeDerived({\n assumptions: assumptions as unknown as AssumptionRecord[],\n readings: readings as unknown as ReadingRecord[],\n decisions: decisions as unknown as DecisionRecord[],\n });\n\n let updated = 0;\n for (const a of assumptions) {\n const next = derived.get(a.id);\n if (!next) continue;\n const cur = (a.derived ?? {}) as Partial<AssumptionRecord[\"derived\"]>;\n if (\n cur.confidence === next.confidence &&\n cur.risk === next.risk &&\n cur.derivedImpact === next.derivedImpact\n ) {\n continue;\n }\n await provider.update(\"assumptions\", a.id, { derived: next }, a.version);\n updated += 1;\n }\n return updated;\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@validation-os/api",
3
+ "version": "0.1.0",
4
+ "description": "Framework-neutral route-handler logic for validation-os: auth-guarded CRUD over a DataProvider, with derive-on-write via the shared derivation module.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "dependencies": {
24
+ "@validation-os/core": "0.1.0"
25
+ },
26
+ "devDependencies": {
27
+ "tsup": "^8.3.0",
28
+ "typescript": "^5.6.3"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/bfish1996/validation-os.git",
33
+ "directory": "packages/api"
34
+ },
35
+ "scripts": {
36
+ "build": "tsup",
37
+ "typecheck": "tsc --noEmit"
38
+ }
39
+ }