{"_id":"@aggiovato/yrest","_rev":"11-4aab9ada290420acde86736e391c09ba","name":"@aggiovato/yrest","dist-tags":{"latest":"0.5.2"},"versions":{"0.1.0":{"name":"@aggiovato/yrest","version":"0.1.0","keywords":["yaml","rest","mock","api","cli","fastify"],"author":"","license":"MIT","_id":"@aggiovato/yrest@0.1.0","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"2630bd4ca07f122930d66276b5b9f2795cd43d81","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.1.0.tgz","fileCount":10,"integrity":"sha512-s4pPiM2lCVKw4xZY4TTngtzOevokTy7QbHj4Dczk2sv8mZN66K7n21ub1qxfVVX75RB7OUCP1IEHTxvIzE9l0A==","signatures":[{"sig":"MEQCIAxexiL7GuZHORcWnhbvUmaYU0KueC5pYaIpbox8b12iAiAB5s2visDw2YSHyHjZH4PTL9AFkwkNu+TtBKGZk6gA5g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41239},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"c0c1778247458746820295ff7cde4d29c204d200","scripts":{"dev":"tsup --watch","test":"vitest","build":"tsup","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"aggiovato","email":"aggiovato@gmail.com"},"repository":{"url":"","type":"git"},"_npmVersion":"10.8.2","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"20.20.2","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","vitest":"^4.1.8","typescript":"^5.5.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.1.0_1780533400176_0.5036097271536639","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.1.1":{"name":"@aggiovato/yrest","version":"0.1.1","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.1.1","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"ca36086542b9968169610e5d37b499bc58c318fa","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.1.1.tgz","fileCount":10,"integrity":"sha512-x6QvWLh36irS3RDfczaj+FbNfSA0QqfT4MMoCWj5HDkAvZWdz51I3JqWe5dbSdcCNzDF6Z3/JrHkk9U+oHzHxA==","signatures":[{"sig":"MEQCIGgYIJyaerOjN58tAhzShvl8QiebARreQxxyTu621Hy1AiAn5WK+LWXrr/ZJZA1prsJcdFhn4tcDTKomPflUjQHuvQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":44840},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"926ba36a85fe7244dec27e2ff13b8c1af823f899","scripts":{"dev":"tsup --watch","test":"vitest","build":"tsup","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"aggiovato","email":"aggiovato@gmail.com"},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"10.9.8","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"22.22.3","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","vitest":"^4.1.8","typescript":"^5.5.0","@types/node":"^22.0.0"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.1.1_1780780986645_0.4374759302446676","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.2.0":{"name":"@aggiovato/yrest","version":"0.2.0","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.2.0","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"8bac17656b62933cdf02fb2acacc5945e45bba1b","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.2.0.tgz","fileCount":10,"integrity":"sha512-kUtkAFmQDdIN2QD507lUBoDLcIhlQ3p31vnfwrioWzwHlYSwKeldzIRtgOlUfy4gdPVKU4nMxBjtq91tSFAffg==","signatures":[{"sig":"MEYCIQDjuB8WqaD4dy0s77nqFnK6enR4j6N6q6i+IRiwwsukJgIhAOx6PP2BlaKBiAPN+gDnI7f55T2F6olms3Oa6ih2JZUA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":144239},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"f82a85eadbb71dec9d085dcdc744306fe8396011","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.2.0_1780849398485_0.33943652740319075","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.2.1":{"name":"@aggiovato/yrest","version":"0.2.1","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.2.1","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"84f16b6a69055907a929e270e99574f6b987d58d","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.2.1.tgz","fileCount":10,"integrity":"sha512-1f7IokBFJpA8fLrToxCLbBQbnoojPQRBuVu3WXFt6QGUsNou7skuWgxs+7tya6QTr7Ksn6COCYPLVFvJt4DTzA==","signatures":[{"sig":"MEQCIHNaXjPIF6TDDP8MxraJ2e+y2gaDY0nQu4gI19SpyWISAiARybPFo5lIyHOuwICCNUzhidKMaGXTVK2rG+M4aKtelA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":148829},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"93a1f51f504edcf6279a366bd181fa9076e7b569","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.2.1_1780850165952_0.8978348830649587","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.2.2":{"name":"@aggiovato/yrest","version":"0.2.2","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.2.2","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"8c00871e20074236cf7b434eb59f9ccc148c3db0","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.2.2.tgz","fileCount":10,"integrity":"sha512-717Bw/5hy5yQfbwCUShIctV2Cw3e0+rTAAWpooqiyqnsghIy3sHh8/Ddx6rmO6dH71Mn6V1V7XqmFMDaTO53Kg==","signatures":[{"sig":"MEUCIHXIbPDCgYxTq5KTQyhoeN0/ifeB8fzoHCqRdFfUSd4JAiEAncJWJpkublN/2tNNnRqMAASBbTyF8tVgJiWE+KMVWLQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.2.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":148829},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"1bf907515dbce4c352b13b29b858e8b5b661bd6d","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.2.2_1780851713635_0.499965003379494","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.3.0":{"name":"@aggiovato/yrest","version":"0.3.0","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.3.0","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"560345a99b2f271144f2306ebdd253a5af164e99","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.3.0.tgz","fileCount":10,"integrity":"sha512-d0/pJpiRm7Lj1pu+9dAZJzDCLkleHjotBm6FcjEp/gUPQ1xXG+heH85l2rMAOcuRqEame13Nb7sbh97QokaetQ==","signatures":[{"sig":"MEUCIDZ47ShKePcAZ4fwFG0zVrxkHaTTuwZ9poGjQjLaL/zyAiEAxu5FS/aFP2pwwz78Q2HvNocTR7Lj9tyynm8y7C4tuSo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":170465},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"19649ad292d9fe194d6e60ef05f5075e328f9df4","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.3.0_1780866202274_0.40179538153153893","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.4.0":{"name":"@aggiovato/yrest","version":"0.4.0","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.4.0","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"09f435a96f76620d830a7b6390c2ae14fb289c5e","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.4.0.tgz","fileCount":10,"integrity":"sha512-SBjI1UzPR3IiGWgOnRo2Qw4yQBEC+GyA0G/+tQf4cgPE6hQ5PsdBRh+DOd3tE8hmXCWycZx7txwUOQtMSue0IQ==","signatures":[{"sig":"MEUCIQDdpB+zgcKVsLEk7xwI8LSllTPKs0ZZIyxMXgFNzlx4jQIgOsEjI9YkTeLjCeJEDF/ApPgCJVp2VNfA8e+D1WWea1A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":192389},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"1e3be58210bbcb4888c8eae5b391dbef51bd4c38","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.4.0_1780874716452_0.43463855260830075","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.5.0":{"name":"@aggiovato/yrest","version":"0.5.0","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.5.0","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"89cf398b1ddbefd0f5432f5250fce787caa3e8ea","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.5.0.tgz","fileCount":10,"integrity":"sha512-ERtr7BSh4stvRlxyqXDURj1wv7OU39wPW2jM+KbRwKxEHGy9CVflmvAQO5JIT8he/g9aHftqvVxa19TMFODk9A==","signatures":[{"sig":"MEYCIQC9mKzcC6DxMTU0HGWxw9l0bmp0WAgokPvFhcGajwXXsgIhAMvCvCnmr+2fqH4rQo5WyX5zKDkvWPDdcDeFaK2TGG1n","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":247701},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"9836050d1cc910fb6a279a979dccc21bc320b4e9","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.5.0_1780971926854_0.8063896439578051","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.5.1":{"name":"@aggiovato/yrest","version":"0.5.1","keywords":["yaml","rest","mock","api","cli","fastify"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.5.1","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"db9d6219fd323f35f12a7c54f35edaf782c0add3","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.5.1.tgz","fileCount":10,"integrity":"sha512-aUkMO72ytPKJtvYMz2vs9BMCiBVwFmWrom74tu3naMLudHGU6MPZysGquxyV6/ANX94Z2IXMv6UnojeyQYfThQ==","signatures":[{"sig":"MEUCIQCrZ/we/Sn99MVyoMmw9VHvTCZqONIPdsTarWxqB6QxRwIgDQVt6zKdNdl8XLlGSEX3THvpuw/9O3lXEg2r9VEF2BA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":248309},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"3d0891b328d1f3a6b1a3c9c8310da771285f9280","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config REST API mock server powered by a YAML file","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.5.1_1781049108763_0.7101370931301407","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."},"0.5.2":{"name":"@aggiovato/yrest","version":"0.5.2","keywords":["yaml","rest","rest-api","mock-api","mock-server","fake-api","fake-backend","json-server","frontend","testing","prototype","crud","cli","fastify","typescript"],"author":{"name":"Aggiovato"},"license":"MIT","_id":"@aggiovato/yrest@0.5.2","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"homepage":"https://github.com/aggiovato/yaml-rest#readme","bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"bin":{"yrest":"dist/cli/index.js"},"dist":{"shasum":"9272b25a8f4fae863fe24fb27125e1212ec4de34","tarball":"https://registry.npmjs.org/@aggiovato/yrest/-/yrest-0.5.2.tgz","fileCount":10,"integrity":"sha512-jlsrfpgRgEdgBlx/CDpevvQB/LAyf2h0ld8lBZLzXrc9j5RL9F+1P6yorJPrBy0PDJv5R80o/tcfwqSs7ZKr0A==","signatures":[{"sig":"MEUCIHv24J6Kia86zgbVc0xqw05fRPIo2qSqzH0xNwORSZklAiEAmFUpBEePrEVHFdFE9VLQeC4kt8LrT9lbJrWRtgZrbhY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aggiovato%2fyrest@0.5.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":259693},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"96f4bc3b8f34bac83ba50df91844124a051a3f52","scripts":{"dev":"tsup --watch","lint":"eslint src tests","test":"vitest","build":"tsup","format":"prettier --write .","lint:fix":"eslint src tests --fix","test:run":"vitest run","typecheck":"tsc --noEmit","format:check":"prettier --check .","prepublishOnly":"npm run test:run && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:47ddd35b-a202-444c-99f8-c139fb97e840"}},"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"_npmVersion":"11.13.0","description":"Zero-config YAML REST API mock server. Create a full CRUD fake backend from a db.yml file for frontend development, testing and prototyping.","directories":{},"_nodeVersion":"24.16.0","dependencies":{"zod":"^3.23.8","yaml":"^2.4.5","fastify":"^5.0.0","commander":"^12.1.0","@fastify/cors":"^10.0.0"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.1.0","eslint":"^10.4.1","vitest":"^4.1.8","prettier":"^3.8.3","@eslint/js":"^10.0.1","typescript":"^5.5.0","@types/node":"^22.19.20","typescript-eslint":"^8.60.1","eslint-config-prettier":"^10.1.8"},"_npmOperationalInternal":{"tmp":"tmp/yrest_0.5.2_1781137277083_0.4334054433190748","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package moved to @yrest/cli. Please update your dependency."}},"time":{"created":"2026-06-04T00:36:40.015Z","modified":"2026-06-13T14:38:22.652Z","0.1.0":"2026-06-04T00:36:40.316Z","0.1.1":"2026-06-06T21:23:06.785Z","0.2.0":"2026-06-07T16:23:18.636Z","0.2.1":"2026-06-07T16:36:06.099Z","0.2.2":"2026-06-07T17:01:53.774Z","0.3.0":"2026-06-07T21:03:22.421Z","0.4.0":"2026-06-07T23:25:16.612Z","0.5.0":"2026-06-09T02:25:27.005Z","0.5.1":"2026-06-09T23:51:48.911Z","0.5.2":"2026-06-11T00:21:17.232Z"},"bugs":{"url":"https://github.com/aggiovato/yaml-rest/issues"},"author":{"name":"Aggiovato"},"license":"MIT","homepage":"https://github.com/aggiovato/yaml-rest#readme","keywords":["yaml","rest","rest-api","mock-api","mock-server","fake-api","fake-backend","json-server","frontend","testing","prototype","crud","cli","fastify","typescript"],"repository":{"url":"git+https://github.com/aggiovato/yaml-rest.git","type":"git"},"description":"Zero-config YAML REST API mock server. Create a full CRUD fake backend from a db.yml file for frontend development, testing and prototyping.","maintainers":[{"name":"aggiovato","email":"aggiovato@gmail.com"}],"readme":"# yrest\n\n![npm version](https://img.shields.io/npm/v/@aggiovato/yrest)\n![npm downloads](https://img.shields.io/npm/dw/@aggiovato/yrest)\n![license](https://img.shields.io/npm/l/@aggiovato/yrest)\n![CI](https://github.com/aggiovato/yaml-rest/actions/workflows/ci.yml/badge.svg)\n![Node](https://img.shields.io/node/v/@aggiovato/yrest)\n![TypeScript](https://img.shields.io/badge/TypeScript-ready-blue)\n\nZero-config YAML REST API mock server. Define your data in a `db.yml` file and get a fully functional CRUD fake backend in seconds — no backend required.\n\n```yaml\n# db.yml\nusers:\n  - id: 1\n    name: Ana\n    email: ana@test.com\n\nposts:\n  - id: 1\n    title: First post\n    userId: 1\n```\n\n```bash\nnpx @aggiovato/yrest serve db.yml\n```\n\n```\nGET  /users          → [{ id: 1, name: \"Ana\", email: \"ana@test.com\" }]\nGET  /users/1        → { id: 1, name: \"Ana\", email: \"ana@test.com\" }\nPOST /users          → 201 Created\nPUT  /users/1        → 200 OK\nPATCH /users/1       → 200 OK\nDELETE /users/1      → 200 OK\n```\n\n---\n\n## Why yrest?\n\nA YAML-first alternative to json-server for frontend development.\n\n| Feature                                      | yrest | json-server |\n| -------------------------------------------- | :---: | :---------: |\n| YAML database                                |  ✅   |     ❌      |\n| Zero config                                  |  ✅   |     ✅      |\n| Full CRUD                                    |  ✅   |     ✅      |\n| Field operators (`_gte`, `_like`, `_regex`…) |  ✅   |     ⚠️      |\n| Full-text search                             |  ✅   |     ✅      |\n| Relations + nested routes                    |  ✅   |     ✅      |\n| Field projection (`_fields`)                 |  ✅   |     ❌      |\n| Pageable mode (envelope response)            |  ✅   |     ❌      |\n| Custom static routes (`_routes`)             |  ✅   |     ❌      |\n| Template variables in responses              |  ✅   |     ❌      |\n| Handler functions (JS logic)                 |  ✅   |     ❌      |\n| Snapshot endpoints                           |  ✅   |     ❌      |\n| Config file                                  |  ✅   |     ⚠️      |\n| API overview page (`/_about`)                |  ✅   |     ❌      |\n| Watch mode                                   |  ✅   |     ✅      |\n| Readonly mode                                |  ✅   |     ❌      |\n| Atomic writes                                |  ✅   |     ✅      |\n| TypeScript types                             |  ✅   |     ❌      |\n\n---\n\n## Install\n\n```bash\nnpm install -D @aggiovato/yrest\n```\n\nOr run directly with npx (no install needed):\n\n```bash\nnpx @aggiovato/yrest serve db.yml\n```\n\n---\n\n## Quick start\n\n```bash\n# Create a sample db.yml and yrest.config.yml\nnpx @aggiovato/yrest init\n\n# Start the server\nnpx @aggiovato/yrest serve db.yml\n```\n\n```\nyrest  ·  http://localhost:3070\n\nCollections (base: /):\n  CRUD  /users\n  CRUD  /posts\n\nMeta:\n  GET    /_about\n```\n\nOpen `http://localhost:3070/_about` for a live overview of all generated endpoints, active modes and ready-to-run `curl` examples.\n\n---\n\n## Commands\n\n### `init`\n\nCreates a sample `db.yml` and a `yrest.config.yml` template in the current directory.\n\n```bash\nnpx @aggiovato/yrest init                            # basic sample (default)\nnpx @aggiovato/yrest init --sample relational        # with _rel relations\nnpx @aggiovato/yrest init --file api.yml             # custom filename\nnpx @aggiovato/yrest init --sample relational --file api.yml\n```\n\n| Flag       | Default  | Description                         |\n| ---------- | -------- | ----------------------------------- |\n| `--file`   | `db.yml` | Output filename                     |\n| `--sample` | `basic`  | Sample data (`basic`, `relational`) |\n\n**Samples:**\n\n- `basic` — two independent collections: `users` and `products`\n- `relational` — three collections with `_rel` relationships: `users`, `posts` and `comments`\n\n---\n\n### `serve`\n\nStarts the mock server.\n\n```bash\nnpx @aggiovato/yrest serve db.yml\nnpx @aggiovato/yrest serve db.yml --port 3001 --host 0.0.0.0\nnpx @aggiovato/yrest serve db.yml --base /api --watch\nnpx @aggiovato/yrest serve db.yml --readonly --delay 300\nnpx @aggiovato/yrest serve db.yml --pageable 20\nnpx @aggiovato/yrest serve db.yml --snapshot\nnpx @aggiovato/yrest serve db.yml --handlers yrest.handlers.js\n```\n\n| Flag                | Default     | Description                                                             |\n| ------------------- | ----------- | ----------------------------------------------------------------------- |\n| `--port`            | `3070`      | Port to listen on                                                       |\n| `--host`            | `localhost` | Host to bind                                                            |\n| `--base`            | _(none)_    | Prefix for all routes (e.g. `/api`)                                     |\n| `--watch`           | `false`     | Reload `db.yml` automatically when it changes on disk                   |\n| `--readonly`        | `false`     | Reject all write operations (POST, PUT, PATCH, DELETE) with `405`       |\n| `--delay <ms>`      | `0`         | Add a fixed delay to all responses (simulates network latency)          |\n| `--pageable [n]`    | `false`     | Wrap GET collection responses in `{ data, pagination }`. Optional limit |\n| `--snapshot`        | `false`     | Save initial state snapshot and expose `/_snapshot` endpoints           |\n| `--handlers <file>` | _(none)_    | Path to a JS file exporting handler functions for custom routes         |\n\nAll flags can also be set in `yrest.config.yml` (see below). CLI flags always take priority over the config file.\n\n---\n\n## Configuration file\n\n`yrest init` creates a `yrest.config.yml` alongside `db.yml`. Options defined here apply every time you run `serve` without needing to type flags:\n\n```yaml\n# yrest.config.yml\nfile: db.yml\nport: 3070\nhost: localhost\n# base: /api\n# watch: false\n# readonly: false\n# delay: 0\n# pageable: false   # true (limit 10), or a number (custom limit)\n# snapshot: false\n# handlers: yrest.handlers.js\n```\n\n**Priority order** (highest wins): CLI flags → `yrest.config.yml` → schema defaults.\n\n---\n\n## Database format\n\n```yaml\nusers:\n  - id: 1\n    name: Ana\n    email: ana@test.com\n  - id: 2\n    name: Luis\n    email: luis@test.com\n\nposts:\n  - id: 1\n    title: First post\n    userId: 1\n```\n\nEach top-level key becomes a resource with full CRUD endpoints.\n\n---\n\n## Generated endpoints\n\nFor each resource in `db.yml`:\n\n```\nGET     /users          List all\nGET     /users/:id      Get one\nPOST    /users          Create\nPUT     /users/:id      Replace\nPATCH   /users/:id      Partial update\nDELETE  /users/:id      Delete\n```\n\nWith `--base /api` all routes are prefixed: `/api/users`, `/api/users/:id`, etc.\n\n---\n\n## Query params\n\nAll query params can be combined freely.\n\n### Filtering\n\nReturn only items that match one or more field values:\n\n```\nGET /users?name=Ana\nGET /users?role=admin&active=true\n```\n\nComparison is case-sensitive and converts types to string (`?id=1` matches numeric `id: 1`).\n\nRepeated params are treated as OR — any match passes:\n\n```\nGET /users?role=admin&role=editor    # returns admins and editors\n```\n\n### Field operators\n\nAppend an operator suffix to any field name:\n\n```\nGET /users?age_gte=18               # age >= 18\nGET /users?age_lte=65               # age <= 65\nGET /users?status_ne=inactive       # status != \"inactive\"\nGET /users?name_like=ana            # name contains \"ana\" (case-insensitive)\nGET /users?name_start=A             # name starts with \"A\" (case-insensitive)\nGET /users?email_regex=@gmail\\.com  # email matches regex (case-insensitive)\n```\n\n| Suffix   | Type             | Description                      |\n| -------- | ---------------- | -------------------------------- |\n| `_gte`   | numeric / string | Greater than or equal            |\n| `_lte`   | numeric / string | Less than or equal               |\n| `_ne`    | any              | Not equal                        |\n| `_like`  | string           | Case-insensitive substring match |\n| `_start` | string           | Case-insensitive prefix match    |\n| `_regex` | string           | Case-insensitive regex match     |\n\n### Full-text search\n\nSearch across all scalar fields of every item (case-insensitive substring match):\n\n```\nGET /users?_q=ana\nGET /posts?_q=javascript\n```\n\nAn item passes if any string or number field contains the search term.\n\n### Sorting\n\n```\nGET /users?_sort=name              # ascending (default)\nGET /users?_sort=name&_order=desc  # descending\n```\n\nString fields are compared case-insensitively. Items missing the sort field are pushed to the end.\n\n### Pagination\n\n**Without `--pageable`** (default):\n\n```\nGET /users?_page=1&_limit=10   # page 1, 10 items per page\nGET /users?_limit=5            # first 5 items\n```\n\nWhen `_page` or `_limit` are used, the response includes an `X-Total-Count` header with the total number of items before pagination.\n\n**With `--pageable`** (or `pageable: true` in config):\n\nEvery GET collection response is automatically wrapped in a `{ data, pagination }` envelope:\n\n```bash\nnpx @aggiovato/yrest serve db.yml --pageable      # default limit: 10\nnpx @aggiovato/yrest serve db.yml --pageable 20   # custom limit: 20\n```\n\n```json\n{\n  \"data\": [\n    { \"id\": 1, \"name\": \"Ana\" },\n    { \"id\": 2, \"name\": \"Luis\" }\n  ],\n  \"pagination\": {\n    \"page\": 1,\n    \"limit\": 10,\n    \"totalItems\": 23,\n    \"totalPages\": 3,\n    \"isFirst\": true,\n    \"isLast\": false,\n    \"hasNext\": true,\n    \"hasPrev\": false\n  }\n}\n```\n\nThe `?_page` and `?_limit` query params still work in pageable mode to navigate pages.\n\n### Field projection\n\nReturn only specific fields in the response:\n\n```\nGET /users?_fields=id,name\nGET /posts?_fields=id,title,userId\n```\n\nWorks on both collection and single-item endpoints.\n\n### Relation embedding (`_expand`)\n\nEmbed a related parent object directly into the response using the `_rel` block (see [Relational data](#relational-data)):\n\n```\nGET /posts?_expand=user           # embed user object in each post\nGET /posts/1?_expand=user         # embed in a single item\n```\n\nBoth syntaxes are supported:\n\n```\n?_expand=author,category          # comma-separated\n?_expand=author&_expand=category  # repeated param\n```\n\nUnresolvable keys are silently ignored. Works on all operations: GET, POST, PUT, PATCH, DELETE.\n\n### Embed children (`_embed`)\n\nEmbed related child collections directly into a parent item:\n\n```\nGET /users/1?_embed=posts         # embed all posts where userId === 1\nGET /users?_embed=posts           # embed posts in every user\n```\n\nBoth syntaxes are supported:\n\n```\n?_embed=posts,comments            # comma-separated\n?_embed=posts&_embed=comments     # repeated param\n```\n\nRequires `_rel` to be declared (see [Relational data](#relational-data)).\n\n### Combined example\n\n```\nGET /posts?userId=1&_sort=title&_order=asc&_page=1&_limit=5&_expand=user&_fields=id,title,user\n```\n\nReturns the first 5 posts by user 1, sorted alphabetically by title, with the user object embedded, returning only `id`, `title` and `user` fields.\n\n---\n\n## Relational data\n\nUse `_rel` to declare foreign key relationships between collections:\n\n```yaml\n_rel:\n  posts:\n    userId: users\n\nusers:\n  - id: 1\n    name: Ana\n\nposts:\n  - id: 1\n    title: First post\n    userId: 1\n```\n\nThis enables:\n\n**Nested routes:**\n\n```\nGET /users/1/posts    # all posts where userId === 1\n```\n\n**Embed parent with `?_expand`:**\n\n```\nGET /posts/1?_expand=user   →  { id: 1, title: \"First post\", userId: 1, user: { id: 1, name: \"Ana\" } }\n```\n\n**Embed children with `?_embed`:**\n\n```\nGET /users/1?_embed=posts   →  { id: 1, name: \"Ana\", posts: [{ id: 1, title: \"First post\", userId: 1 }] }\n```\n\n---\n\n## Custom routes\n\nDefine endpoints that don't fit CRUD directly in `db.yml` using the `_routes` block.\n\n### Static responses\n\n```yaml\n_routes:\n  - method: POST\n    path: /login\n    response:\n      status: 200\n      body:\n        token: fake-jwt-token-abc123\n\n  - method: POST\n    path: /logout\n    response:\n      status: 204\n\n  - method: GET\n    path: /dashboard/stats\n    response:\n      status: 200\n      headers:\n        Cache-Control: no-store\n      body:\n        users: 150\n        revenue: 4820.50\n```\n\n- `method` is case-insensitive. `path` supports Fastify params (`:id`).\n- `response.status` defaults to `200`. `response.body` is any YAML value.\n- Custom routes are registered before resource routes and always take priority.\n- Shown in `/_about` under \"Custom routes\".\n\n### Template variables\n\nInterpolate request data into the response body using `{{}}` syntax:\n\n```yaml\n_routes:\n  - method: GET\n    path: /users/:id/summary\n    response:\n      status: 200\n      body:\n        requestedId: \"{{params.id}}\"\n        timestamp: \"{{now}}\"\n\n  - method: POST\n    path: /echo\n    response:\n      status: 200\n      body:\n        received: \"{{body}}\"\n        query: \"{{query}}\"\n        requestId: \"{{uuid}}\"\n```\n\nAvailable variables:\n\n| Variable        | Description                                         |\n| --------------- | --------------------------------------------------- |\n| `{{params.X}}`  | URL parameter (e.g. `{{params.id}}`)                |\n| `{{query.X}}`   | Query string param (e.g. `{{query.page}}`)          |\n| `{{body}}`      | Full request body                                   |\n| `{{body.X}}`    | Field from the request body (e.g. `{{body.email}}`) |\n| `{{headers.X}}` | Request header value                                |\n| `{{now}}`       | Current UTC timestamp (ISO 8601)                    |\n| `{{uuid}}`      | Random UUID v4                                      |\n\nWhen a field contains only a single `{{variable}}` placeholder, the resolved value preserves its original type (number, boolean, object). When embedded in a larger string it is stringified.\n\n### Handler functions\n\nFor routes that need real logic (conditional responses, stateful mocks, request inspection), reference a JavaScript function via the `handler:` field:\n\n```yaml\n_routes:\n  - method: POST\n    path: /login\n    handler: login\n    response: # optional fallback if handler throws\n      status: 200\n      body: { token: fake }\n\n  - method: GET\n    path: /auth/me\n    handler: getCurrentUser\n```\n\nCreate a `yrest.handlers.js` file in the same directory as `db.yml`:\n\n```js\n// yrest.handlers.js\nexport async function login(req) {\n  const { email, password } = req.body ?? {};\n  if (password !== \"secret\") return { status: 401, body: { error: \"Invalid credentials\" } };\n  return { status: 200, body: { token: `tok-${email}` } };\n}\n\nexport async function getCurrentUser(req) {\n  return { status: 200, body: { id: 1, name: \"Ana\", role: \"admin\" } };\n}\n```\n\nPass the file to the server with `--handlers`:\n\n```bash\nnpx @aggiovato/yrest serve db.yml --handlers yrest.handlers.js\n```\n\n**Handler signature:**\n\n```ts\ntype HandlerRequest = {\n  params: Record<string, string>;\n  query: Record<string, string | string[]>;\n  body: unknown;\n  headers: Record<string, string | string[]>;\n};\n\ntype HandlerResponse = {\n  status?: number; // defaults to 200\n  body?: unknown;\n  headers?: Record<string, string>;\n};\n\ntype Handler = (req: HandlerRequest) => HandlerResponse | Promise<HandlerResponse>;\n```\n\nIf a named handler is not found in the file, the server returns `501`. If the handler throws, it returns `500`. If a `response:` block is defined alongside `handler:`, it is used as fallback only when the handler itself throws.\n\n---\n\n## Server modes\n\n### Watch mode\n\nAutomatically reloads `db.yml` when it changes on disk — useful when you edit the file manually while the server is running:\n\n```bash\nnpx @aggiovato/yrest serve db.yml --watch\n```\n\n> **Note:** Watch mode reloads data in existing collections. Adding or removing entire collections requires a server restart.\n\n### Readonly mode\n\nRejects all write operations with `405 Method Not Allowed`:\n\n```bash\nnpx @aggiovato/yrest serve db.yml --readonly\n```\n\nUseful to expose a stable read-only snapshot for demos or CI environments.\n\n### Delay mode\n\nAdds a fixed delay (in milliseconds) to every response to simulate real network latency:\n\n```bash\nnpx @aggiovato/yrest serve db.yml --delay 500   # 500ms on every response\n```\n\n### Snapshot mode\n\nSaves the initial database state at startup and exposes three meta endpoints to inspect, save and restore it:\n\n```bash\nnpx @aggiovato/yrest serve db.yml --snapshot\n```\n\n| Endpoint                | Description                                                         |\n| ----------------------- | ------------------------------------------------------------------- |\n| `GET /_snapshot`        | Returns snapshot metadata (saved time + item counts per collection) |\n| `POST /_snapshot/save`  | Replaces the snapshot with the current database state               |\n| `POST /_snapshot/reset` | Restores the database to the last saved snapshot                    |\n\nUseful for test suites that need a clean reset between runs or demos that need a predictable starting state.\n\n---\n\n## API overview page\n\nEvery running server exposes `GET /_about` — a self-contained HTML page listing all generated endpoints, custom routes, active modes, query param reference and ready-to-run `curl` examples derived from your actual `db.yml`:\n\n```bash\nopen http://localhost:3070/_about\n```\n\nThe page reflects the live state of the server, so it updates automatically in watch mode.\n\n---\n\n## HTTP responses\n\n| Status | When                                                                 |\n| ------ | -------------------------------------------------------------------- |\n| `200`  | Successful GET, PUT, PATCH, DELETE                                   |\n| `201`  | Successful POST                                                      |\n| `400`  | Invalid or missing request body                                      |\n| `404`  | Resource or id not found                                             |\n| `405`  | Write operation in readonly mode                                     |\n| `500`  | Error reading or writing the YAML file                               |\n| `501`  | Handler referenced in `_routes` is not exported by the handlers file |\n\nDELETE returns the deleted item as confirmation.\n\n---\n\n## ID generation\n\nIf a POST body does not include an `id`, yrest assigns the next incremental integer automatically. If the body includes an `id`, it is respected.\n\n## Persistence\n\nAll write operations (POST, PUT, PATCH, DELETE) are saved back to `db.yml` immediately using an atomic write strategy (write to temp file → rename), so data is never corrupted even if the process is interrupted.\n\n## CORS\n\nCORS is enabled by default, so you can call the API from any frontend running on a different port without extra configuration.\n\n---\n\n## Frontend usage\n\n```ts\n// List all\nconst users = await fetch(\"http://localhost:3070/users\").then((r) => r.json());\n\n// Filter + operators + search\nconst res = await fetch(\"http://localhost:3070/users?age_gte=18&name_like=ana&_q=dev\");\n\n// Sort + paginate + project fields\nconst res = await fetch(\"http://localhost:3070/users?_sort=name&_page=1&_limit=10&_fields=id,name\");\n\n// Embed related object (parent)\nconst post = await fetch(\"http://localhost:3070/posts/1?_expand=user\").then((r) => r.json());\n// → { id: 1, title: \"...\", userId: 1, user: { id: 1, name: \"Ana\" } }\n\n// Embed children\nconst user = await fetch(\"http://localhost:3070/users/1?_embed=posts\").then((r) => r.json());\n// → { id: 1, name: \"Ana\", posts: [{ id: 1, title: \"First post\", userId: 1 }] }\n\n// Create\nawait fetch(\"http://localhost:3070/users\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ name: \"Carlos\", email: \"carlos@test.com\" }),\n});\n\n// Partial update\nawait fetch(\"http://localhost:3070/users/1\", {\n  method: \"PATCH\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ name: \"Ana Updated\" }),\n});\n\n// Delete\nawait fetch(\"http://localhost:3070/users/1\", { method: \"DELETE\" });\n\n// Custom route with handler\nconst session = await fetch(\"http://localhost:3070/login\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({ email: \"ana@test.com\", password: \"secret\" }),\n}).then((r) => r.json());\n// → { token: \"tok-ana@test.com\" }\n```\n\n## Use in package.json scripts\n\n```json\n{\n  \"scripts\": {\n    \"mock\": \"yrest serve db.yml\",\n    \"mock:watch\": \"yrest serve db.yml --watch\",\n    \"mock:readonly\": \"yrest serve db.yml --readonly --delay 200\"\n  }\n}\n```\n\n---\n\n## Contributing\n\n### Prerequisites\n\n- Node.js >= 20\n- [Task](https://taskfile.dev) — task runner (`brew install go-task` / `scoop install task` / [other methods](https://taskfile.dev/installation/))\n\n### Task commands\n\nRun `task --list` to see all available commands.\n\n#### Development\n\n| Command                 | What it does                                                           |\n| ----------------------- | ---------------------------------------------------------------------- |\n| `task test`             | Runs the full test suite once                                          |\n| `task test:watch`       | Runs tests in watch mode — reruns on every file change                 |\n| `task build`            | Compiles TypeScript to `dist/` via tsup                                |\n| `task dev`              | Builds once, then starts watch-build + server from `dist/` in parallel |\n| `task serve:dist`       | Builds and starts the server from the local `dist/`                    |\n| `task serve:dist:watch` | Builds and starts the server with `--watch` (reloads db.yml on change) |\n| `task serve:npx`        | Starts the published npm version (useful to compare against local)     |\n| `task serve:npx:watch`  | Starts the published npm version with `--watch`                        |\n| `task preflight`        | Full pre-push check: format, lint, typecheck and tests in order        |\n\n#### Release\n\n| Command              | What it does                                                   |\n| -------------------- | -------------------------------------------------------------- |\n| `task release:patch` | Bumps `x.x.N`, creates a git commit and tag                    |\n| `task release:minor` | Bumps `x.N.0`, creates a git commit and tag                    |\n| `task release:major` | Bumps `N.0.0`, creates a git commit and tag                    |\n| `task publish`       | Runs tests + build and publishes to npm (requires `npm login`) |\n\n### Development workflow\n\n**Day-to-day work:**\n\n```bash\ntask test:watch   # keep this running in one terminal\ntask dev          # keep this running in another terminal\n```\n\n`test:watch` reruns the suite on every save so you catch regressions immediately. `dev` rebuilds and serves so you can call the endpoints manually while you work.\n\n**Before pushing:**\n\n```bash\ntask preflight    # format + lint + typecheck + tests in one command\n```\n\n**Good practices:**\n\n- Write tests for every new feature or bug fix before opening a PR.\n- Keep `db.yml` in a valid state — it is used as the default file when running local servers.\n- `dist/` is gitignored and generated at build time; never commit it manually.\n- Version bumps are done with `task release:*`, not by editing `package.json` directly — the Task command also creates the git tag that triggers the publish pipeline.\n\n### Release workflow\n\nReleases are fully automated via GitHub Actions once a version tag is pushed:\n\n```bash\n# 1. Make sure everything is clean\ntask preflight\n\n# 2. Bump the version (choose one)\ntask release:patch   # bug fixes\ntask release:minor   # new features, backwards compatible\ntask release:major   # breaking changes\n\n# 3. Push the commit and the tag\ngit push && git push --tags\n```\n\nStep 3 triggers two GitHub Actions pipelines automatically:\n\n- **CI** — runs on every push to `main` and on every PR. Executes typecheck + tests on Node 20 and Node 22.\n- **Publish** — runs only when a `v*` tag is pushed. Runs tests + build and publishes to npm using Trusted Publishing (OIDC — no tokens stored as secrets).\n\n### CI/CD pipelines\n\n```\npush to main / PR open\n        │\n        ▼\n    [CI workflow]\n    ├── Node 20: lint + format check + typecheck + tests\n    └── Node 22: lint + format check + typecheck + tests\n\npush tag v*\n        │\n        ▼\n    [Publish workflow]\n    ├── tests + build  (via prepublishOnly)\n    └── npm publish --provenance  (via Trusted Publishing / OIDC, Node 24)\n```\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}