Services refactor

This commit is contained in:
Dominic Ferrando
2026-06-23 15:36:53 -04:00
parent 5bae0f067d
commit 720aa61c66
6 changed files with 502 additions and 638 deletions
+21 -9
View File
@@ -1,7 +1,7 @@
import {
PrintfulService,
SyncService,
WebflowService,
PrintfulClient,
ProductSyncer,
WebflowClient,
} from "@blade-and-brawn/commerce";
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -25,23 +25,35 @@ const validateEquality = (wValue: any, pValue: any): Validation => {
return validation;
};
const wProducts = await WebflowService.Products.getAll();
const printful = new PrintfulClient({
token: Bun.env.PRINTFUL_AUTH!,
storeId: Bun.env.PRINTFUL_STORE_ID!,
});
const webflow = new WebflowClient({
siteId: Bun.env.WEBFLOW_SITE_ID!,
collectionsId: Bun.env.WEBFLOW_COLLECTION_ID!,
token: Bun.env.WEBFLOW_AUTH!,
webhookSecret: Bun.env.WEBFLOW_WEBHOOK_SECRET!,
});
const syncer = new ProductSyncer(printful, webflow);
const wProducts = await webflow.Products.getAll();
let invalidCount = 0;
for (const wProduct of wProducts) {
for (const sku of wProduct.skus ?? []) {
console.log("Webflow: " + sku.id, sku.fieldData.name);
const pVariant = await PrintfulService.Products.Variants.get(
`@${sku.id}`,
);
const pVariant = await printful.Products.Variants.get(`@${sku.id}`);
if (pVariant) {
console.log("Printful: " + pVariant.id, pVariant.name);
const validations = [
// validateEquality(sku.fieldData.name, pVariant.name),
validateEquality(
sku.fieldData["sku-values"]?.["color"],
SyncService.findColorInProductName(pVariant.name),
syncer.findColorInProductName(pVariant.name),
),
validateEquality(
sku.fieldData["sku-values"]?.["size"],
@@ -55,7 +67,7 @@ for (const wProduct of wProducts) {
// if (!validateEquality(sku.fieldData.name, pVariant.name).isValid) {
// sku.fieldData.name = pVariant.name;
// await WebflowService.Products.Skus.update(wProduct.product.id, sku.id, sku);
// await webflow.Products.Skus.update(wProduct.product.id, sku.id, sku);
// }
const errors = validations.filter((v) => !v.isValid);
+37 -22
View File
@@ -11,9 +11,9 @@ import {
import { cors } from "@elysiajs/cors";
import { Elysia, NotFoundError, status } from "elysia";
import {
PrintfulService,
SyncService,
WebflowService,
PrintfulClient,
ProductSyncer,
WebflowClient,
Printful,
Webflow,
FetchError,
@@ -21,10 +21,28 @@ import {
import zipcodesUs from "zipcodes-us";
import z from "zod";
// SERVICES
// -----------
const levelCalculator = new LevelCalculator(
new Standards(DEFAULT_STANDARDS_DATA),
);
const printful = new PrintfulClient({
token: Bun.env.PRINTFUL_AUTH!,
storeId: Bun.env.PRINTFUL_STORE_ID!,
});
const webflow = new WebflowClient({
siteId: Bun.env.WEBFLOW_SITE_ID!,
collectionsId: Bun.env.WEBFLOW_COLLECTION_ID!,
token: Bun.env.WEBFLOW_AUTH!,
webhookSecret: Bun.env.WEBFLOW_WEBHOOK_SECRET!,
});
const productSyncer = new ProductSyncer(printful, webflow);
// ELYSIA
// -----------
export const app = new Elysia()
.use(
cors({
@@ -105,42 +123,39 @@ export const app = new Elysia()
.group("/sync", (app) =>
app
// Sync status
.get("/", async ({ }) => await SyncService.getState())
.get("/", async ({ }) => await productSyncer.getState())
// Full sync
.post("/", async ({ }) => {
const syncState = await SyncService.getState();
const syncState = await productSyncer.getState();
if (syncState.isSyncing)
return status(409, { error: "Sync already in progress" });
await SyncService.sync();
await productSyncer.sync();
return { ok: true };
})
// Per-product sync
.post("/:printfulProductId", async ({ params }) => {
const syncState = await SyncService.getState();
const syncState = await productSyncer.getState();
if (syncState.isSyncing)
return status(409, { error: "Sync already in progress" });
await SyncService.sync(params.printfulProductId);
await productSyncer.sync(params.printfulProductId);
return { ok: true };
}, { params: z.object({ printfulProductId: z.number() }) }),
)
// TODO: add schema validation
.get("/:printfulProductId", async ({ params }) => {
const printfulProductId = +params.printfulProductId;
const printfulProduct =
await PrintfulService.Products.get(printfulProductId);
if (!printfulProduct) {
return new NotFoundError();
}
await printful.Products.get(printfulProductId);
if (!printfulProduct) return new NotFoundError();
const webflowProductId =
printfulProduct.sync_product.external_id.split("-")[0];
if (!webflowProductId) {
return new NotFoundError();
}
if (!webflowProductId) return new NotFoundError();
const webflowProduct =
await WebflowService.Products.get(webflowProductId);
await webflow.Products.get(webflowProductId);
return { printfulProduct, webflowProduct };
}),
@@ -153,11 +168,11 @@ export const app = new Elysia()
switch (payload.type) {
case Printful.Webhook.Event.ProductUpdated: {
const printfulProduct = payload.data.sync_product;
await SyncService.sync(printfulProduct.id);
await productSyncer.sync(printfulProduct.id);
break;
}
case Printful.Webhook.Event.ProductDeleted: {
await WebflowService.Products.remove(
await webflow.Products.remove(
payload.data.sync_product.external_id,
);
break;
@@ -166,12 +181,12 @@ export const app = new Elysia()
const webflowOrderId = payload.data.order.external_id;
const shipInfo = payload.data.shipment;
await WebflowService.Orders.update(webflowOrderId, {
await webflow.Orders.update(webflowOrderId, {
shippingTrackingURL: shipInfo.tracking_url,
shippingTracking: shipInfo.tracking_number,
shippingProvider: shipInfo.carrier,
});
await WebflowService.Orders.fulfill(webflowOrderId, {
await webflow.Orders.fulfill(webflowOrderId, {
sendOrderFulfilledEmail: true,
});
break;
@@ -181,7 +196,7 @@ export const app = new Elysia()
return { ok: true };
})
.post("/webhook/webflow", async ({ request, body, set }) => {
if (!WebflowService.Util.verifyWebflowSignature(request, body)) {
if (!webflow.Util.verifyWebflowSignature(request, body)) {
set.status = 400;
return "Invalid signature";
}
@@ -192,7 +207,7 @@ export const app = new Elysia()
case Webflow.Webhook.Event.OrderCreated: {
const webflowOrder = payload.payload;
await PrintfulService.Orders.create({
await printful.Orders.create({
external_id: webflowOrder.orderId,
// TODO: derive from webflow
shipping: "STANDARD",
@@ -1,11 +1,27 @@
import { PrintfulService, WebflowService } from "@blade-and-brawn/commerce";
import { PrintfulClient, WebflowClient } from "@blade-and-brawn/commerce";
import {
PRINTFUL_AUTH,
PRINTFUL_STORE_ID,
WEBFLOW_SITE_ID,
WEBFLOW_COLLECTION_ID,
WEBFLOW_AUTH,
WEBFLOW_WEBHOOK_SECRET,
} from "$env/static/private";
import type { PageServerLoad } from "./$types";
const printful = new PrintfulClient({ token: PRINTFUL_AUTH, storeId: PRINTFUL_STORE_ID });
const webflow = new WebflowClient({
siteId: WEBFLOW_SITE_ID,
collectionsId: WEBFLOW_COLLECTION_ID,
token: WEBFLOW_AUTH,
webhookSecret: WEBFLOW_WEBHOOK_SECRET,
});
export const load = async ({}: Parameters<PageServerLoad>[0]) => {
return {
products: {
printful: PrintfulService.Products.getAll(),
webflow: WebflowService.Products.getAll(),
printful: printful.Products.getAll(),
webflow: webflow.Products.getAll(),
},
};
};