From 1da9795d84775dd90f65344fc1f6954b57e1c7d0 Mon Sep 17 00:00:00 2001 From: Dominic Ferrando Date: Sat, 4 Jul 2026 01:12:15 -0400 Subject: [PATCH] Setup getConfig with typebox validations --- apps/api/package.json | 1 - apps/api/src/services/calculator.ts | 18 +++++++++++- bun.lock | 11 ++++---- package.json | 4 +++ packages/calculator/package.json | 2 +- packages/calculator/src/index.ts | 43 +++++++++++++++-------------- packages/commerce/package.json | 4 +-- packages/domain/package.json | 3 +- 8 files changed, 52 insertions(+), 34 deletions(-) diff --git a/apps/api/package.json b/apps/api/package.json index 57846d4..585cee2 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -31,7 +31,6 @@ "kysely": "^0.29.2", "ml-levenberg-marquardt": "^5.0.1", "pg": "^8.22.0", - "pino": "^10.3.1", "zipcodes-us": "^1.1.3" }, "devDependencies": { diff --git a/apps/api/src/services/calculator.ts b/apps/api/src/services/calculator.ts index 1eb8cfe..8da9179 100644 --- a/apps/api/src/services/calculator.ts +++ b/apps/api/src/services/calculator.ts @@ -1,5 +1,7 @@ -import { LevelCalculator, Standards, DEFAULT_STANDARDS_DATA } from "@blade-and-brawn/calculator"; +import { LevelCalculator, Standards, DEFAULT_STANDARDS_DATA, type StandardsConfig, StandardsConfigSchema } from "@blade-and-brawn/calculator"; import type { ActivityPerformance, Player } from "@blade-and-brawn/domain"; +import { db } from "../database/db"; +import { Value } from "@sinclair/typebox/value"; export class CalculatorService { private readonly levelCalculator; @@ -13,4 +15,18 @@ export class CalculatorService { calculate(player: Player, activityPerformances: ActivityPerformance[]) { return this.levelCalculator.calculate(player, activityPerformances) } + + async getConfig(opt: { skipCache?: boolean } = {}): Promise { + if (!opt.skipCache) return this.levelCalculator.standards.cfg; + + const result = await db.selectFrom("calculator_configs") + .select(["parameters"]) + .where("is_selected", "=", true) + .limit(1) + .executeTakeFirstOrThrow({ errorConstructor: () => new Error("No calculator config selected") }); + + const standardsConfig = result.parameters; + Value.Assert(StandardsConfigSchema, standardsConfig); + return standardsConfig; + } } diff --git a/bun.lock b/bun.lock index f95a4a6..e4bf81e 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,10 @@ "workspaces": { "": { "name": "blade-and-brawn", + "dependencies": { + "@sinclair/typebox": "^0.34.48", + "pino": "^10.3.1", + }, "devDependencies": { "@types/bun": "^1.3.14", "typescript": "^6.0.3", @@ -23,7 +27,6 @@ "kysely": "^0.29.2", "ml-levenberg-marquardt": "^5.0.1", "pg": "^8.22.0", - "pino": "^10.3.1", "zipcodes-us": "^1.1.3", }, "devDependencies": { @@ -60,22 +63,18 @@ "version": "0.0.0", "dependencies": { "@blade-and-brawn/domain": "workspace:*", - "ml-levenberg-marquardt": "^5.0.0", + "ml-levenberg-marquardt": "^5.0.1", }, }, "packages/commerce": { "name": "@blade-and-brawn/commerce", "version": "0.0.0", - "dependencies": { - "pino": "^10.3.1", - }, }, "packages/domain": { "name": "@blade-and-brawn/domain", "version": "0.0.0", "dependencies": { "@blade-and-brawn/domain": "workspace:*", - "@sinclair/typebox": "^0.34.48", }, }, }, diff --git a/package.json b/package.json index e282053..b4bd5a2 100644 --- a/package.json +++ b/package.json @@ -14,5 +14,9 @@ "devDependencies": { "@types/bun": "^1.3.14", "typescript": "^6.0.3" + }, + "dependencies": { + "pino": "^10.3.1", + "@sinclair/typebox": "^0.34.48" } } diff --git a/packages/calculator/package.json b/packages/calculator/package.json index e47fecc..9050137 100644 --- a/packages/calculator/package.json +++ b/packages/calculator/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "dependencies": { - "ml-levenberg-marquardt": "^5.0.0", + "ml-levenberg-marquardt": "^5.0.1", "@blade-and-brawn/domain": "workspace:*" }, "exports": { diff --git a/packages/calculator/src/index.ts b/packages/calculator/src/index.ts index bb54f57..83a1dbb 100644 --- a/packages/calculator/src/index.ts +++ b/packages/calculator/src/index.ts @@ -11,6 +11,8 @@ import { type StandardUnit, } from "@blade-and-brawn/domain"; import { levenbergMarquardt as LM } from "ml-levenberg-marquardt"; +import { Type, type Static } from "@sinclair/typebox"; +import { Value } from "@sinclair/typebox/value"; import defaultConfig from "./config.json" with { type: "json" }; import defaultStandardsJson from "./data/default-standards.json" with { type: "json" }; import { getAvgWeight } from "./avg-weights"; @@ -211,26 +213,27 @@ export class LevelCalculator { } } -export type StandardsConfig = { - global: { - maxLevel: number; - }; - activity: Record< - Activity, - { - weightModifier: number; - weightSkew: number; - ageModifier: number; - enableGeneration: boolean; - difficultyModifier: number; - peakAge: number; - stretch: { - upper: number; - lower: number; - }; - } - >; -}; +const StandardsActivityConfigSchema = Type.Object({ + weightModifier: Type.Number(), + weightSkew: Type.Number(), + ageModifier: Type.Number(), + enableGeneration: Type.Boolean(), + difficultyModifier: Type.Number(), + peakAge: Type.Number(), + stretch: Type.Object({ + upper: Type.Number(), + lower: Type.Number(), + }), +}); + +export const StandardsConfigSchema = Type.Object({ + global: Type.Object({ + maxLevel: Type.Number(), + }), + activity: Type.Record(Type.Enum(Activity), StandardsActivityConfigSchema), +}); + +export type StandardsConfig = Static; export class Standards { readonly cfg: StandardsConfig; diff --git a/packages/commerce/package.json b/packages/commerce/package.json index d2248d6..9c0dcdc 100644 --- a/packages/commerce/package.json +++ b/packages/commerce/package.json @@ -6,7 +6,5 @@ "exports": { ".": "./src/index.ts" }, - "dependencies": { - "pino": "^10.3.1" - } + "dependencies": {} } diff --git a/packages/domain/package.json b/packages/domain/package.json index b03badc..b142b53 100644 --- a/packages/domain/package.json +++ b/packages/domain/package.json @@ -4,8 +4,7 @@ "version": "0.0.0", "type": "module", "dependencies": { - "@blade-and-brawn/domain": "workspace:*", - "@sinclair/typebox": "^0.34.48" + "@blade-and-brawn/domain": "workspace:*" }, "exports": { ".": "./src/index.ts"