{"_id":"express-idempotency","_rev":"14-a684698de2c874db7d01645854f56214","name":"express-idempotency","dist-tags":{"rc":"1.0.6-rc.2","latest":"2.1.0"},"versions":{"1.0.0-rc.1":{"name":"express-idempotency","version":"1.0.0-rc.1","author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.0-rc.1","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotencyy","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"063509f09002bec11f7b33785beb4721bc0ad62e","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.0-rc.1.tgz","fileCount":17,"integrity":"sha512-Pm1HaN6vEltp5+M0nj0eAEu1dVvNCQl368kJEa+ylyL9wyacAvrsBYWqH7VCb0N5D9jsdBkZKax8pAfLzG2/ZQ==","signatures":[{"sig":"MEUCIQDn9WZZBreE8xiH1nZ0aF1XkRmiNBDhMADd+hERJSh+nQIgT/dR3x2Bz4nwMJTcrwGF0pkWp8K6UF4FUV/37iv3Nk4=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":41022,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe5sfyCRA9TVsSAnZWagAAo4cP/0hT73eqSdkC1Emym4JO\nHymtd20lJ7TstEtcQb3ADGFlSBMk+il9XmyvllLPe8muoXTS+Qn1hzK8unNs\noIQbbpA+LMOQ2jdof05pxpvk7bvJ427qQSEX8+C2/xBivbmqygzYnNfZUS+n\nKDXjuQ1+GK0O0kmKr7N5AEKM4zx0L3kY++xkvkpabW8er7J/hA3JpHxX7jIc\nyxVFoWOzVf0/JrIQY0/gJVi/ewkcgXd30cOyfMBCpjSZoBHtGEyaqpakZgaA\nf9r69b/mLXJ03HCR2oNJr72CklQp5Sw5hp2qOna8eHKj06WciP14SbUFCNOe\nzQJ8GvM2BmZff9K4lEZHV3yjEfkC3cH87X8jvA4yWOq8+bfTgpebiAqI/cGI\nvm1FBK1FDmNNlmmdJ5GO8ndMAm1aNLjkjKvb2PxqbRlwkkY2pGhno3wWjMM9\nUX5IOMM4xyZt4LZdkJTVy76yF1fzY9BQfXfBSv7Mma0aPRXQfWxXv5e1loCn\nkOVAHpSgHXbMBeVubgTr4Fxno6YViK06nNYeHx7aQaJqchzNiSQKz/qyk9ka\nYtsWlUjriUT2N062HhTh3c4QDwD/cRQOTNLrJmOnvFU63+JVpWp2gjFz5iQB\nnXHC7V//CIil41FgfOEKyZ6lS7wKxYrGDpQIw9/Hs38jHaQYYKc97Kl6OM2m\nQj7E\r\n=Lvq9\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"c339c0f7bfa9959491414e75dfa59a551fe50a76","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"6.14.5","description":"[![CircleCI](https://circleci.com/gh/VilledeMontreal/express-idempotency/tree/master.svg?style=shield)](https://circleci.com/gh/VilledeMontreal/express-idempotency/tree/master) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/958bd19185f44fcda6","directories":{},"_nodeVersion":"14.4.0","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.6","@commitlint/cli":"^8.3.5","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","autobind-decorator":"^2.4.0","source-map-support":"^0.5.19","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^8.3.4","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.0-rc.1_1592182770199_0.4865769900549577","host":"s3://npm-registry-packages"}},"1.0.1":{"name":"express-idempotency","version":"1.0.1","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.1","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotencyy","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"e020aafeddf4ccec2fa5c3d2b1253b05789cba0c","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.1.tgz","fileCount":17,"integrity":"sha512-E2vFip1p1l2GzIiqthSpQJ3qJLcdYLNehP+0/g0R9BakmunyilanFATbt6J9jdogkhUiFnfqgRfOilWOlPE9Kw==","signatures":[{"sig":"MEQCIAMnRpe6/R546a8/Mpw7jXoQlkYn4JWLN9+/7uKGtZoiAiBTQOgVaBUOmGl+SzMjMFvqSorPHIjwsOGtWjxl5IxAaA==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":41182,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe5tkrCRA9TVsSAnZWagAALXYP/0vH5VEq/MEZDpzTElwc\nPwSQViSLCfPSBBl/6hOKGeVHT9NHCLRvMjxyLWzcs8ugO646PR5iNs4IKQJC\n4na7x9La6t6muypRWi81X2AwXSu/Jsf9/ozAXhQ4xS6WbumxFvmkGiC+N9VQ\nQJS4x0oG51yYdqAJwR4v0eWw9CKViuB4y5T0z8Od+d82qQ/MhYsZlDhj4bfh\nXI8Q5J5RZAg0HKRS5reNOGncePw1Lb3yVJ9zcuTzpnDBs7+nlh32kwIyJ4M1\nK18Pas36apbh0gM1uPcx8sQvgb0+NEi71nm/AtcI6LOtU5aGlZX+hVFvYuc8\nHQk85Gi7RdnxVah5/f+LXuk963xSbBWmrCERByZ5P959+WJE+Zgl1TIyub+o\noQJWn1AXBFoX7yRMBptcvYE6rOhspfiHAANYKyNhF0DLCA8K2tqMsp8RXBZM\nlZ9BgdVigAKTJl3S0Lx7M+C+bs17xmP8PtBSvsRQFX0qI8JGqour1qzpLFmg\n9aF4ORY4VbE8+22fMyer1qZ8Tf/WRZIMd3VkX7IeKJTNobI34fNjOSdaVAxG\nL+2B7LL9jGEqBkYGXgHATo9lQNM8Tk6+h0zElzDjWEMsgo6xuArJsFuCnGqe\nDILTJvqYUU/3dWvSmcA2PrUT1+gOUp9Kg0QN3Z5AC8nFaFHbeaEYzWp9QP5E\n8gMj\r\n=aflV\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"e59dcae5eacb541bad7db31b6ef864836f198742","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"6.14.5","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"14.4.0","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.6","@commitlint/cli":"^8.3.5","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","autobind-decorator":"^2.4.0","source-map-support":"^0.5.19","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^8.3.4","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.1_1592187178898_0.43106514686126896","host":"s3://npm-registry-packages"}},"1.0.2":{"name":"express-idempotency","version":"1.0.2","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.2","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotencyy","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"64558be29ff30cef214ea6c9dff041bba92bcc14","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.2.tgz","fileCount":17,"integrity":"sha512-dj2ROCk2/15jJFSoLCPlzGuSn0zZMNmTiwVVnoalCDpVujNMLgxtDNpkp/UN3W8/Msk7KEgtqIXmButD5rUo9A==","signatures":[{"sig":"MEQCIQD6hVduCxvJnSwFIKc9iRHntt2OOQphCCqV4IcvbFYGKgIfYynFvNwgNk1Uz3kq8ECIYu1y9CEotAtjrkQRTtV2Yg==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":41618,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe53f3CRA9TVsSAnZWagAA1M4P/jrEIFGlMgxF+Zfz/gyc\n5EHi2a85a0cLwr2581y9q8z6e3enyXeLSk++i9N3KGXU4Pkx1Zw+iMgzOS5p\nP+4u2Dbx6hnfyzQzL8qaEkHOyVdVQOeoYIkejz27fZdsrKIrQCney8QEjZhf\nGT8JqWS9TW1Hw49ssMB2V1royhppdxN7//pTCAhQyJOqOHrZHyY/wcaeAedd\ns7B8GJM1jKFcaG1VE1zOXMxgMTT9roHWuU39hK2S9f0XI2gOzQQmbppjOQOT\n6/XVIIW0Qdhe7ByIdoegeFk3palPAkDLjWvUooMc4/Fl3OaT2zoSWB4sjUnI\n61Mc1vsrf/erMKkEX91Wk8klQ1BA2YvyALQv3SEy6OHZO/i1rdxfkfsomNAd\nmeG/wWwMoYhYfYpW333hZityfx/7l1jPqg/B+bbOIX+iUboXvG5yGWqmNVbF\nbKRWNziL/g33UCOO6hC+YpMm2xqg+hibi5yeA1oyeJDwlnQ+PRB609zYwwru\nbdUtTviAezV4AI1T5yEpXc1k5hpyyjHkHfmnE9U+0w9gTZjXLn+IRuS7G5wz\n6PDLu6GSzhWhZnAqjIdqRER+RCgP5/tm1hVcFsMHFIi76nnCFgunZg4u6lto\nCFbSYu3si7pOPnp9DLVBV2lXMC+h8F9/cCZ299gvYQdLIt8ze7NCydH1nmi0\nXqt9\r\n=c2sd\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"9922b0cd3521ae4b7ed4d3f8754cbae7c8ce135d","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"6.14.5","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"14.4.0","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.6","@commitlint/cli":"^8.3.5","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","autobind-decorator":"^2.4.0","source-map-support":"^0.5.19","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^8.3.4","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.2_1592227831449_0.7822376443501211","host":"s3://npm-registry-packages"}},"1.0.3":{"name":"express-idempotency","version":"1.0.3","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.3","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotency","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"df6cda853ccf15ff7023c69a5d0f05e5eddce3b3","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.3.tgz","fileCount":18,"integrity":"sha512-cG9m3emKYozfsKuKgrI8I6Pz3Dr0iUvlXysW2X8sGgz5AgwQQwy50nas0XeD6qcJOEoSjwnmfUH4DSF+JsShZw==","signatures":[{"sig":"MEUCIQD8wY4XxlnCaLgdxR5rP8rptWm8Jf+48//JObIF+0H6AgIgcNq3BYXjlmFOJaQfBN8SLsDsoz559NZFM4JwXBLbjGk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":43675,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfifa2CRA9TVsSAnZWagAAYiMP/jXjGr4A924+QdarwNA/\ncGWe0gCpWvxYvQyU7BQ3G5b3cFrv0Lwq5Mxo1hzmD7UN5UWKeBxsKD8GRoXA\n8cTnYiqItKMf/Qz/2VxBnsJ6gQeO87V6DZAcfYkFbjpQZtwOIYV0LqtWc8iH\nc+WCc+RZo/8GTzc859DZgZ2Zxz2HbAz4i69XPYMloL3O662pzFWcS6Z4z/P6\nVz2nPwmNG0SrMHkCKQpbPC7ttZNPhkgflaNIxh9MeI0PhYiuLTq1RD9NQjeI\nmUgx1/SwZWDDQ62ESP+bDcNn4wkOJgCXqHmU2q7TPPqqttsO/Q+HHpVdjPmx\nNxLINW89FhpLUi2cLuxD3oRDZKejhcf84R5tBwQV1B3bwthnzZ7V8pVJGtdb\nReY2C0Piv8KKvqtfp1iBvP2wfJc9kymArKXdccCyxTelIxLrXQbzFQUunvIQ\n3w0jOKv7TU+FydvHxKQdgcEFB68B2p99cbGhmER7GluT5prB6FJRp+ZhynBY\n9jEn1QSO4oefWAgMLGLUBS4JIO25viQxEJWIcQrpq4dir088u7cGXunVEtDB\ny3MH7xU0wgmDIzmvSi4hMC5hGgk58jENRJW54hOOADUJAbk9V2LNJvMxh5OW\nXE8BeL+LbGanzNC6HcJHii3E81aZItoQKSfcjocDm12AXEgcJBSzmJQmA08L\nznvu\r\n=cIZo\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"6b7ca47d2795c68992ed4e96a94202dc31dc7281","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"6.14.8","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"14.13.1","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0","autobind-decorator":"^2.4.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.6","@commitlint/cli":"11.0.0","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","source-map-support":"^0.5.19","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^11.0.0","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.3_1602877110128_0.6485458829572421","host":"s3://npm-registry-packages"}},"1.0.4":{"name":"express-idempotency","version":"1.0.4","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.4","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotency","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"346abc704e548587844eca1a1e7e3ccf01865ac5","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.4.tgz","fileCount":18,"integrity":"sha512-41BdiTcKD7g0wtWUQWR9GyiBLr53r7a7bjxFR4y6HwSFzPpcJAGMKR3NoDCIVW00CTX+IqD1tlkegh6uhQE0Yw==","signatures":[{"sig":"MEUCIHMxZ+YHeSTfg26yXHFSw71lbmlcVEHaziKmBiDCXjfeAiEAl5uORPj2GYbW2pGViK/VMMKl7uL6wkKslL53kMlIu3I=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":44007,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgpA8fCRA9TVsSAnZWagAA/AYP/RudbTLZ18KroO4TnZYZ\nVDmsaCmpNXHk2Q8KmFPbQmm8NyvQD0N8hRpUo5An+FBLfgcFRpE7C6lGsO3C\nt9FdL4sBfDMG/kCy065tAFDFMuLVc7V1UdSajlVF25YvlMEYTJhkDz9Ouvsp\np0Mfh3DMJCbVYzKjmu9cmIYDypuT/eJg3WczsvF9EYaS+Y/7nnDZ7DkT35oa\nlCCcUo9UcrJXHMm3sdhQ+aeluDbaGfnvwU4rqfgbv/FgpEvTisbncpjzoMKf\novLzo+Sv0xDB8e6ItryCMxaxR4YIvxrXvkU87fWFadXDw0AT44yQWTKSBHaO\n39bb3Op5pdM/CR1F3oq6Vl7POtUmWvYbjxkWo2ShGRz0LlYfIdEB1qOUVkDB\nL61oPm5iqxgikumHZuPDbm38n6EImyXCd3nt9BbFTkJHRc2A9cFKKer8JnOE\n57j9DIWe87wgXny0IxeN60EGi31EvUACwlubqfnkqwu36o6vohbgAXdpZ1zO\nQ6ghA/uSeyINXJk7vba2nqYVDLmw0vv/gihloWlUNzcSsodaIAc0jL2voUaX\nm66qM3lZy/mJIGJZ0G4lVUIaYtL1oQw+pcRi28XFB7uysn22ZpO+ezT8lPI/\nRJkdowBmjLlka01bL6SRU54aGkiQFCYm4jfXKC6Hzdqp4oDl0dwk0qQ4kF6E\nOQ0d\r\n=4/F3\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"9dd2120e73ee8673c7655a42cbb801790ca616b7","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"7.7.6","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"15.14.0","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0","autobind-decorator":"^2.4.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.11","@commitlint/cli":"^11.0.0","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","source-map-support":"^0.5.19","@types/serve-static":"1.13.9","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^11.0.0","@types/express-serve-static-core":"4.17.19","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.4_1621364511069_0.15294312074890337","host":"s3://npm-registry-packages"}},"1.0.5":{"name":"express-idempotency","version":"1.0.5","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.5","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotency","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"49746c9a6222126d2520ab878b0698164f7bd5f4","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.5.tgz","fileCount":17,"integrity":"sha512-FwSd2SybZ/L/RXyQtGu6imaRqQny5pY4ne96W7kq22fEX6Zc41W/GfHs9vNDaM65eSXg1BRYprqfsT0Kf8ZQdQ==","signatures":[{"sig":"MEUCIGrxtUjkf/zt2cpZkwfvhs4ypeWRlSuh5/hx5MKhvsyrAiEAj8oKy1UQ9Sv2PLq3f7eGqkcT81kEkGoKnPSiEoaIYe0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":43307,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhujj5CRA9TVsSAnZWagAAuWkP/3yjA27vaDGwYl5x717z\nD9YkxkaoNOu6GFa0uMXbMjmd/kRfqgaQwiMaoou6DAcB+/Sto/7GA/lrhk9J\nBybHGqS1t868qLUZzQh4ywQkbFTpVl0O8Oy0oDHYXooub71qSFGsK8DsXyrg\nCApAgdd+o0kUSrqn2UhlvGbJen7buXjYzEvbFDi887BjSjLa13X5PY8BnUh8\nYg0XtZjw34ewKysJyLxGTEnYyD8AN6c1TeCj8Jn4aqVDLIx4WLIR+kLJW8vW\nWVAys9QIjQGHTPgWwh41O6J9Uml6tbQBBHhKFcrC91fx/n/WbVhyw91x2Ato\nfEAzSbQvK6he8pU05eK7rlBTzvrxXUoFc4zT6uIhHQT0nAkVwvTrkbLGufsH\nrt0MTyGFAHT5W+91umef9kg7NyzZrnBXDh8Y/3Qa9CLk3EUW09PWKkkptac8\nK7J5h6cxSsmu1aU4tsQB900ZoCmIqL/nprz79irDzZuXxqODeqDDFvA0aQSN\nNNtvk8W6Gth3Ey0Y0oCAgve5aB7i2btaEFa4alvH7vX+HpLKTi7ZVCUmn4ps\naQ9/AoapCfosYH/dH/hccZFfMCMl1z0tS5zDaxNbkHaRPoz/6l+WSP8Nb96L\nhRuoDR4LLo9ZNffL3D/6UGzTr+ZMDV2S6SvhFerYVwTcan7tRbDDECqDyIrM\nZBzX\r\n=qfFM\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"78cace025981b2f1298b187257c09fcf09ebd74a","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"8.1.2","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"17.1.0","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0","autobind-decorator":"^2.4.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.13","@commitlint/cli":"^11.0.0","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","source-map-support":"^0.5.19","@types/serve-static":"1.13.9","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^11.0.0","@types/express-serve-static-core":"^4.17.26","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.5_1639594233123_0.706256505388845","host":"s3://npm-registry-packages"}},"1.0.6":{"name":"express-idempotency","version":"1.0.6","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.6","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotency","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"f67a3659e9a66014ccb07840a699a66c67768ecd","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.6.tgz","fileCount":17,"integrity":"sha512-cSQn9K0K2GcRAvIyzSSP/sUJMhjL7SPTT8thIyKbXC+FZv9scGRoc+jUJdTSKdmDWW2H6DkPhkX6NT/7yB2HtA==","signatures":[{"sig":"MEUCIQCmKifG9ZWjLaUAcWRdIG/GBsXXFkt83s3rzUCEaAH1fQIgcuPjLSEg1rowCNwM9huW5VWIw2bVdODU2fhsqwTc2TM=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":42808,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihSwBACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmom5BAAoieSK7OgRLcspL9IBR/+MjMlrI81Wy/Xi7eHAP9iwOjOMQeC\r\nMhBf4tR7/wnTIoUfxU8BA3g8+12LAtdNsXDgFPcC+4EU517aTlSkQcFHpPHU\r\nQb8DE9HjLbFNqkNHhnXzADuZ0cK8Qj0WpfOL2uQZD2oJ1AvyzfYHcDgWHDBT\r\nrXOFWjnEm6UWyHqPxLQ8QFT8VDEh2Ykm48m2MMJjcndd6Cjflj3cg3gD0/tU\r\nwdjKi0Gx3a8XGeIH4e1ZqSmp55D9FBlvrPM/U7bbjMitctVw4XtWQGXyiDAS\r\npJ8WckiSmVN3gncvhEAtFQ5KM+SkNezVtPEw9dazNM612wh7Oel/yUZR+1Ma\r\nlZ3ScCucdQz5JksMmv+elIRJvysBXCEdd94+K2abA+vKJvneeKdPocWmFLBE\r\ntF2VisfyDa6xEFuOR6JB9niXhfHMV7D1Ay2ipRycQxxO+ttOY4dvyyLCYgts\r\nkaV1aXNa+Q9o/xvrZg2omFDaOYNGKB14gfJTwaj26XXrnDEFxVp8ns1Nc2e7\r\nXICtc9uJX/z5gaJHkwQweMHND40TP06AnkJdcX98GMOwO1hKwsvPvKG0QeLE\r\noxet2TTpkLGQ0hKsY9NZBjEFNXvLurH6pz9d3nOeMK8axsMRx3rc6aEFYsR0\r\nQwwFQmElT1ub3DeFe44eHzFAfwVEYVPohOc=\r\n=Bm8p\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"a048e0cd7a38212e7bb4e453ceaa1a5ad56585d6","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"8.1.4","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"17.2.0","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0","autobind-decorator":"^2.4.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.13","@commitlint/cli":"^11.0.0","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","source-map-support":"^0.5.19","@types/serve-static":"1.13.9","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^11.0.0","@types/express-serve-static-core":"^4.17.26","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.6_1652894720874_0.14643157317894118","host":"s3://npm-registry-packages"}},"1.0.6-rc.1":{"name":"express-idempotency","version":"1.0.6-rc.1","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.6-rc.1","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotency","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"017d4758bdf2db1db9f76a801eb98677992f8523","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.6-rc.1.tgz","fileCount":17,"integrity":"sha512-l5fQh7tUNy8OI02nZj6ES8sZxDzJipPAusiQHzYJp6wj0cDorPSePNwPlH6GnuSHQMWuGcTWT42J9kr9SFLDWQ==","signatures":[{"sig":"MEUCIAxUyxlZ0rRifwSEIjbGKhZj32CPfnmc90Tk6zPWWz1sAiEAgDiCxOtpJ8FPkcOCC75iEsbkJkzx9JVgx0NTFdlmA38=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":42813,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJihTSlACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmqnyg//R+kJAdDRUy3foFEAHeNBkDM3kGhYlMVpL6Vkw7MAvAwVQtV8\r\nlawsBQ52UlE0bFkVSnnFo3jJYRAFelxR2xnLR7AFf2f3GbEKAVbaF/+SOIoK\r\nU5n4iYZqq0LzqaepZU+6WkoYaWCjlLdrKVMraBeZ6n/9Z9Dlr8Fu/4tbOwts\r\nbIuUpUjJa8wEGFm2ceyp21kxS2w7COJ28YqKHuDfWggXLW1ya3TuKVOMmnRM\r\nv/zkBNJ4vHmzn7DkP7NtJSuOIfUucegOe9eUgmGq+Jr3c5Rkrr/HFVzFRhoX\r\nFj72OZXzs6IFH9XUhLvZSU48SyvgkiaHJcbpY7xwHPJ8HsI/b/btf3gddW2/\r\nRoJ1Lv2ZZLj3ONKIArieAYDAQFa/dGAJCbR0Qe539gEuC4sAgc5KRc65lRVc\r\nGisGqmy8nN2aC4ToudsSIFrFqZHdt3zpUHUTA6E9sA1VX1wbCWQ9VLQtBScB\r\n+6xhTBFZk3o8YNqPRbqY88WARxLQo7cCatLnyWtN3M5sz33iTkevOR70fhaS\r\ny7dFndRIJzmdnQTK3Ic+RUJ3wtFT3e3f88e6GMJGciwTNsf/yulDoNUOMYVl\r\nvQwVxSdbG092bfzV7tqDkoJrqfCugOYmmUygSkTCPnwJMmxwsR+mPWe1gjSO\r\nth+CdEbIcCBsnDOQyLzW4ruJJhyF3iDwAAs=\r\n=gww5\r\n-----END PGP SIGNATURE-----\r\n"},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"698021b567cabdea47908050be46cbc87bc8a8ba","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"8.1.4","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"17.2.0","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0","autobind-decorator":"^2.4.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^7.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^3.8.3","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.13","@commitlint/cli":"^11.0.0","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","source-map-support":"^0.5.19","@types/serve-static":"1.13.9","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^3.2.0","@commitlint/config-conventional":"^11.0.0","@types/express-serve-static-core":"^4.17.26","@typescript-eslint/eslint-plugin":"^3.2.0","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.6-rc.1_1652896933447_0.539629145562913","host":"s3://npm-registry-packages"}},"1.0.6-rc.2":{"name":"express-idempotency","version":"1.0.6-rc.2","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@1.0.6-rc.2","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotency","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"b17d55df3cea2e31204df904544799d171e81f6f","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-1.0.6-rc.2.tgz","fileCount":17,"integrity":"sha512-Bk4QIEebMOjx4AG9RpZIfc6KfoPSwePAOpNmmNNnhdX/owHf916A13ARGs6txPcy/R1VH/2oD5Ofxj+17drm3g==","signatures":[{"sig":"MEYCIQD4ZptVoH05GXL/uKg4soCsqzD5ZTHwncBGMc8ZUZ6iMgIhAJ3/FAJ3BvTznmvEEYv4z+lMdBqZcb95IEWL/W5cFRfl","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":43247},"main":"dist/index.js","husky":{"hooks":{"pre-push":"npm run prettier && npm run lint && npm test","commit-msg":"commitlint -E HUSKY_GIT_PARAMS","pre-commit":""}},"gitHead":"6b054b1159229995800be318489ebcdb26cc50e8","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"9.6.7","description":"Add idempotency to your express route, effortlessly, the way you want it.","directories":{},"_nodeVersion":"18.17.1","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^1.4.0","autobind-decorator":"^2.4.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^15.0.1","chai":"^4.2.0","faker":"^4.1.0","husky":"^4.2.5","mocha":"^10.2.0","sinon":"^9.0.2","eslint":"^7.2.0","ts-node":"^8.10.2","prettier":"2.0.5","typescript":"^5.2.2","@types/chai":"^4.2.11","@types/faker":"^4.1.12","@types/mocha":"^7.0.2","@types/sinon":"^9.0.4","@types/express":"^4.17.13","@commitlint/cli":"^17.7.1","node-mocks-http":"^1.8.1","@types/deep-equal":"^1.0.1","source-map-support":"^0.5.19","@types/serve-static":"1.13.9","eslint-config-prettier":"^6.11.0","@typescript-eslint/parser":"^6.4.1","@commitlint/config-conventional":"^11.0.0","@types/express-serve-static-core":"^4.17.26","@typescript-eslint/eslint-plugin":"^6.4.1","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_1.0.6-rc.2_1692985695659_0.5431668451544731","host":"s3://npm-registry-packages"}},"2.0.0":{"name":"express-idempotency","version":"2.0.0","keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","_id":"express-idempotency@2.0.0","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"}],"homepage":"https://github.com/VilledeMontreal/express-idempotency","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"dist":{"shasum":"a096354814d5bb72468bf62bf348d7de5870f5af","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-2.0.0.tgz","fileCount":18,"integrity":"sha512-Kwe20yg1dPvVw3sY5hZfqEFX+jguDY9Dzwz2EJGXt3Fp3L8q4CsYkMqhpPtRtrnhNmCPbLiA03yFUnBs0VOj6w==","signatures":[{"sig":"MEQCIFnG0QEaI/88e+DEB1ZaGU5vFbtMrwLIuiAH5HVBGRKzAiBoTGv/dNCQqIt3GsMSHF+mwdgzWj14Gq2curuWjy5CzQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41402},"main":"dist/index.js","engines":{"npm":">=9.0.0","node":">=18.0.0"},"gitHead":"e1e429ece367bc24a13a715a56a0031616124904","scripts":{"lint":"eslint ./src --ext .ts,.tsx","test":"tsc --build tsconfig.test.json && nyc mocha","compile":"tsc --build tsconfig.dist.json","prepare":"husky","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src"},"typings":"dist/index.d.ts","_npmUser":{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},"repository":{"url":"git+https://github.com/VilledeMontreal/express-idempotency.git","type":"git"},"_npmVersion":"10.9.4","description":"Idempotency middleware for Express - Add idempotency to your express routes effortlessly","directories":{},"_nodeVersion":"22.21.1","dependencies":{"deep-equal":"^2.0.3","http-status-codes":"^2.3.0","autobind-decorator":"^2.4.0"},"_hasShrinkwrap":false,"devDependencies":{"nyc":"^17.1.0","chai":"^6.2.0","husky":"^9.1.7","mocha":"^11.7.5","sinon":"^21.0.0","eslint":"^9.39.1","ts-node":"^10.9.2","prettier":"^3.6.2","typescript":"^5.9.3","@types/chai":"^5.2.3","@types/mocha":"^10.0.10","@types/sinon":"^17.0.4","@types/express":"^5.0.5","@commitlint/cli":"^20.1.0","@faker-js/faker":"^10.1.0","node-mocks-http":"^1.17.2","@types/deep-equal":"^1.0.4","source-map-support":"^0.5.19","@types/serve-static":"^2.2.0","eslint-config-prettier":"^10.1.8","@typescript-eslint/parser":"^8.46.3","@commitlint/config-conventional":"^20.0.0","@types/express-serve-static-core":"^5.1.0","@typescript-eslint/eslint-plugin":"^8.46.3","@istanbuljs/nyc-config-typescript":"^1.0.1"},"_npmOperationalInternal":{"tmp":"tmp/express-idempotency_2.0.0_1762380339975_0.9562866259422058","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"express-idempotency","version":"2.1.0","description":"Idempotency middleware for Express - Add idempotency to your express routes effortlessly","main":"dist/index.js","typings":"dist/index.d.ts","engines":{"node":">=18.0.0","npm":">=9.0.0"},"scripts":{"compile":"tsc --build tsconfig.dist.json","test":"tsc --build tsconfig.test.json && nyc mocha","lint":"eslint ./src --ext .ts,.tsx","lint:fix":"eslint ./src --ext .ts,.tsx --fix","prettier":"prettier --check ./src","prettier:fix":"prettier --write ./src","prepare":"husky","test:e2e":"cross-env TS_NODE_PROJECT=tsconfig.e2e.json mocha --config .mocharc.e2e.yml","test:all":"npm test && npm run test:e2e","e2e:serve":"cross-env TS_NODE_PROJECT=tsconfig.e2e.json ts-node tests/e2e/harness/server.ts"},"repository":{"type":"git","url":"git+https://github.com/VilledeMontreal/express-idempotency.git"},"keywords":["express","middleware","idempotent","idempotency"],"author":{"name":"Ville de Montréal"},"license":"MIT","homepage":"https://github.com/VilledeMontreal/express-idempotency","devDependencies":{"@commitlint/cli":"^20.1.0","@commitlint/config-conventional":"^20.0.0","@faker-js/faker":"^10.1.0","@istanbuljs/nyc-config-typescript":"^1.0.1","@types/chai":"^5.2.3","@types/deep-equal":"^1.0.4","@types/express":"^5.0.5","@types/express-serve-static-core":"^5.1.0","@types/mocha":"^10.0.10","@types/node":"^25.9.3","@types/serve-static":"^2.2.0","@types/sinon":"^21.0.1","@typescript-eslint/eslint-plugin":"^8.46.3","@typescript-eslint/parser":"^8.46.3","chai":"^6.2.0","cross-env":"^10.1.0","eslint":"^9.39.1","eslint-config-prettier":"^10.1.8","express":"^5.2.1","husky":"^9.1.7","mocha":"^11.7.5","node-mocks-http":"^1.17.2","nyc":"^18.0.0","prettier":"^3.6.2","sinon":"^21.0.0","source-map-support":"^0.5.19","ts-node":"^10.9.2","typescript":"^5.9.3"},"overrides":{"mocha":{"diff":"^8.0.4","serialize-javascript":"^7.0.5"},"istanbul-lib-instrument":{"@babel/core":"^7.29.6"},"js-yaml":"^4.2.0"},"dependencies":{"autobind-decorator":"^2.4.0","deep-equal":"^2.0.3","http-status-codes":"^2.3.0"},"gitHead":"d7ee89409d0e02d69df37e2c4d5d1477b16859d8","_id":"express-idempotency@2.1.0","bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"_nodeVersion":"24.17.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-RtMq6KMVsuc8RF2tC+v84cqPW6vYiUP4STHXJ4vfUcO8a9ei3bNn2xqkrj8Q4a/myzcZwXOIpRIrKx18MH4y6w==","shasum":"eb85d350009979d4c7fbd2202aa52a1389d15b93","tarball":"https://registry.npmjs.org/express-idempotency/-/express-idempotency-2.1.0.tgz","fileCount":19,"unpackedSize":75650,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/express-idempotency@2.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDKXXtzrnWKoYhNUB+LKkkqIZmUwk0uXQ2P3a2s2RZJegIgIK221S4kT5c6Hh/GdY2diBEwV+87GKF59ktQJZ2s8zE="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1101a6f6-7e65-48be-912b-b7777edcb372"}},"directories":{},"maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},{"name":"lawp09","email":"phil.lawson9@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/express-idempotency_2.1.0_1782420752209_0.6358203420750086"},"_hasShrinkwrap":false}},"time":{"created":"2020-06-15T00:59:30.160Z","modified":"2026-06-25T20:52:32.624Z","1.0.0-rc.1":"2020-06-15T00:59:30.351Z","1.0.0":"2020-06-15T01:37:10.803Z","1.0.1":"2020-06-15T02:12:59.196Z","1.0.2":"2020-06-15T13:30:31.550Z","1.0.3":"2020-10-16T19:38:30.278Z","1.0.4":"2021-05-18T19:01:51.276Z","1.0.5":"2021-12-15T18:50:33.310Z","1.0.6":"2022-05-18T17:25:21.123Z","1.0.6-rc.1":"2022-05-18T18:02:13.617Z","1.0.6-rc.2":"2023-08-25T17:48:15.907Z","2.0.0":"2025-11-05T22:05:40.203Z","2.1.0":"2026-06-25T20:52:32.347Z"},"bugs":{"url":"https://github.com/VilledeMontreal/express-idempotency/issues"},"author":{"name":"Ville de Montréal"},"license":"MIT","homepage":"https://github.com/VilledeMontreal/express-idempotency","keywords":["express","middleware","idempotent","idempotency"],"repository":{"type":"git","url":"git+https://github.com/VilledeMontreal/express-idempotency.git"},"description":"Idempotency middleware for Express - Add idempotency to your express routes effortlessly","maintainers":[{"name":"joscelynjean","email":"joscelyn.jean@gmail.com"},{"name":"lawp09","email":"phil.lawson9@gmail.com"}],"readme":"Add idempotency to your express route, effortlessly, the way you want it.\n\n#### Production (master)\n\n[![CI](https://github.com/VilledeMontreal/express-idempotency/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/VilledeMontreal/express-idempotency/actions/workflows/ci.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/958bd19185f44fcda617a15fb6a72c1d?branch=master)](https://www.codacy.com/gh/VilledeMontreal/express-idempotency?utm_source=github.com&utm_medium=referral&utm_content=VilledeMontreal/express-idempotency&utm_campaign=Badge_Grade&branch=master)\n[![Codacy Badge](https://app.codacy.com/project/badge/Coverage/958bd19185f44fcda617a15fb6a72c1d?branch=master)](https://www.codacy.com/gh/VilledeMontreal/express-idempotency?utm_source=github.com&utm_medium=referral&utm_content=VilledeMontreal/express-idempotency&utm_campaign=Badge_Coverage&branch=master)\n\n#### Development branch (develop)\n\n[![CI](https://github.com/VilledeMontreal/express-idempotency/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/VilledeMontreal/express-idempotency/actions/workflows/ci.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/958bd19185f44fcda617a15fb6a72c1d?branch=develop)](https://www.codacy.com/gh/VilledeMontreal/express-idempotency?utm_source=github.com&utm_medium=referral&utm_content=VilledeMontreal/express-idempotency&utm_campaign=Badge_Grade&branch=develop)\n[![Codacy Badge](https://app.codacy.com/project/badge/Coverage/958bd19185f44fcda617a15fb6a72c1d?branch=develop)](https://www.codacy.com/gh/VilledeMontreal/express-idempotency?utm_source=github.com&utm_medium=referral&utm_content=VilledeMontreal/express-idempotency&utm_campaign=Badge_Coverage&branch=develop)\n\n([Français](#french-version))\n\n<a id='english-version' class='anchor' aria-hidden='true'></a>\n\n# Idempotency middleware for Express\n\nIntegrate idempotency feature to [Express](https://expressjs.com) routes quickly, without efforts. The implementation is inspired from the Stripe idempotency implementation.\n\nThis is a [Node.js](https://nodejs.org/) module designed to work with Express, available through the [NPM registry](https://www.npmjs.com/).\n\n## Features\n\n-   Middleware for Express with a high level of customization\n-   Helpers to detect processing from the middleware and report errors\n\n## Examples\n\nFor examples, check the `examples` folder.\n\n## Getting started\n\n### Requirements\n\n- **Node.js** >= 18.0.0\n- **TypeScript** >= 5.0.0 (if using TypeScript)\n- **npm** >= 9.0.0\n\n### Installation\n\nInstall the dependency.\n\n```bash\nnpm install express-idempotency\n```\n\nIntegrate the middleware in your Express initialization.\n\n```javascript\n// Javascript\nconst idempotency = require('express-idempotency');\n// ...express initialization\napp.post('*', idempotency.idempotency());\n\n// Typescript\nimport { idempotency } from 'express-idempotency';\n// ...express initialization\napp.post('*', idempotency());\n```\n\n### Determine a idempotency hit in route handler\n\nThe idempotency middleware will call the next function, whenever a idempotency key is detected or not. This is by design to avoid breaking the middleware and route handler chain. To prevent transaction processing to occurs, there is a _hit_ function which determine if the idempotency middleware did process the request.\n\n```javascript\napp.post('/', function (req, res) {\n    // Check if there was a hit!\n    const idempotencyService = getSharedIdempotencyService();\n    if (idempotencyService.isHit(req)) {\n        return;\n    }\n\n    // Do something\n    res.send('Got a new POST request');\n});\n```\n\n### Report error in processing request\n\nSometimes, there is errors that can occur in the process of the request. In that case, the middleware must be aware of the error and remove any information related to the idempotency key that failed. You can notify the middleware by using the _reportError_ function.\n\n```javascript\napp.post('/', function (req, res) {\n    const idempotencyService = getSharedIdempotencyService();\n\n    // Processing...\n    // Oh BOOM! There is a error. Let's notify the middleware.\n    idempotencyService.reportError(req);\n});\n```\n\n### Options\n\nYou can configure the way the idempotency middleware will behave by providing options during initialization.\n\n```javascript\napp.post(\n    '*',\n    idempotency({\n        // Specify the header to be used to retrieve the idempotency key.\n        idempotencyKeyHeader,\n        // The data adapter used to store the resources.\n        dataAdapter,\n        // Logic to indicate if response must be kept for idempotency\n        responseValidator,\n        // Logic to detect misuse of the idempotency key\n        intentValidator,\n        // Maximum processing time (ms) before an in-progress resource is\n        // considered orphaned and can be taken over by a retry.\n        // Disabled when absent or <= 0.\n        processingTimeout,\n        // Case-insensitive whitelist of request headers persisted at rest.\n        // Default: ['content-type']. Use [] to persist none.\n        requestHeaderWhitelist,\n    })\n);\n```\n\n#### Change the idempotency key header\n\nBy default, the header used to retrieve the idempotency key is `Idempotency-Key` but you can change it for any value you would like.\n\n#### Data adapter\n\nThe data adapter allows to persist cached response for a idempotency key. The default implementation use in-memory storage, which is not recommended for production environment.\n\nYou can create your own data adapter by implementing the `IIdempotencyDataAdapter` interface but there is already some implementation ready.\n\n-   [Mongo Data Adapter](https://www.npmjs.com/package/express-idempotency-mongo-adapter)\n\n#### Response validator\n\nBy default, a request will be considered successful and the response will be cached if the response http status code is between 200 and 299. If it is not the behavior that is wished, you can implement your own logic by providing your own responseValidator, which must implements the `IIdempotencyResponseValidator` interface.\n\n```typescript\nexport class CustomResponseValidator implements IIdempotencyResponseValidator {\n    public isValidForPersistence(\n        idempotencyResponse: IdempotencyResponse\n    ): boolean {\n        // Insert logic here\n        // For example, we could cache any 500 status code.\n        return idempotencyResponse.statusCode == 500;\n    }\n}\n```\n\n#### Intent validator\n\nWhen receiving a request with an idempotency key, the middleware will compare it to the original request to ensure the intend. By default, the middleware is expecting a match for the **url**, the **method**, the **query parameters** and the **body**. If any of these element does not match, it will be qualified as a misuse of the idempotency key and an error will be thrown.\n\nThis intent validator can be override by providing your own implementation, if this is not the desired behavior. Simply implements the `IIdempotencyIntentValidator`interface.\n\n```typescript\nexport class CustomIntentValidator implements IIdempotencyIntentValidator {\n\n  isValidIntent(req: express.Request, idempotencyRequest: IdempotencyRequest): boolean {\n    // Insert logic here\n    // For example, the url must match\n    return req.url === idempotencyRequest.url;\n  }\n```\n\n#### Processing timeout\n\nBy default, if a request starts processing but never completes (crash, OOM, rollout, or a response sent via `res.end()` / streaming / `sendFile` that bypasses `res.send`), the in-progress resource remains locked and subsequent retries receive a permanent `409 Conflict` until the adapter's TTL expires.\n\nThe `processingTimeout` option (in milliseconds) enables a lease mechanism: if a retry arrives after the timeout has elapsed since the resource was created, the middleware considers the original request orphaned and takes over processing.\n\n```javascript\napp.post(\n    '*',\n    idempotency({\n        dataAdapter,\n        // Allow a retry to take over after 30 seconds\n        processingTimeout: 30_000,\n    })\n);\n```\n\n**Requirements and caveats:**\n\n- The data adapter must persist and return the `createdAt` field of `IdempotencyResource`. Without it the feature is silently inert (safe degradation to the v2.0.0 behaviour).\n- Choose a value at least 2× the worst-case processing duration to avoid false takeovers.\n- Due to the check-then-act nature of the takeover, at-least-once delivery semantics apply when the timeout is reached. If two retries race at expiry, one will win and the other will fall back to a `409`.\n- When a response is sent via `res.end()`, streaming, or `sendFile` (bypassing `res.send`), the middleware cannot capture the body. It automatically deletes the resource so the next retry is reprocessed rather than permanently blocked.\n\n#### Request header filtering\n\nBy default the middleware persists **only** the `content-type` request header into the idempotency resource. Every other header — `Authorization`, `Cookie`, API keys — is stripped before the request is handed to the data adapter, so secret-bearing headers are never stored **at rest** for the lifetime of the TTL (previously the whole `req.headers` object was persisted).\n\nUse `requestHeaderWhitelist` to control which headers are kept. Matching is case-insensitive. The list **replaces** the default — it is not merged — so re-include `content-type` explicitly if you still need it.\n\n```javascript\napp.post(\n    '*',\n    idempotency({\n        // Persist no request headers at all:\n        requestHeaderWhitelist: [],\n        // ...or keep the specific headers your custom intent validator needs\n        // (this replaces the default, so add back content-type if required):\n        // requestHeaderWhitelist: ['content-type', 'x-correlation-id'],\n    })\n);\n```\n\n> **Note:** this filters request **headers** only. The request **body** is still persisted as-is, so a secret carried in the body (e.g. a password in a POST payload) is not affected by this option.\n\n**Caveat:** only the **persisted** request is filtered. The intent validator receives the live request untouched, so `isValidIntent(req, idempotencyRequest)` compares the **raw** `req.headers` on one side against the **filtered** `idempotencyRequest.headers` on the other. A custom validator that compares a header must account for that asymmetry (and a header it relies on must be present in the whitelist).\n\n## Testing\n\nThis library has two test layers, both run in CI on every branch:\n\n- **Unit tests** — `npm test` (mock-based, fast; coverage reported to Codacy via lcov).\n- **End-to-end tests** — `npm run test:e2e` exercises the full middleware over a **real HTTP server** (Express + native `fetch`): replay/hit, `409` in-progress conflict, concurrent retries, `processingTimeout` takeover, zombie-write guard, phantom-key cleanup (`res.end` bypass), intent mismatch (`417`) and `reportError`.\n\n`npm run test:all` runs both layers. The e2e suite requires **Node >= 18.2** (it relies on `server.closeAllConnections`).\n\n### Manual probing\n\nA standalone harness server is available for manual exploration with curl or a REST client:\n\n```bash\nnpm run e2e:serve   # http://localhost:8080 (override with the PORT env var)\n\n# Same key replays the first response; a different key is processed fresh:\ncurl -H 'Idempotency-Key: demo-1' http://localhost:8080/resource\ncurl -H 'Idempotency-Key: demo-1' http://localhost:8080/resource\n```\n\n> **Error handling:** the middleware signals conflicts and misuse by calling `next(err)` with a typed error — `IdempotencyConflictError` (`409`) or `IdempotencyIntentMismatchError` (`417`). Both extend the exported `IdempotencyError` and carry the HTTP status on `statusCode` (and `status`), so Express derives the correct code natively — no custom error handler required. Registering one is still recommended to shape the response body; it can branch on the error type with `instanceof` or read `err.statusCode`. See `tests/e2e/harness/buildApp.ts` for a reference handler.\n\n### Reusing the suite for custom adapters\n\nThe behavioural suite is factored as `runIdempotencySuite(makeApp)` (`tests/e2e/harness/scenarios.ts`), so a custom data adapter can replay the exact same guarantees:\n\n```typescript\nimport { buildApp } from './harness/buildApp';\nimport { runIdempotencySuite } from './harness/scenarios';\n\ndescribe('MyAdapter over real HTTP', () => {\n    runIdempotencySuite((options) => buildApp({ ...options, dataAdapter: new MyAdapter() }));\n});\n```\n\n## License\n\nThe source code of this project is distributed under the [MIT License](LICENSE).\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md#english-version).\n\n## Code of Conduct\n\nParticipation in this poject is governed by the [Code of Conduct](CODE_OF_CONDUCT.md).\n\n## References\n\n1. [Designing robust and predictable APIs with idempotency](https://stripe.com/fr-ca/blog/idempotency)\n\n---\n\n([English](#english-version))\n\n<a id='french-version' class='anchor' aria-hidden='true'></a>\n\n# Middleware d'idempotence pour Express\n\nAjouter à [Express](https://expressjs.com) des fonctionnalités d'idempotence pour certaines routes rapidement, sans effort. L'implémentation est inspirée par la stratégie de Stripe.\n\nCe module [Node.js](https://nodejs.org/) est conçu pour fonctionner avec Express, et disponible sur le [registre NPM](https://www.npmjs.com/).\n\n## Fonctionnalités\n\n-   Middleware pour Express avec un haut niveau de configuration\n-   Utilitaires pour permettre la détection de l'intervention du middleware et rapporter les erreurs\n\n## Exemples\n\nPour des exemples, voir le répertoire `examples`.\n\n## Démarrage rapide\n\nInstallation de la dépendance.\n\n```\n$ npm install express-idempotency\n```\n\nIntégrer le middleware dans l'initialisation de votre application Express.\n\n```javascript\n// Javascript\nconst idempotency = require('express-idempotency');\n// ...initialisation de Express\napp.post('*', idempotency.idempotency());\n\n// Typescript\nimport { idempotency } from 'express-idempotency';\n// ...initialisation de Express\napp.post('*', idempotency());\n```\n\n### Déterminer l'intervention du middleware dans une route\n\nLe middleware d'idempotence va faire l'appel de la fonction next, peu importe si la clé d'idempotence est détecté ou non. Cette décision de design permet de conserver la chaine de communication quant à la prise en charge de la requête. Afin de prévenir une transaction d'être exécuté une deuxième fois, il y a une fonction _hit_ permettant d'identifier le traitement préalable du middleware.\n\n```javascript\napp.post('/', function (req, res) {\n    // Vérifier l'intenvention!\n    const idempotencyService = getSharedIdempotencyService();\n    if (idempotencyService.isHit(req)) {\n        return;\n    }\n\n    // Faire quelque chose\n    res.send('Got a new POST request');\n});\n```\n\n### Rapporter des erreurs de traitement\n\nQuelques fois, on veut communiquer au middleware que le traitement attendu a échoué. Dans ces cas, il faut que le middleware sache qu'une erreur est survenue et retirer l'information relative à la clé d'idempotence courante. On peut donc notifier le middleware en utilisant la fonction _reportError_.\n\n```javascript\napp.post('/', function (req, res) {\n    const idempotencyService = getSharedIdempotencyService();\n\n    // Processing...\n    // Oh BOOM! There is a error. Let's notify the middleware.\n    idempotencyService.reportError(req);\n});\n```\n\n### Options\n\nVous pouvez configurer lors de l'initialisation la façon dont le middleware va se comporter.\n\n```javascript\napp.post(\n    '*',\n    idempotency({\n        // Préciser l'entête de requête contenant la clé d'idempotence.\n        idempotencyKeyHeader,\n        // L'adapteur de données utilisé pour stocker les informations.\n        dataAdapter,\n        // Préciser la logique permettant d'indiquer si la réponse doit être conservé pour l'idempotence.\n        responseValidator,\n        // Préciser la logique à appliquer pour s'assurer de la bonne utilisation de la clé d'idempotence.\n        intentValidator,\n        // Durée maximale de traitement (ms) avant qu'une ressource en cours soit\n        // considérée orpheline et reprise par une nouvelle tentative.\n        // Désactivé si absent ou <= 0.\n        processingTimeout,\n        // Liste blanche (insensible à la casse) des entêtes de requête persistés\n        // au repos. Défaut : ['content-type']. Utiliser [] pour n'en persister aucun.\n        requestHeaderWhitelist,\n    })\n);\n```\n\n#### Changer la clé d'entête de requête\n\nPar défaut, l'entête utilisé pour la clé d'idempotence est `Idempotency-Key` mais elle peut être changé pour une autre valeur désirée.\n\n#### Adapteur de données\n\nL'adapteur de données permet de persister l'information relatif à la clé d'idempotence. L'implémentation par défaut conserve l'information en mémoire, ce qui n'est pas recommandé pour un environnement de production.\n\nVous pouvez créer votre propre adapteur de données par l'implémentation de l'interface `IIdempotencyDataAdapter`. Les implémentations connues sont les suivantes :\n\n-   [Mongo Data Adapter](https://www.npmjs.com/package/express-idempotency-mongo-adapter)\n\n#### Validateur de réponse\n\nPar défaut, une requête est considéré valide lorsque le statut http est entre 200 et 299 inclusivement. À ce moment-là, la réponse est persistée. Si ce n'est pas le comportement attendu, il est possible d'implémenter sa propre logique en fournissant votre propre validateur de réponse. À ce moment-là, il faut implémenter l'interface `IIdempotencyResponseValidator`.\n\n```typescript\nexport class CustomResponseValidator implements IIdempotencyResponseValidator {\n    public isValidForPersistence(\n        idempotencyResponse: IdempotencyResponse\n    ): boolean {\n        // Insert logic here\n        // For example, we could cache any 500 status code.\n        return idempotencyResponse.statusCode == 500;\n    }\n}\n```\n\n#### Validateur d'intention\n\nLorsqu'on reçoit une requête avec une clé d'idempotence, le middleware va comparer celle-ci avec la requête originale ayant généré une ressource idempotente afin d'assurer l'intention. Par défaut, le middleware va s'assurer que l'adresse (url), la méthode, les paramètres de requête et le contenu. Si l'un de ces éléments divergent, la requête va être considéré comme invalide et l'utilisation de la clé d'idempotence incorrecte.\n\nCe comporement peut être remplacé en fournissant son propre validateur d'intention par l'implémentation de l'interface `IIdempotencyIntentValidator`.\n\n```typescript\nexport class CustomIntentValidator implements IIdempotencyIntentValidator {\n\n  isValidIntent(req: express.Request, idempotencyRequest: IdempotencyRequest): boolean {\n    // Insérer logique ici\n    // Par exemple, seulement l'adresse doit correspondre\n    return req.url === idempotencyRequest.url;\n  }\n```\n\n#### Délai de traitement\n\nPar défaut, si une requête démarre son traitement mais ne se termine jamais (crash, OOM, redéploiement, ou réponse envoyée via `res.end()` / streaming / `sendFile` sans passer par `res.send`), la ressource en cours reste verrouillée et les nouvelles tentatives reçoivent un `409 Conflict` permanent jusqu'à l'expiration du TTL de l'adapteur.\n\nL'option `processingTimeout` (en millisecondes) active un mécanisme de bail : si une nouvelle tentative arrive après l'écoulement du délai depuis la création de la ressource, le middleware considère la requête originale comme orpheline et reprend le traitement.\n\n```javascript\napp.post(\n    '*',\n    idempotency({\n        dataAdapter,\n        // Permettre à une nouvelle tentative de reprendre après 30 secondes\n        processingTimeout: 30_000,\n    })\n);\n```\n\n**Prérequis et mises en garde :**\n\n- L'adapteur de données doit persister et retourner le champ `createdAt` de `IdempotencyResource`. Sans cela, la fonctionnalité est silencieusement inerte (dégradation propre vers le comportement v2.0.0).\n- Choisir une valeur d'au moins 2× la durée de traitement maximale pour éviter les reprises prématurées.\n- En raison de la nature « vérifier puis agir » de la reprise, une sémantique de livraison « au moins une fois » s'applique lorsque le délai est atteint. Si deux tentatives entrent en concurrence à l'expiration, l'une gagnera et l'autre recevra un `409`.\n- Lorsqu'une réponse est envoyée via `res.end()`, le streaming ou `sendFile` (sans passer par `res.send`), le middleware ne peut pas capturer le corps. Il supprime automatiquement la ressource afin que la prochaine tentative soit retraitée plutôt que bloquée de façon permanente.\n\n#### Filtrage des entêtes de requête\n\nPar défaut, le middleware ne persiste **que** l'entête de requête `content-type` dans la ressource d'idempotence. Tous les autres entêtes — `Authorization`, `Cookie`, clés d'API — sont retirés avant que la requête ne soit remise à l'adapteur de données, de sorte que les entêtes porteurs de secrets ne sont jamais stockés **au repos** pendant toute la durée du TTL (auparavant, l'objet `req.headers` entier était persisté).\n\nUtilisez `requestHeaderWhitelist` pour contrôler les entêtes conservés. La comparaison est insensible à la casse. La liste **remplace** le défaut — elle ne s'y ajoute pas — donc réincluez `content-type` explicitement si vous en avez encore besoin.\n\n```javascript\napp.post(\n    '*',\n    idempotency({\n        // Ne persister aucun entête de requête :\n        requestHeaderWhitelist: [],\n        // ...ou conserver les entêtes dont votre validateur d'intention a besoin\n        // (ceci remplace le défaut, donc rajoutez content-type au besoin) :\n        // requestHeaderWhitelist: ['content-type', 'x-correlation-id'],\n    })\n);\n```\n\n> **Note :** ceci filtre uniquement les **entêtes** de requête. Le **corps** de la requête reste persisté tel quel ; un secret transporté dans le corps (ex. un mot de passe dans un POST) n'est pas affecté par cette option.\n\n**Mise en garde :** seule la requête **persistée** est filtrée. Le validateur d'intention reçoit la requête vivante intacte ; ainsi `isValidIntent(req, idempotencyRequest)` compare les `req.headers` **bruts** d'un côté aux `idempotencyRequest.headers` **filtrés** de l'autre. Un validateur personnalisé qui compare un entête doit tenir compte de cette asymétrie (et l'entête dont il dépend doit figurer dans la liste blanche).\n\n## Tests\n\nLa librairie comporte deux niveaux de tests, tous deux exécutés en CI sur chaque branche :\n\n- **Tests unitaires** — `npm test` (basés sur des mocks, rapides ; couverture envoyée à Codacy via lcov).\n- **Tests de bout en bout** — `npm run test:e2e` exerce l'ensemble du middleware sur un **vrai serveur HTTP** (Express + `fetch` natif) : rejeu/hit, conflit `409` en cours de traitement, tentatives concurrentes, reprise par `processingTimeout`, garde anti-écriture « zombie », nettoyage des clés fantômes (contournement de `res.send` via `res.end()`), intention divergente (`417`) et `reportError`.\n\n`npm run test:all` lance les deux niveaux. La suite e2e requiert **Node >= 18.2** (elle s'appuie sur `server.closeAllConnections`).\n\n### Exploration manuelle\n\nUn serveur de test autonome permet une exploration manuelle (curl ou client REST) :\n\n```bash\nnpm run e2e:serve   # http://localhost:8080 (modifiable via la variable d'env PORT)\n\n# Une même clé rejoue la première réponse ; une clé différente est traitée à neuf :\ncurl -H 'Idempotency-Key: demo-1' http://localhost:8080/resource\ncurl -H 'Idempotency-Key: demo-1' http://localhost:8080/resource\n```\n\n> **Gestion des erreurs :** le middleware signale les conflits et les mésusages en appelant `next(err)` avec une erreur typée — `IdempotencyConflictError` (`409`) ou `IdempotencyIntentMismatchError` (`417`). Toutes deux héritent de l'erreur exportée `IdempotencyError` et portent le statut HTTP sur `statusCode` (et `status`), de sorte qu'Express en dérive nativement le bon code — aucun gestionnaire d'erreurs personnalisé n'est requis. En enregistrer un reste recommandé pour mettre en forme le corps de la réponse ; il peut discriminer le type d'erreur avec `instanceof` ou lire `err.statusCode`. Voir `tests/e2e/harness/buildApp.ts` pour un gestionnaire de référence.\n\n### Réutiliser la suite pour des adapteurs personnalisés\n\nLa suite comportementale est factorisée sous la forme `runIdempotencySuite(makeApp)` (`tests/e2e/harness/scenarios.ts`), de sorte qu'un adapteur de données personnalisé peut rejouer exactement les mêmes garanties :\n\n```typescript\nimport { buildApp } from './harness/buildApp';\nimport { runIdempotencySuite } from './harness/scenarios';\n\ndescribe('MonAdapteur sur un vrai serveur HTTP', () => {\n    runIdempotencySuite((options) => buildApp({ ...options, dataAdapter: new MonAdapteur() }));\n});\n```\n\n## Contribuer\n\nVoir [CONTRIBUTING.md](CONTRIBUTING.md#french-version)\n\n## Licence et propriété intellectuelle\n\nLe code source de ce projet est libéré sous la licence [MIT License](LICENSE).\n\n## Code de Conduite\n\nLa participation à ce projet est réglementée part le [Code de Conduite](CODE_OF_CONDUCT.md#french-version)\n\n## Références\n\n1. [Designing robust and predictable APIs with idempotency](https://stripe.com/fr-ca/blog/idempotency)\n","readmeFilename":"README.md"}