{"version":3,"sources":["../src/index.ts","../src/polly-plugin.ts"],"sourcesContent":["export { polly } from './polly-plugin';\n","import type { FastifyRequest, FastifyReply } from 'fastify';\nimport type { IPolicy } from 'polly-ts-core';\n\n/**\n * Creates a Fastify hook handler that applies a Polly policy.\n * Usage: fastify.addHook('onRequest', polly(policy));\n *\n * @param policy The policy to apply (CircuitBreaker, Bulkhead, etc.)\n * @returns A Fastify hook handler.\n */\nexport function polly(\n  policy: IPolicy,\n): (request: FastifyRequest, reply: FastifyReply) => Promise<void> {\n  return async (request: FastifyRequest, reply: FastifyReply): Promise<void> => {\n    let gateResolve: () => void;\n    let gateReject: (reason?: unknown) => void;\n    let gateOpened = false;\n\n    const gatePromise = new Promise<void>((resolve, reject) => {\n      gateResolve = (): void => {\n        if (!gateOpened) {\n          gateOpened = true;\n          resolve();\n        }\n      };\n      gateReject = (reason): void => {\n        if (!gateOpened) {\n          gateOpened = true;\n          reject(reason instanceof Error ? reason : new Error(String(reason)));\n        }\n      };\n    });\n\n    const waitForResponse = new Promise<void>((resolve, reject) => {\n      const onFinish = (): void => {\n        cleanup();\n        if (reply.raw.statusCode >= 500) {\n          // Rejecting this promise causes the policy checks to fail\n          reject(new Error(`HTTP ${String(reply.raw.statusCode)}`));\n        } else {\n          resolve();\n        }\n      };\n\n      const onError = (err: Error): void => {\n        cleanup();\n        reject(err);\n      };\n\n      const onClose = (): void => {\n        cleanup();\n        resolve();\n      };\n\n      const cleanup = (): void => {\n        reply.raw.removeListener('finish', onFinish);\n        reply.raw.removeListener('error', onError);\n        reply.raw.removeListener('close', onClose);\n      };\n\n      reply.raw.on('finish', onFinish);\n      reply.raw.on('error', onError);\n      reply.raw.on('close', onClose);\n    });\n\n    // eslint-disable-next-line @typescript-eslint/no-empty-function -- intentional no-op to suppress unhandled rejection\n    waitForResponse.catch(() => {});\n    const executionPromise = policy.execute(async (context) => {\n      (request.raw as FastifyRequest['raw'] & { signal?: AbortSignal }).signal = context.signal;\n\n      gateResolve();\n\n      await waitForResponse;\n    });\n\n    executionPromise.catch((err: unknown) => {\n      if (!gateOpened) {\n        gateReject(err);\n      }\n    });\n\n    await gatePromise;\n  };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUO,SAAS,MACd,QACiE;AACjE,SAAO,OAAO,SAAyB,UAAuC;AAC5E,QAAI;AACJ,QAAI;AACJ,QAAI,aAAa;AAEjB,UAAM,cAAc,IAAI,QAAc,CAAC,SAAS,WAAW;AACzD,oBAAc,MAAY;AACxB,YAAI,CAAC,YAAY;AACf,uBAAa;AACb,kBAAQ;AAAA,QACV;AAAA,MACF;AACA,mBAAa,CAAC,WAAiB;AAC7B,YAAI,CAAC,YAAY;AACf,uBAAa;AACb,iBAAO,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC,CAAC;AAAA,QACrE;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,kBAAkB,IAAI,QAAc,CAAC,SAAS,WAAW;AAC7D,YAAM,WAAW,MAAY;AAC3B,gBAAQ;AACR,YAAI,MAAM,IAAI,cAAc,KAAK;AAE/B,iBAAO,IAAI,MAAM,QAAQ,OAAO,MAAM,IAAI,UAAU,CAAC,EAAE,CAAC;AAAA,QAC1D,OAAO;AACL,kBAAQ;AAAA,QACV;AAAA,MACF;AAEA,YAAM,UAAU,CAAC,QAAqB;AACpC,gBAAQ;AACR,eAAO,GAAG;AAAA,MACZ;AAEA,YAAM,UAAU,MAAY;AAC1B,gBAAQ;AACR,gBAAQ;AAAA,MACV;AAEA,YAAM,UAAU,MAAY;AAC1B,cAAM,IAAI,eAAe,UAAU,QAAQ;AAC3C,cAAM,IAAI,eAAe,SAAS,OAAO;AACzC,cAAM,IAAI,eAAe,SAAS,OAAO;AAAA,MAC3C;AAEA,YAAM,IAAI,GAAG,UAAU,QAAQ;AAC/B,YAAM,IAAI,GAAG,SAAS,OAAO;AAC7B,YAAM,IAAI,GAAG,SAAS,OAAO;AAAA,IAC/B,CAAC;AAGD,oBAAgB,MAAM,MAAM;AAAA,IAAC,CAAC;AAC9B,UAAM,mBAAmB,OAAO,QAAQ,OAAO,YAAY;AACzD,MAAC,QAAQ,IAAyD,SAAS,QAAQ;AAEnF,kBAAY;AAEZ,YAAM;AAAA,IACR,CAAC;AAED,qBAAiB,MAAM,CAAC,QAAiB;AACvC,UAAI,CAAC,YAAY;AACf,mBAAW,GAAG;AAAA,MAChB;AAAA,IACF,CAAC;AAED,UAAM;AAAA,EACR;AACF;","names":[]}