import type { FastifyInstance } from "fastify" import fp from "fastify-plugin" import { type FetchFn, MedusaClient } from "../services/medusa-client.js" import { trySync } from "../services/medusa-sync.js" declare module "fastify" { interface FastifyInstance { /** Client Medusa: `medusa.store` (Store API) e `medusa.internal` (route /internal/*). */ medusa: MedusaClient /** * Avvia una sincronizzazione con Medusa senza attenderla (la risposta HTTP non dipende da Medusa). * Gli errori diventano warning nei log; le operazioni in corso vengono attese alla chiusura del server. */ syncInBackground: (what: string, userId: string, fn: () => Promise) => void /** Attende le sincronizzazioni in background in corso (usato da onClose e dai test). */ flushSyncs: () => Promise } } /** Espone il client Medusa come `app.medusa`. `fetch` รจ sostituibile nei test (Medusa mockato). */ export default fp( async function medusaClientPlugin(app: FastifyInstance, opts: { fetch?: FetchFn | undefined }) { app.decorate( "medusa", new MedusaClient({ baseUrl: app.config.MEDUSA_URL, publishableKey: app.config.MEDUSA_PUBLISHABLE_KEY, internalSecret: app.config.INTERNAL_API_SECRET, timeoutMs: app.config.MEDUSA_TIMEOUT_MS, ...(opts.fetch ? { fetch: opts.fetch } : {}), }), ) const pending = new Set>() app.decorate("syncInBackground", (what: string, userId: string, fn: () => Promise) => { const p = trySync(app.log, what, userId, fn).finally(() => pending.delete(p)) pending.add(p) }) app.decorate("flushSyncs", async () => { while (pending.size > 0) await Promise.allSettled([...pending]) }) app.addHook("onClose", async () => { await app.flushSyncs() }) }, { name: "medusa-client", dependencies: ["config"] }, )