Setup getConfig with typebox validations

This commit is contained in:
Dominic Ferrando
2026-07-04 01:12:15 -04:00
parent d042340c8b
commit 1da9795d84
8 changed files with 52 additions and 34 deletions
-1
View File
@@ -31,7 +31,6 @@
"kysely": "^0.29.2", "kysely": "^0.29.2",
"ml-levenberg-marquardt": "^5.0.1", "ml-levenberg-marquardt": "^5.0.1",
"pg": "^8.22.0", "pg": "^8.22.0",
"pino": "^10.3.1",
"zipcodes-us": "^1.1.3" "zipcodes-us": "^1.1.3"
}, },
"devDependencies": { "devDependencies": {
+17 -1
View File
@@ -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 type { ActivityPerformance, Player } from "@blade-and-brawn/domain";
import { db } from "../database/db";
import { Value } from "@sinclair/typebox/value";
export class CalculatorService { export class CalculatorService {
private readonly levelCalculator; private readonly levelCalculator;
@@ -13,4 +15,18 @@ export class CalculatorService {
calculate(player: Player, activityPerformances: ActivityPerformance[]) { calculate(player: Player, activityPerformances: ActivityPerformance[]) {
return this.levelCalculator.calculate(player, activityPerformances) return this.levelCalculator.calculate(player, activityPerformances)
} }
async getConfig(opt: { skipCache?: boolean } = {}): Promise<StandardsConfig> {
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;
}
} }
+5 -6
View File
@@ -4,6 +4,10 @@
"workspaces": { "workspaces": {
"": { "": {
"name": "blade-and-brawn", "name": "blade-and-brawn",
"dependencies": {
"@sinclair/typebox": "^0.34.48",
"pino": "^10.3.1",
},
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.14", "@types/bun": "^1.3.14",
"typescript": "^6.0.3", "typescript": "^6.0.3",
@@ -23,7 +27,6 @@
"kysely": "^0.29.2", "kysely": "^0.29.2",
"ml-levenberg-marquardt": "^5.0.1", "ml-levenberg-marquardt": "^5.0.1",
"pg": "^8.22.0", "pg": "^8.22.0",
"pino": "^10.3.1",
"zipcodes-us": "^1.1.3", "zipcodes-us": "^1.1.3",
}, },
"devDependencies": { "devDependencies": {
@@ -60,22 +63,18 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@blade-and-brawn/domain": "workspace:*", "@blade-and-brawn/domain": "workspace:*",
"ml-levenberg-marquardt": "^5.0.0", "ml-levenberg-marquardt": "^5.0.1",
}, },
}, },
"packages/commerce": { "packages/commerce": {
"name": "@blade-and-brawn/commerce", "name": "@blade-and-brawn/commerce",
"version": "0.0.0", "version": "0.0.0",
"dependencies": {
"pino": "^10.3.1",
},
}, },
"packages/domain": { "packages/domain": {
"name": "@blade-and-brawn/domain", "name": "@blade-and-brawn/domain",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@blade-and-brawn/domain": "workspace:*", "@blade-and-brawn/domain": "workspace:*",
"@sinclair/typebox": "^0.34.48",
}, },
}, },
}, },
+4
View File
@@ -14,5 +14,9 @@
"devDependencies": { "devDependencies": {
"@types/bun": "^1.3.14", "@types/bun": "^1.3.14",
"typescript": "^6.0.3" "typescript": "^6.0.3"
},
"dependencies": {
"pino": "^10.3.1",
"@sinclair/typebox": "^0.34.48"
} }
} }
+1 -1
View File
@@ -4,7 +4,7 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"ml-levenberg-marquardt": "^5.0.0", "ml-levenberg-marquardt": "^5.0.1",
"@blade-and-brawn/domain": "workspace:*" "@blade-and-brawn/domain": "workspace:*"
}, },
"exports": { "exports": {
+23 -20
View File
@@ -11,6 +11,8 @@ import {
type StandardUnit, type StandardUnit,
} from "@blade-and-brawn/domain"; } from "@blade-and-brawn/domain";
import { levenbergMarquardt as LM } from "ml-levenberg-marquardt"; 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 defaultConfig from "./config.json" with { type: "json" };
import defaultStandardsJson from "./data/default-standards.json" with { type: "json" }; import defaultStandardsJson from "./data/default-standards.json" with { type: "json" };
import { getAvgWeight } from "./avg-weights"; import { getAvgWeight } from "./avg-weights";
@@ -211,26 +213,27 @@ export class LevelCalculator {
} }
} }
export type StandardsConfig = { const StandardsActivityConfigSchema = Type.Object({
global: { weightModifier: Type.Number(),
maxLevel: number; weightSkew: Type.Number(),
}; ageModifier: Type.Number(),
activity: Record< enableGeneration: Type.Boolean(),
Activity, difficultyModifier: Type.Number(),
{ peakAge: Type.Number(),
weightModifier: number; stretch: Type.Object({
weightSkew: number; upper: Type.Number(),
ageModifier: number; lower: Type.Number(),
enableGeneration: boolean; }),
difficultyModifier: number; });
peakAge: number;
stretch: { export const StandardsConfigSchema = Type.Object({
upper: number; global: Type.Object({
lower: number; maxLevel: Type.Number(),
}; }),
} activity: Type.Record(Type.Enum(Activity), StandardsActivityConfigSchema),
>; });
};
export type StandardsConfig = Static<typeof StandardsConfigSchema>;
export class Standards { export class Standards {
readonly cfg: StandardsConfig; readonly cfg: StandardsConfig;
+1 -3
View File
@@ -6,7 +6,5 @@
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"
}, },
"dependencies": { "dependencies": {}
"pino": "^10.3.1"
}
} }
+1 -2
View File
@@ -4,8 +4,7 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@blade-and-brawn/domain": "workspace:*", "@blade-and-brawn/domain": "workspace:*"
"@sinclair/typebox": "^0.34.48"
}, },
"exports": { "exports": {
".": "./src/index.ts" ".": "./src/index.ts"