{"_id":"@duyquangnvx/webnovel-scraper","_rev":"7-5bfec5ca1cfecae944674d14571a34d8","name":"@duyquangnvx/webnovel-scraper","dist-tags":{"latest":"0.3.3"},"versions":{"0.0.0":{"name":"@duyquangnvx/webnovel-scraper","version":"0.0.0","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"author":{"name":"duyquangnvx"},"license":"MIT","_id":"@duyquangnvx/webnovel-scraper@0.0.0","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"dist":{"shasum":"30077a41583abfbdd4473a1145658be8eba0eb3a","tarball":"https://registry.npmjs.org/@duyquangnvx/webnovel-scraper/-/webnovel-scraper-0.0.0.tgz","fileCount":7,"integrity":"sha512-IVP8rN5pS15g4bEKuW5dRFY5NeSVR5nBiC3LN0G9xYg8w5tDtOENgu0Pg3pD//AM1B/1UUTJfGjPuFkSL9I+6g==","signatures":[{"sig":"MEYCIQCYbnYY6IzdojGD2Df3f5T+XGJyW7Ip5uhG4cdzWg8TVQIhAJqZpGk69pfNzQ5gTyXcSPqOOoUke68SG/L/GUsnhA7I","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":34271},"main":"./dist/index.js","type":"module","_from":"file:duyquangnvx-webnovel-scraper-0.0.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"lint":"biome check .","test":"vitest run","build":"tsup","format":"biome check --write .","release":"pnpm publish --access public","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"_resolved":"C:\\Users\\QuangVD\\AppData\\Local\\Temp\\d458da4ee17cbda2b9724d1652346f71\\duyquangnvx-webnovel-scraper-0.0.0.tgz","_integrity":"sha512-IVP8rN5pS15g4bEKuW5dRFY5NeSVR5nBiC3LN0G9xYg8w5tDtOENgu0Pg3pD//AM1B/1UUTJfGjPuFkSL9I+6g==","repository":{"url":"git+https://github.com/duyquangnvx/webnovel-scraper.git","type":"git"},"_npmVersion":"10.9.4","description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","directories":{},"_nodeVersion":"22.21.1","dependencies":{"zod":"^3.23.8","cheerio":"^1.0.0","got-scraping":"^4.0.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","vitest":"^2.1.0","lefthook":"^2.1.9","typescript":"^5.6.0","@types/node":"^20.14.0","@biomejs/biome":"^2.5.2","@vitest/coverage-v8":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/webnovel-scraper_0.0.0_1783439371535_0.967078783067489","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@duyquangnvx/webnovel-scraper","version":"0.1.0","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"author":{"name":"duyquangnvx"},"license":"MIT","_id":"@duyquangnvx/webnovel-scraper@0.1.0","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"dist":{"shasum":"8447df0c46aafdc8dea16d9c325fb406ce77d51e","tarball":"https://registry.npmjs.org/@duyquangnvx/webnovel-scraper/-/webnovel-scraper-0.1.0.tgz","fileCount":7,"integrity":"sha512-fkJNcdYZ9Lk9NyCQH+ND7e4bTKZgJ0c0MankFfwYYzUHKESipjBbu2pafUIdP0VKoZCyqxvamuFPx0dVGwxtaw==","signatures":[{"sig":"MEUCIDputvVjju0XmdtRvjMnKtF6+V4iNMVrFC4iPtbg0gV+AiEA2Ej3LG6cD2/Ciysv1A6lmGO7tJHzR5Vu+MFA/FIe3OE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76192},"main":"./dist/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"2ed1737383ab10decf269148739aaf98f02a50f8","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup","format":"biome check --write .","prepare":"lefthook install","release":"pnpm publish --access public","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"pnpm build"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/webnovel-scraper.git","type":"git"},"_npmVersion":"10.8.2","description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"zod":"^3.23.8","cheerio":"^1.0.0","p-queue":"^9.3.1","got-scraping":"^4.0.6"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","devDependencies":{"tsup":"^8.3.0","vitest":"^2.1.0","lefthook":"^2.1.9","typescript":"^5.6.0","@types/node":"^20.14.0","@biomejs/biome":"^2.5.2","@vitest/coverage-v8":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/webnovel-scraper_0.1.0_1783523865167_0.22205354622546736","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@duyquangnvx/webnovel-scraper","version":"0.2.0","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"author":{"name":"duyquangnvx"},"license":"MIT","_id":"@duyquangnvx/webnovel-scraper@0.2.0","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"dist":{"shasum":"76549c8efe48f4ae638ae5de7b65ecf86c0b6cae","tarball":"https://registry.npmjs.org/@duyquangnvx/webnovel-scraper/-/webnovel-scraper-0.2.0.tgz","fileCount":7,"integrity":"sha512-cuijcwQZ6kQPFF5vSCxy6mp2tqigKBbTjA7Lmh+iyoknYlgymd+mr391DmrSfV1vI4IW+PxFYB1AloVAeEDRPw==","signatures":[{"sig":"MEUCIGHFB+jjx/Fn2sx3zIwud3MOkXT0ObffOvlddeh+URSWAiEAm5GN7XG2Z32BA3Q7W837vFoZq8hhTDjQZyNtkggX8ow=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":98667},"main":"./dist/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"350d6b5e96acf17c892c9fe1e6b0acd63aacccd9","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup","format":"biome check --write .","prepare":"lefthook install","release":"pnpm publish --access public","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"pnpm build"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/webnovel-scraper.git","type":"git"},"_npmVersion":"10.9.8","description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^3.23.8","cheerio":"^1.0.0","p-queue":"^9.3.1","got-scraping":"^4.0.6","html-to-text":"^10.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","devDependencies":{"tsup":"^8.3.0","vitest":"^2.1.0","lefthook":"^2.1.9","typescript":"^5.6.0","@types/node":"^20.14.0","@biomejs/biome":"^2.5.2","@types/html-to-text":"^9.0.4","@vitest/coverage-v8":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/webnovel-scraper_0.2.0_1783603708363_0.29003865397323025","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@duyquangnvx/webnovel-scraper","version":"0.3.0","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"author":{"name":"duyquangnvx"},"license":"MIT","_id":"@duyquangnvx/webnovel-scraper@0.3.0","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"dist":{"shasum":"62878df50939b754091e68aefa520035b5f803c1","tarball":"https://registry.npmjs.org/@duyquangnvx/webnovel-scraper/-/webnovel-scraper-0.3.0.tgz","fileCount":7,"integrity":"sha512-dfjTyiq5M6qubKGQLTiuf0wj2uT/TaWqoFWAG5HT7ucFqe22zk9eJKgIvaUqpDxH3PLKmnxq/CNpGQWpjlZwVw==","signatures":[{"sig":"MEUCIQC/d/VBEECOKzELYMR2niQCETer/360hN/D7Fra2dffrAIgAmuazfShQw2NvOp9QsXNYTNl00MEkqIaDM8icGZ1Gc0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110179},"main":"./dist/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"8deb6d54a78778522f73bd84d60ec9d5b4e0c6e5","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup","format":"biome check --write .","prepare":"lefthook install","release":"pnpm publish --access public","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"pnpm build"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/webnovel-scraper.git","type":"git"},"_npmVersion":"10.9.8","description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^3.23.8","cheerio":"^1.0.0","p-queue":"^9.3.1","got-scraping":"^4.0.6","html-to-text":"^10.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","devDependencies":{"tsup":"^8.3.0","vitest":"^2.1.0","lefthook":"^2.1.9","typescript":"^5.6.0","@types/node":"^20.14.0","@biomejs/biome":"^2.5.2","@types/html-to-text":"^9.0.4","@vitest/coverage-v8":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/webnovel-scraper_0.3.0_1783743119919_0.7540307733011034","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@duyquangnvx/webnovel-scraper","version":"0.3.1","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"author":{"name":"duyquangnvx"},"license":"MIT","_id":"@duyquangnvx/webnovel-scraper@0.3.1","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"dist":{"shasum":"80cea59663bb68f85f42919ed9a83373c1403729","tarball":"https://registry.npmjs.org/@duyquangnvx/webnovel-scraper/-/webnovel-scraper-0.3.1.tgz","fileCount":7,"integrity":"sha512-SfShpFu2mCczjffhwt0n9vAemviUUIBop7j5rmOdYGs57fmUvtEi9J7Z5fRPyLOwkliLYgx61IM0EiMz4Dk61A==","signatures":[{"sig":"MEUCIQD/Ds/Z4NbICsgAT4vsDV6CW6DRjbif2UKBcFEu8B35KQIgA6vXtXiTpGYGCgsM3SNJHO2JpxZwCbhdNrTGFCUi24Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110655},"main":"./dist/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"2146b19d836733e49b06bcdead48d6ffd47f9ae1","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup","format":"biome check --write .","prepare":"lefthook install","release":"pnpm publish --access public","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"pnpm build"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/webnovel-scraper.git","type":"git"},"_npmVersion":"10.9.8","description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^3.23.8","cheerio":"^1.0.0","p-queue":"^9.3.1","got-scraping":"^4.0.6","html-to-text":"^10.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","devDependencies":{"tsup":"^8.3.0","vitest":"^2.1.0","lefthook":"^2.1.9","typescript":"^5.6.0","@types/node":"^20.14.0","@biomejs/biome":"^2.5.2","@types/html-to-text":"^9.0.4","@vitest/coverage-v8":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/webnovel-scraper_0.3.1_1783775787270_0.8550820914752719","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@duyquangnvx/webnovel-scraper","version":"0.3.2","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"author":{"name":"duyquangnvx"},"license":"MIT","_id":"@duyquangnvx/webnovel-scraper@0.3.2","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"dist":{"shasum":"2c1f7455e6dd6cc79f7a2ebdd86de259733b92d2","tarball":"https://registry.npmjs.org/@duyquangnvx/webnovel-scraper/-/webnovel-scraper-0.3.2.tgz","fileCount":7,"integrity":"sha512-SyHhJiAuNOOT2+cnhUVRcgpoIR81v0AXs+ohQdwW3FFaq8+u7BBjlCAHmnzrfBWB38rJQ3dk8yflSGE2KgNGtA==","signatures":[{"sig":"MEQCIAihln2QWlbNzelcARPC/iQJ330HokzkRO/mwCENcF89AiArSPWO/qIfPmrwSONLPpc76CWYtW0FsQshgUra+JqHZA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":111981},"main":"./dist/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"892f3393053ecd52fd3f17219bbc509a2bdc5543","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup","format":"biome check --write .","prepare":"lefthook install","release":"pnpm publish --access public","typecheck":"tsc --noEmit","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"pnpm build"},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"repository":{"url":"git+https://github.com/duyquangnvx/webnovel-scraper.git","type":"git"},"_npmVersion":"10.9.8","description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^3.23.8","cheerio":"^1.0.0","p-queue":"^9.3.1","got-scraping":"^4.0.6","html-to-text":"^10.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@9.15.0","devDependencies":{"tsup":"^8.3.0","vitest":"^2.1.0","lefthook":"^2.1.9","typescript":"^5.6.0","@types/node":"^20.14.0","@biomejs/biome":"^2.5.2","@types/html-to-text":"^9.0.4","@vitest/coverage-v8":"^2.1.0"},"_npmOperationalInternal":{"tmp":"tmp/webnovel-scraper_0.3.2_1783800204395_0.0804301309927904","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"name":"@duyquangnvx/webnovel-scraper","version":"0.3.3","description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"author":{"name":"duyquangnvx"},"repository":{"type":"git","url":"git+https://github.com/duyquangnvx/webnovel-scraper.git"},"homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"type":"module","license":"MIT","packageManager":"pnpm@9.15.0","engines":{"node":">=20"},"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","import":"./dist/browser.js"}},"publishConfig":{"access":"public"},"scripts":{"build":"tsup","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","lint":"biome check .","format":"biome check --write .","prepare":"lefthook install","prepublishOnly":"pnpm build","release":"pnpm publish --access public"},"dependencies":{"cheerio":"^1.0.0","got-scraping":"^4.0.6","html-to-text":"^10.0.0","p-queue":"^9.3.1","zod":"^3.23.8"},"peerDependencies":{"puppeteer-real-browser":"^1.4.4"},"peerDependenciesMeta":{"puppeteer-real-browser":{"optional":true}},"devDependencies":{"@biomejs/biome":"^2.5.2","@types/html-to-text":"^9.0.4","@types/node":"^20.14.0","@vitest/coverage-v8":"^2.1.0","lefthook":"^2.1.9","puppeteer-real-browser":"^1.4.4","tsup":"^8.3.0","typescript":"^5.6.0","vitest":"^2.1.0"},"pnpm":{"onlyBuiltDependencies":["esbuild"]},"_id":"@duyquangnvx/webnovel-scraper@0.3.3","gitHead":"3de7cab7d395a591a045103dbb13d2a09032dc00","_nodeVersion":"22.23.1","_npmVersion":"10.9.8","dist":{"integrity":"sha512-r9i7MfOagzM8wpATagaPM/uaqGChd3osCfn1u/7ZpMkbkGi3yqaps9MrG1x+B40YL3O1EiYWUk11JMc3Suzm9Q==","shasum":"158d4c75f4bd5ddd54b33d100eb1d75746699509","tarball":"https://registry.npmjs.org/@duyquangnvx/webnovel-scraper/-/webnovel-scraper-0.3.3.tgz","fileCount":13,"unpackedSize":132225,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHCDGYWth0TID+6jfKXQOpHYnlnoqw0REhWDa9kUFYOxAiA7gTpxY/W9MC7jDCUTXwsdpy1idbnFIMf1ohTyBWI2iQ=="}]},"_npmUser":{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"},"directories":{},"maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webnovel-scraper_0.3.3_1783848501328_0.18343925706403197"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-07T15:49:31.403Z","modified":"2026-07-12T09:28:21.598Z","0.0.0":"2026-07-07T15:49:31.671Z","0.1.0":"2026-07-08T15:17:45.313Z","0.2.0":"2026-07-09T13:28:28.525Z","0.3.0":"2026-07-11T04:12:00.053Z","0.3.1":"2026-07-11T13:16:27.406Z","0.3.2":"2026-07-11T20:03:24.542Z","0.3.3":"2026-07-12T09:28:21.483Z"},"bugs":{"url":"https://github.com/duyquangnvx/webnovel-scraper/issues"},"author":{"name":"duyquangnvx"},"license":"MIT","homepage":"https://github.com/duyquangnvx/webnovel-scraper#readme","keywords":["webnovel","scraper","truyen","vietnamese","novel","cheerio"],"repository":{"type":"git","url":"git+https://github.com/duyquangnvx/webnovel-scraper.git"},"description":"Extracts web novels (metadata, ordered chapter list, clean chapter text) from Vietnamese reading sites into typed data. Extraction-only core.","maintainers":[{"name":"duyquangnvx","email":"duyquangnvx@gmail.com"}],"readme":"# webnovel-scraper\n\nA TypeScript library for extracting web novels — novel metadata, the ordered chapter list, and clean chapter text — from popular Vietnamese reading sites. It does **extraction only**: downloading, resuming, and exporting (EPUB/TXT/JSON) are separate layers built on top.\n\nPackage: `@duyquangnvx/webnovel-scraper` (public, published on npm). Status: pre-release (`0.x` — the public API is unstable and may change between minor versions). Extraction runs end-to-end for three built-in Vietnamese sources (`truyenfull`, `dtruyen`, `sstruyen`).\n\n## Setup\n\n> Built with Node 20+, TypeScript ESM, `got-scraping` + `cheerio` + `zod`, tested with `vitest`, bundled with `tsup`. Develop with `pnpm install`, then the scripts in [CLAUDE.md](./CLAUDE.md).\n\n```bash\nnpm install @duyquangnvx/webnovel-scraper\n```\n\n## Usage\n\n```ts\nimport { createScraper } from '@duyquangnvx/webnovel-scraper'\n\nconst scraper = createScraper()\nconst info = await scraper.getNovelInfo(url)          // NovelInfo\nconst chapters = await scraper.getChapterList(url)     // ChapterRef[] — ordered, paginated\nconst content = await scraper.getChapter(chapters[0])  // ChapterContent { title, paragraphs }\n```\n\n`getChapter` also accepts a bare chapter URL (`getChapter(chapterUrl)`); the source resolves it to a `ChapterRef` first. To check a URL before scraping, `scraper.supports(url)` returns a boolean without throwing, and `scraper.supportedHosts` lists the hostnames the registry accepts.\n\nWhole-novel download, per-chapter error policy, and export are the consumer's job. The library hands back the ordered list; you drive the loop and decide what a failed chapter means. **Always** wrap each chapter in its own error boundary — one drifted or locked chapter must not abort the run (politeness is enforced per-host under the hood, so a tight loop stays safe):\n\n```ts\nimport { createScraper, ChapterLockedError, ParseError } from '@duyquangnvx/webnovel-scraper'\n\nconst scraper = createScraper()\nconst chapters = await scraper.getChapterList(novelUrl)\n\nfor (const ref of chapters) {\n  try {\n    save(ref.order, await scraper.getChapter(ref))\n  } catch (err) {\n    if (err instanceof ChapterLockedError) continue // VIP/paywall — skip\n    if (err instanceof ParseError) continue         // site drift — record & skip\n    throw err                                        // FetchError / unexpected — surface or retry\n  }\n}\n```\n\nDevelopment commands live in the table in [CLAUDE.md](./CLAUDE.md).\n\n### Custom sources & transports\n\nBuilt-in sources are produced by feeding a declarative `SelectorConfig` (per-site CSS selectors + a few typed URL functions) to `createSelectorSource`. The engine hides all shared machinery — fetch + per-host throttle/retry, pagination-follow, `html-to-text` content cleaning, zod validation. To support another static-selector site, pass your own config and register it:\n\n```ts\nimport { createScraper, createSelectorSource, builtinSources } from '@duyquangnvx/webnovel-scraper'\n\nconst mySource = createSelectorSource(myConfig)\nconst scraper = createScraper({ sources: [...builtinSources, mySource] })\n```\n\nTransports are chosen per source by its `renderingHint`. `createScraper` takes a hint-keyed `transports` map (default: a built-in static HTTP transport); a source declaring `renderingHint: 'dynamic'` with no `dynamic` transport configured throws `ConfigurationError` at construction. Authentication is bring-your-own-session — supply per-host cookies/headers when building the HTTP transport; the library never logs in:\n\n```ts\nimport { createScraper, createHttpFetcher } from '@duyquangnvx/webnovel-scraper'\n\nconst scraper = createScraper({\n  transports: {\n    static: createHttpFetcher({\n      sessions: { 'site.example': { cookie: 'sid=…' } }\n    })\n  }\n})\n```\n\n## Structure\n\n- `src/core/` — `Source` interface, `createScraper` facade, registry, errors, schemas, boundary helpers (`fetchOk`, `validate`)\n- `src/fetch/` — the `Fetcher` transport seam: a `got-scraping` HTTP fetcher with per-host throttle + retry\n- `src/selector-source/` — the declarative `createSelectorSource` engine that builds a `Source` from a `SelectorConfig`\n- `src/sources/` — one config per site (`truyenfull`, `dtruyen`, `sstruyen`): a 4-line `index.ts` + a `config.ts`\n- `docs/` — requirements, architecture, decisions (ADRs), backlog\n\nTarget layout: docs/structure.md.\n\n## Releasing\n\nReleases are automated by `.github/workflows/release.yml`: pushing a `vX.Y.Z` tag builds, publishes to npm **with provenance**, and opens a GitHub Release from the matching `CHANGELOG.md` section (see ADR-0007).\n\nOne-time setup: add an npm **automation token** as the `NPM_TOKEN` repository secret (Settings → Secrets and variables → Actions).\n\nTo cut a release:\n\n1. In `CHANGELOG.md`, move the `[Unreleased]` entries under a new `## [X.Y.Z] - YYYY-MM-DD` heading (leave a fresh empty `[Unreleased]` above), and commit.\n2. `npm version <patch|minor|major>` — bumps `package.json`, commits, and creates the `vX.Y.Z` tag.\n3. `git push --follow-tags` — CI publishes and creates the Release.\n\nThe **first** publish should be done manually (`npm publish --access public`) to claim the scoped name; wire the token and use the tag flow afterwards.\n\n## More\n\n- Requirements: docs/requirements.md\n- Architecture: docs/architecture.md\n- Decisions (ADRs): docs/adr/\n- Backlog: docs/backlog.md\n- Agent config: CLAUDE.md\n","readmeFilename":"README.md"}