Move domain models into domain package with schemas and validate with zod + elysia. Some maintenence as well

This commit is contained in:
Dominic Ferrando
2026-06-22 13:59:04 -04:00
parent ed5abac209
commit 6fa3d78571
16 changed files with 220 additions and 166 deletions
+6 -4
View File
@@ -8,11 +8,13 @@
"start": "bun run src/index.ts"
},
"dependencies": {
"@elysiajs/cors": "^1.4.2",
"elysia": "^1.4.28",
"zipcodes-us": "^1.1.3",
"@blade-and-brawn/calculator": "workspace:*",
"@blade-and-brawn/commerce": "workspace:*",
"ml-levenberg-marquardt": "^5.0.1"
"@blade-and-brawn/domain": "workspace:*",
"@elysiajs/cors": "^1.4.2",
"elysia": "^1.4.29",
"ml-levenberg-marquardt": "^5.0.1",
"zipcodes-us": "^1.1.3",
"zod": "^4.4.3"
}
}
+38 -19
View File
@@ -2,9 +2,14 @@ import {
DEFAULT_STANDARDS_DATA,
LevelCalculator,
Standards,
} from "@blade-and-brawn/calculator";
import {
ActivityPerformanceSchema,
PlayerSchema,
type ActivityPerformance,
type Player,
} from "@blade-and-brawn/calculator";
} from "@blade-and-brawn/domain"
import { cors } from "@elysiajs/cors";
import { Elysia, NotFoundError } from "elysia";
import {
@@ -16,6 +21,7 @@ import {
FetchError,
} from "@blade-and-brawn/commerce";
import zipcodesUs from "zipcodes-us";
import z from "zod";
const levelCalculator = new LevelCalculator(
new Standards(DEFAULT_STANDARDS_DATA),
@@ -25,13 +31,18 @@ export const app = new Elysia()
.use(
cors({
origin: [
// bladeandbrawn.com (apex + any subdomain)
// WEBSITE
// -----------
// production
/^https?:\/\/([a-z0-9-]+\.)?bladeandbrawn\.com$/i,
// Webflow preview domains
// testing
/^https?:\/\/([a-z0-9-]+\.)?bladeandbrawn\.webflow\.io$/i,
// Fly app host (this one already works)
// PORTAL
// -----------
// production
/^https?:\/\/blade-and-brawn\.fly\.dev$/i,
// Local dev portal
// development
"http://localhost:5173",
],
}),
@@ -65,14 +76,9 @@ export const app = new Elysia()
// CALCULATOR
.post("/calculate", async ({ body, query }) => {
interface CalcRequest {
player: Player;
activityPerformances: ActivityPerformance[];
}
const { player, activityPerformances } = body as CalcRequest;
.post("/calculate", async ({ body }) => {
const output = {
levels: levelCalculator.calculate(player, activityPerformances),
levels: levelCalculator.calculate(body.player, body.activityPerformances),
};
// console.log({ log: query?.log });
@@ -85,6 +91,11 @@ export const app = new Elysia()
// }
return output;
}, {
body: z.object({
player: PlayerSchema,
activityPerformances: z.array(ActivityPerformanceSchema)
})
})
// COMMERCE
@@ -93,18 +104,26 @@ export const app = new Elysia()
app
.group("/sync", (app) =>
app
.get("/", async ({}) => SyncService.state)
.post("/:printfulProductId?", async ({ params, set }) => {
// Sync status
.get("/", async ({ }) => SyncService.state)
// Full sync
.post("/", async ({ set }) => {
if (SyncService.state.isSyncing) {
set.status = 409;
return { error: "Sync already in progress" };
}
const printfulProductId = params.printfulProductId
? +params.printfulProductId
: undefined;
await SyncService.sync(printfulProductId);
await SyncService.sync();
return { ok: true };
}),
})
// Per-product sync
.post("/:printfulProductId", async ({ params, set }) => {
if (SyncService.state.isSyncing) {
set.status = 409;
return { error: "Sync already in progress" };
}
await SyncService.sync(params.printfulProductId);
return { ok: true };
}, { params: z.object({ printfulProductId: z.number() }) }),
)
.get("/:printfulProductId", async ({ params }) => {
const printfulProductId = +params.printfulProductId;
+3 -3
View File
@@ -2,7 +2,7 @@
"name": "@blade-and-brawn/portal",
"type": "module",
"devDependencies": {
"@sveltejs/kit": "^2.65.1",
"@sveltejs/kit": "^2.66.0",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@types/bun": "^1.3.14",
"svelte": "^5.56.3",
@@ -22,9 +22,9 @@
"dependencies": {
"@tailwindcss/vite": "^4.3.1",
"daisyui": "^5.5.23",
"memoirist": "^0.4.0",
"tailwindcss": "^4.3.1",
"@blade-and-brawn/calculator": "workspace:*",
"@blade-and-brawn/commerce": "workspace:*"
"@blade-and-brawn/commerce": "workspace:*",
"@blade-and-brawn/domain": "workspace:*"
}
}
@@ -1,16 +1,18 @@
<script lang="ts">
import {
LevelCalculator,
type LevelCalculatorOutput,
type Standards,
} from "@blade-and-brawn/calculator";
import {
Activity,
Attribute,
Gender,
lbToKg,
range,
type LevelCalculatorOutput,
type Standards,
type ActivityPerformance,
type Player,
} from "@blade-and-brawn/calculator";
} from "@blade-and-brawn/domain";
interface CalcData {
levels?: LevelCalculatorOutput;
@@ -1,14 +1,16 @@
<script lang="ts">
import {
Standards,
type Standard,
type StandardsConfig,
} from "@blade-and-brawn/calculator";
import {
Activity,
cmToIn,
kgToLb,
range,
type Metrics,
type Standard,
type StandardsConfig,
} from "@blade-and-brawn/calculator";
} from "@blade-and-brawn/domain";
interface Props {
allStandards: Standards;
@@ -1,13 +1,15 @@
<script lang="ts">
import {
Activity,
DEFAULT_STANDARDS_DATA,
Gender,
lbToKg,
Standards,
type Metrics,
type StandardsConfig,
} from "@blade-and-brawn/calculator";
import {
Activity,
Gender,
lbToKg,
type Metrics,
} from "@blade-and-brawn/domain";
import StandardsTable from "$lib/components/StandardsTable.svelte";
import PlayersTable from "$lib/components/PlayersTable.svelte";
@@ -15,6 +17,7 @@
const defaultStandards = new Standards(DEFAULT_STANDARDS_DATA);
// TODO: try to clean this up
let input = $state({
activity: Activity.BenchPress,
metrics: {