diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index eb9ba36..cbc914c 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -101,9 +101,7 @@ export const app = new Elysia() }) .onAfterResponse(({ request, status, path }) => { - const skip: Record = { - "/products/sync/": ["GET"] - }; + const skip: Record = { "/products/sync/": ["GET"] }; if (env.NODE_ENV === "development" && skip[path]?.includes(request.method)) return; log.info({ @@ -165,16 +163,12 @@ export const app = new Elysia() state: await productSyncer.getState(), isRunning: await productSyncer.isRunning() })) - // Full sync - .post("/", async ({ }) => { - if (!await productSyncer.sync()) - throw status(409, "Sync already in progress"); - }) - // Per-product sync - .post("/:printfulProductId", async ({ params }) => { - if (!await productSyncer.sync({ printfulProductIdsFilter: [params.printfulProductId] })) - throw status(409, "Sync already in progress"); - }, { params: t.Object({ printfulProductId: t.Numeric() }) }), + // Run sync + .post("/:printfulProductId?", async ({ params: { printfulProductId } }) => { + log.debug({ printfulProductId }); + const canSync = await productSyncer.sync({ filter: { printfulProductIds: printfulProductId } }); + if (!canSync) throw status(409, "Sync already in progress"); + }, { params: t.Object({ printfulProductId: t.Optional(t.Numeric()) }) }), ) .get("/:printfulProductId", async ({ params }) => { const printfulProduct = await printful.Products.get(params.printfulProductId); @@ -200,7 +194,7 @@ export const app = new Elysia() case Printful.Webhook.Event.ProductUpdated: { const printfulProduct = payload.data.sync_product; log.info({ productId: printfulProduct.id }, "printful webhook: product updated"); - await productSyncer.sync({ printfulProductIdsFilter: [printfulProduct.id] }); + await productSyncer.sync({ filter: { printfulProductIds: printfulProduct.id } }); break; } case Printful.Webhook.Event.ProductDeleted: { diff --git a/apps/portal/src/routes/(app)/commerce/+page.svelte b/apps/portal/src/routes/(app)/commerce/+page.svelte index 71fef7c..ac32768 100644 --- a/apps/portal/src/routes/(app)/commerce/+page.svelte +++ b/apps/portal/src/routes/(app)/commerce/+page.svelte @@ -28,7 +28,7 @@ }, sync: async (printfulProductId: number) => { synchronizer.startPolling(); - await api.products.sync.post({ printfulProductId }); + await api.products.sync({ printfulProductId }).post(); }, }); diff --git a/packages/commerce/src/sync.ts b/packages/commerce/src/sync.ts index 70b3d61..268f5f0 100644 --- a/packages/commerce/src/sync.ts +++ b/packages/commerce/src/sync.ts @@ -23,7 +23,9 @@ type SyncState = { }; type SyncOptions = { - printfulProductIdsFilter?: number[]; + filter?: { + printfulProductIds?: number[] | number; + } }; export class ProductSyncer { @@ -38,14 +40,17 @@ export class ProductSyncer { } async sync(opt: SyncOptions = {}): Promise { + if (typeof opt.filter?.printfulProductIds === "number") + opt.filter.printfulProductIds = [opt.filter.printfulProductIds]; + this.log.info("attempting sync run"); const canRun = await this.run(); if (!canRun) return false; try { const syncStart = Date.now(); - if (opt.printfulProductIdsFilter) - this.log.info({ printfulProductIds: opt.printfulProductIdsFilter }, "sync started (filtered)"); + if (opt.filter?.printfulProductIds) + this.log.info({ printfulProductIds: opt.filter.printfulProductIds }, "sync started (filtered)"); else this.log.info("sync started (all)"); @@ -55,8 +60,8 @@ export class ProductSyncer { this.log.debug("retrieving printful products"); const allPrintfulProducts = await this.printful.Products.list({ forceAll: true }); - this.log.info({ printfulProductCount: allPrintfulProducts.length, filter: opt.printfulProductIdsFilter ?? "N/A" }, "generating meta printful products"); - const metaPrintfulProducts = await this.generateMetaPrintfulProducts(allWebflowProducts, allPrintfulProducts, opt.printfulProductIdsFilter); + this.log.info({ printfulProductCount: allPrintfulProducts.length, filter: opt.filter ?? "N/A" }, "generating meta printful products"); + const metaPrintfulProducts = await this.generateMetaPrintfulProducts(allWebflowProducts, allPrintfulProducts, opt); for (const metaPrintfulProduct of metaPrintfulProducts) { this.log.info({ name: metaPrintfulProduct.name, externalId: metaPrintfulProduct.webflowProductId }, "syncing meta printful product"); @@ -266,9 +271,12 @@ export class ProductSyncer { async generateMetaPrintfulProducts( allWebflowProducts: Webflow.Products.ProductAndSkus[], allPrintfulProducts: Printful.Products.SyncProduct[], - printfulProductIdsFilter?: number[], + opt: SyncOptions, ) { - const metaNameFilter = printfulProductIdsFilter + if (typeof opt.filter?.printfulProductIds === "number") + opt.filter.printfulProductIds = [opt.filter.printfulProductIds]; + + const metaNameFilter = opt.filter?.printfulProductIds ?.map((id) => allPrintfulProducts.find((p) => p.id === id)) ?.filter((p) => p !== undefined) ?.map((p) => this.getMetaPrintfulProductName(p));