Restructure services

This commit is contained in:
Dominic Ferrando
2026-07-04 00:51:42 -04:00
parent 2eea7216d6
commit d042340c8b
4 changed files with 50 additions and 46 deletions
+18 -39
View File
@@ -1,9 +1,3 @@
import {
DEFAULT_STANDARDS_DATA,
LevelCalculator,
Standards,
} from "@blade-and-brawn/calculator";
import {
ActivityPerformanceSchema,
PlayerSchema,
@@ -11,9 +5,7 @@ import {
import { cors } from "@elysiajs/cors";
import { Elysia, NotFoundError, status, t } from "elysia";
import {
PrintfulClient,
PrintfulError,
WebflowClient,
WebflowError,
Printful,
Webflow,
@@ -22,29 +14,16 @@ import zipcodesUs from "zipcodes-us";
import { env, log } from "./util";
import serverTiming from "@elysia/server-timing";
import jwt from "@elysia/jwt";
import { SyncService } from "./services/sync";
import { CommerceService } from "./services/commerce";
import cluster from "node:cluster";
import { randomUUIDv7 } from "bun";
import { CalculatorService } from "./services/calculator";
// SERVICES
// -----------
const levelCalculator = new LevelCalculator(
new Standards(DEFAULT_STANDARDS_DATA),
);
const printful = new PrintfulClient({
token: env.PRINTFUL_AUTH,
storeId: env.PRINTFUL_STORE_ID,
});
const webflow = new WebflowClient({
siteId: env.WEBFLOW_SITE_ID,
collectionsId: env.WEBFLOW_COLLECTION_ID,
token: env.WEBFLOW_AUTH,
webhookSecret: env.WEBFLOW_WEBHOOK_SECRET,
});
const syncService = new SyncService(printful, webflow);
const calculatorService = new CalculatorService();
const commerceService = new CommerceService();
// ELYSIA
// -----------
@@ -122,7 +101,7 @@ export const app = new Elysia()
.group("/calculator",
(app) => app
.post("/calculate", async ({ body }) => {
return { levels: levelCalculator.calculate(body.player, body.activityPerformances) };
return { levels: calculatorService.calculate(body.player, body.activityPerformances) };
}, {
body: t.Object({
player: PlayerSchema,
@@ -150,17 +129,17 @@ export const app = new Elysia()
app
// Sync status
.get("/", async ({ sessionId }) => {
const latestSync = await syncService.getLatestSync(sessionId);
const latestSync = await commerceService.getLatestSync(sessionId);
if (!latestSync) throw new NotFoundError("No sync found");
return {
startDate: latestSync.started_at,
status: syncService.deriveSyncStatus(latestSync),
status: commerceService.deriveSyncStatus(latestSync),
syncingPrintfulProductIds: latestSync.syncing_printful_product_ids
}
})
// Run sync
.post("/:printfulProductId?", async ({ params: { printfulProductId }, sessionId }) => {
await syncService.sync({
await commerceService.sync({
session: { id: sessionId, name: "Portal" },
filter: {
printfulProductIds: printfulProductId ? [printfulProductId] : null
@@ -169,13 +148,13 @@ export const app = new Elysia()
}, { params: t.Object({ printfulProductId: t.Optional(t.Numeric()) }) }),
)
.get("/:printfulProductId", async ({ params }) => {
const printfulProduct = await printful.Products.get(params.printfulProductId);
const printfulProduct = await commerceService.printful.Products.get(params.printfulProductId);
if (!printfulProduct) throw new NotFoundError("Missing printful product");
const webflowProductId = printfulProduct.sync_product.external_id.split("-")[0];
if (!webflowProductId) throw new NotFoundError("Missing webflow product ID");
const webflowProduct = await webflow.Products.get(webflowProductId);
const webflowProduct = await commerceService.webflow.Products.get(webflowProductId);
return { printfulProduct, webflowProduct };
}, {
@@ -193,7 +172,7 @@ export const app = new Elysia()
const printfulProduct = payload.data.sync_product;
log.info({ productId: printfulProduct.id }, "printful webhook: product updated");
await syncService.sync({
await commerceService.sync({
session: { id: randomUUIDv7(), name: "Printful" },
filter: {
printfulProductIds: [printfulProduct.id]
@@ -207,7 +186,7 @@ export const app = new Elysia()
log.info({ externalId: payload.data.sync_product.external_id, webflowProductId }, "printful webhook: product deleted");
if (!webflowProductId) throw new NotFoundError("Missing webflow product ID");
await webflow.Products.remove(webflowProductId);
await commerceService.webflow.Products.remove(webflowProductId);
break;
}
case Printful.Webhook.Event.PackageShipped: {
@@ -215,12 +194,12 @@ export const app = new Elysia()
const shipInfo = payload.data.shipment;
log.info({ webflowOrderId, carrier: shipInfo.carrier, tracking: shipInfo.tracking_number }, "printful webhook: package shipped");
await webflow.Orders.update(webflowOrderId, {
await commerceService.webflow.Orders.update(webflowOrderId, {
shippingTrackingURL: shipInfo.tracking_url,
shippingTracking: shipInfo.tracking_number,
shippingProvider: shipInfo.carrier,
});
await webflow.Orders.fulfill(webflowOrderId, {
await commerceService.webflow.Orders.fulfill(webflowOrderId, {
sendOrderFulfilledEmail: true,
});
break;
@@ -230,7 +209,7 @@ export const app = new Elysia()
}
})
.post("/webhook/webflow", async ({ request, body }) => {
if (!webflow.Util.verifyWebflowSignature(request, body))
if (!commerceService.webflow.Util.verifyWebflowSignature(request, body))
throw status(400, "Invalid signature");
const payload = body as Webflow.Webhook.EventPayload;
@@ -240,7 +219,7 @@ export const app = new Elysia()
const webflowOrder = payload.payload;
log.info({ orderId: webflowOrder.orderId }, "webflow webhook: order created");
await printful.Orders.create({
await commerceService.printful.Orders.create({
external_id: webflowOrder.orderId,
// TODO: derive from webflow
shipping: "STANDARD",
@@ -273,8 +252,8 @@ app.listen(3000, async () => {
log.info({ port: 3000 }, "server started")
try {
const frontQueuedSync = await syncService.queue.front();
if (frontQueuedSync) await syncService.sync(frontQueuedSync);
const frontQueuedSync = await commerceService.queue.front();
if (frontQueuedSync) await commerceService.sync(frontQueuedSync);
}
catch (err) {
log.error({ err }, "failed to resume product sync queue")