{"_id":"truecopy","_rev":"35-db7aa4edcf946a9b56b5f4e17817882c","name":"truecopy","dist-tags":{"latest":"2.0.13"},"versions":{"1.0.0":{"name":"truecopy","version":"1.0.0","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","ocr","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@1.0.0","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"f9908577d486354663d227db982b878ca0565a80","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-1.0.0.tgz","fileCount":68,"integrity":"sha512-/M1zUebDckLpsCh/R9wa5XqN100A2bvr1dvzkU1D+t9urERQCxA9SrmFhTlh66jX8wUR52+GYwMXQ4pKuJgYSQ==","signatures":[{"sig":"MEUCIDuNWFWRK3x/owlJtULw7wiYGHK4CqkhLtTfMa5yXXv9AiEA3YXNNqZBU0KhCkXIpmQChasJA06FutPISt9v7VBS4Sg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":240066},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"885a10d3da294610337206bbe28c4ff6ffec4ffb","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run lint && npm run check && npm run build && npm run api && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"florianmousseau","email":"florian.mousseau@gmail.com"},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.2.0","description":"Turn a PDF, a paste or a CSV into rows, and refuse the readings you cannot trust. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_1.0.0_1785789544961_0.1593859435734013","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"truecopy","version":"1.0.1","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@1.0.1","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"b179f9a7d888414b7b815b0a7fec1b71701327f1","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-1.0.1.tgz","fileCount":69,"integrity":"sha512-YxnyPjA8F3g4lvVPF/PqWrPAhX7X3DB67hKhqAKVjT+6nl0k48KzWxp4h0Y39zzTmPz6Xd+mmPC9XyPIGLGl7w==","signatures":[{"sig":"MEUCIGDk0JruFg9Nv9cpDipumBSX679INmw+6+SQKQpscP6RAiEAvlAkacOD+aNDzfsqdNkQRX3rGX+LGSxsFovR0l5LllU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":255985},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"b92c98f1dce4e5e25de1a5215f02eca25363b1ed","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Turn a PDF, a paste or a CSV into rows, and refuse the readings you cannot trust. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_1.0.1_1786294986685_0.9008978038472191","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"truecopy","version":"1.0.2","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@1.0.2","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"9cbc0800126879c54e50952a02c3c2a3352a08be","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-1.0.2.tgz","fileCount":69,"integrity":"sha512-DNL6YkoYIklhc8iCp831w9cEoFUjRjOn4Oyiwfj2UmlKSMtyqKY5E5iJ8VLWPVPQdpAuMA+N6qWN8s+DQs6Ndg==","signatures":[{"sig":"MEUCIEhLnxd4m9IHFqfFVJccFTPICWqo/JpRE24myVRUHF8iAiEA7wubBxf/CZBmad2SWJ6XqzrmkEameGNGQPZPak9pnQc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@1.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":285535},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"641c1cb48020750f639289355c9b74bd4ba3d9a2","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_1.0.2_1786459394143_0.9174800408102346","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"truecopy","version":"1.0.3","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@1.0.3","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"585c2118c211c01d041f725735d1616cfe52f46c","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-1.0.3.tgz","fileCount":73,"integrity":"sha512-EQ4F/g0+7GpMXpXgglOWPjLrJCp1fmC6UCeikXbMYGdp1lcZx2YROZWKhEFqVQiTOBdv8iHpYu522k9eFlCwYQ==","signatures":[{"sig":"MEUCIDbl07frtE6/KLgzKcOErY2lDGnKqm5jaPLYyokfpHVYAiEAtEQgELYYBnS5IwIHMCXH4yruNTJgAvOBxrJfU9q6uSk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@1.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":310826},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"e15f122df5f7c13f1d603271fd6a6ba097224d43","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_1.0.3_1786556235070_0.7287700405529212","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"truecopy","version":"1.0.4","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@1.0.4","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"259f06c96651eeb7bc90706adf065bf5157ef533","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-1.0.4.tgz","fileCount":77,"integrity":"sha512-gZrp1EG2+iw/znr8paeUeleoP9c9lZ4IGpwWzs3M5wTJGqSU58pmFKxM01f/Sn3Ys/KLk7ywlrf2EtLWBZwoPg==","signatures":[{"sig":"MEYCIQDoH6ejdekvnosYJmSIWbswhKU7d/DrkZ4HRMdMF8hKuAIhAKlHeaDQuZhkZ48JPnQ0MhPHuWCZ+ljb/6dXxdjkcUfW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@1.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":345170},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"15437e84fbb52efe15418efdc61ee93d1e5c9eb2","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_1.0.4_1786562108099_0.8672719761746841","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"truecopy","version":"2.0.0","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.0","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"dc089298ce9d63faaf480eea35f37c6c7f719b06","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.0.tgz","fileCount":77,"integrity":"sha512-OZdZHDgN5XltxVq4iQyNKcppsv/ks/zBi7cZ5UYWpfzgpoc6xC74G9DorGS3MN/SInHWM6yoDk9N0g9saWXm+g==","signatures":[{"sig":"MEUCICrWZgKumy7riu2Kxa0WgY9pTScTacccvoi6TIRfAiURAiEA8wAZxRcIQV+h70Mm4ckwVDyTCni0E91KIDk2zgK80dE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":366530},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"4b4fc1e4e9522cc0cebd5c2e6b26dee15dc2f951","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.0_1787098843368_0.6034895602886767","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"truecopy","version":"2.0.1","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.1","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"9032eee62ff2cedf3c76c3843b9b7474e81d4ac6","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.1.tgz","fileCount":77,"integrity":"sha512-bSZ4i49rNeThkqEGswR5wPKpQDcX8+w6ZDW21MqJuA0Udr6I8j18lV4yqdTXahBvrZP9te5duHEzAvDnnrQI9A==","signatures":[{"sig":"MEQCIH91h4b2knyv6KRt4Szfx3G8ZPR2uDxytT3m+I91qQNtAiB6C5uEzzyTvso1m8JXtL/5tnqZeMb9W72vpw5M34/SWQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":376804},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"b356dabd42b3e466c6785c579175f40e1b10c3d3","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.1_1787137809558_0.48156134505625947","host":"s3://npm-registry-packages-npm-production"}},"2.0.2":{"name":"truecopy","version":"2.0.2","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.2","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"b2c3eeb0f809c93b85944d62a5bc110fdf3a8f14","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.2.tgz","fileCount":77,"integrity":"sha512-Gp/5K3y0jBbXPZDHbMlPM1Xr9D3fCfYz8FR6GIPYc0dcd5alysep05MLcOfv1EDE+Y/iqilBhHk/addN32LNPg==","signatures":[{"sig":"MEQCIAs/Ta67BRj6E9Vannkq0KzB/8pVN5PfLI+ndez24M0oAiBtn6yuL+AoIuDhOTJiV1fTj9oviYJcTNsqS6OCSPmCYA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":381352},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"417df79879c3e738fb9692ec93d51c50bd817979","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.2_1787148306998_0.8357614423260136","host":"s3://npm-registry-packages-npm-production"}},"2.0.3":{"name":"truecopy","version":"2.0.3","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.3","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs"},"dist":{"shasum":"e83374a909a51573f579d4c24c7ede0c8efb64b4","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.3.tgz","fileCount":81,"integrity":"sha512-3dlOG18r9K1Lhg8ONin9+3Ux7bmTgK4syg2f723Tbe0O36wZmFIKAfV/onttjN41DGVXzXX5WC1oB+1dCLvhsA==","signatures":[{"sig":"MEUCIQC16Gj+fx3meQeDBI3iOtI6D/lQqlAGih3CNxKRWr1GqAIgKT+ceNmgCqyd1yNRrpxkKE8UOKRXJ5nBnRYQGi0YS6s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":414136},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"eee4986fe0bee1d47b828709dade6f82fe90582d","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.3_1787182422654_0.5817320631319347","host":"s3://npm-registry-packages-npm-production"}},"2.0.4":{"name":"truecopy","version":"2.0.4","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.4","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"7ec46b5e834d41e611a764fbd87296873fca7b93","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.4.tgz","fileCount":86,"integrity":"sha512-mO55of6gCL6RaNeEecH8o0dQK4bpcjD9z/gg65RNqwQF7XHvbXavrqHnD2G97RKy87+n77OTtRcMPHLDCc/DNQ==","signatures":[{"sig":"MEQCIHOv7/fBKca3XecJtC0k/tirUw2RqWegp7NKkC+8duYoAiBTemnlQ6UANX/RjjBtYWRzrxblVyRFIVhxz5z9qGzhJQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":480249},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"bbd3ae48a12a46ed86d66b99c438f24925af06d7","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.4_1787506539635_0.4497746500273698","host":"s3://npm-registry-packages-npm-production"}},"2.0.5":{"name":"truecopy","version":"2.0.5","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.5","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"ffa737a86d37bfc5c7362b944e691bbdb527e2ba","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.5.tgz","fileCount":86,"integrity":"sha512-aoVGA1K1qEQYmAUgAqGWzBVgyuxKaVQiGLcKZr0g3F45Z8YTrTqulEnm4EDZGDF43Zp6SD6WsRk8Q2acloQ7MQ==","signatures":[{"sig":"MEYCIQDe27tmzHQLwkXzXDwSp8rda/I+eVrPDxiMQa8wwrCWnwIhAPj/G8AEfT+55C1FAjdrOpTx3BFcBp6eZeUrbvQXJ34/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":491117},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"6f9d1b272b439f3403a2b4f136b9a302363acc66","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.5_1787571523417_0.0029037844131876156","host":"s3://npm-registry-packages-npm-production"}},"2.0.6":{"name":"truecopy","version":"2.0.6","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.6","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"cad77fa6628c2577491492ae349dbe701a2d7ec9","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.6.tgz","fileCount":94,"integrity":"sha512-wHTlwgx4UeIHOJqa67o3VuH1SHOqrThMliWw1Bn/tH2RLut3xSKMXn4aE5PVFcS9I/mPynuWWAlrY+2l6goX9A==","signatures":[{"sig":"MEUCIHbZzhkqz9V4Moiv5obEFR7sqmRHoj9VT6CoH8h+U86FAiEAoB45TAhLY2Z0ip0ELnV/EMoafnErg0+RbFsEZ1AUS5Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":548553},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"39eb05ababaf2b1177d8ce3c928275061c11bc9e","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.6_1787689064292_0.0936090151165152","host":"s3://npm-registry-packages-npm-production"}},"2.0.7":{"name":"truecopy","version":"2.0.7","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.7","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"492c62a60288c5aec749eea9f1bdfd739220ad39","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.7.tgz","fileCount":94,"integrity":"sha512-+0eimGkrSTlrDhsxwjTg9eSIL5ahM+zGi/gkPBLK8XLoOkUDc7TF6SRxxqwDgxmB/s++EyVMx6uDZwVRAZ5ERQ==","signatures":[{"sig":"MEYCIQC/q4skwttUQb+ctplBYq9zdruERbYniygcmwf8J5EsVgIhAPEspXtIk/xpUGy6bfzh17JrPO65QvQtXUYbAMfUV2hI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":574005},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"ba406489ab4b834ef4e50f76a1f2982b56b66064","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.7_1787773726306_0.2996051832184006","host":"s3://npm-registry-packages-npm-production"}},"2.0.8":{"name":"truecopy","version":"2.0.8","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.8","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"9c0f6adfa4a0f636049255e5977330222cce643d","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.8.tgz","fileCount":94,"integrity":"sha512-6UE8I4gjv/FDGPnwj4e7RXNIDfEvoULFZMRFzIieDz5RuOPJCiQaKAu604a4qDQ046zbcahw5J3VIbvzJK2hxQ==","signatures":[{"sig":"MEQCIFnvRbnZqoKYyFN2kAwidIq5rYKwLJiAnnvO233ob5ebAiBrdx2/2gDWNFY5lN565vAlAVUcqThd+AX9RkHLCMPMtQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIG/lg/5WUhUlski+YBto0XksCofNSX5vfQmy0Pn1n8g6AiEArnIluC+WTaH553BfjTe9mw/ZqzHMxbUlmHCj2dvsN+4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.8","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":578497},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"37cc0682463d01d4e3a4823ae35ebbed3ad1ed40","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.8_1787920068436_0.7567583408314262","host":"s3://npm-registry-packages-npm-production"}},"2.0.9":{"name":"truecopy","version":"2.0.9","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.9","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"25ebc3202440c55a1816303575b136a39a207ffe","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.9.tgz","fileCount":94,"integrity":"sha512-4DXBPm7ogb3WQdsM8N9k1vaIfNHGIuyBKWNuo5iq0ZkD3TVIQED5IDOs6CGIV1at4NMbXR1X864nAcPvwYb2zg==","signatures":[{"sig":"MEUCIEoQzlYPU0+SMee69QgRjWLccNV38UFPl1UxKnUe+AEbAiEAy1myGvcHunf6OmU+/82OcEcd90gzjstoOCo3H9iTldk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCi16TcTUFk6Yc0ex6OHpDj4xG28ClmyrHgYFZ2KpG5rQIgFWIrkgrESyJS5lypU3oB4jjgceDeIa5yq7bzXUX0HdY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.9","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":590486},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"e533de7c981ea45b5a874b19d35366d7d0338da2","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.9_1788022844471_0.9792656565500095","host":"s3://npm-registry-packages-npm-production"}},"2.0.10":{"name":"truecopy","version":"2.0.10","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.10","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"c09a9032e501705ed89660148e628d110e6d476a","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.10.tgz","fileCount":94,"integrity":"sha512-2cKKRAtZHroppQXrmd1goRpAUGlrb2JKwlN+d8g2MrhKVE+C1gqyY+hs0PIjgh/GzCqn1vunwTL6BabiQYTO9w==","signatures":[{"sig":"MEQCIF2tLh2qUaZBU7LZO45wwu9H7kXTfL7PSRWbuj4jifhWAiBqkzJ2pb4X4tsRLQpYgLnkfsREvPinzycaQWpV7EKDIg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDdf/w7wiWikLDTGsiIrO1tpMytxo0c8aesmKEVVbJB0wIhAKQuhzElW9VJwofV0jvzD4cnJEiki13Kt7BMw+vYNNOF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.10","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":596664},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"1900c2ad7eb62acd661d07eecd28bdfabc8f8c47","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^5.66.0","jscpd":"^4.0.5","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.10_1788189278200_0.790674345269597","host":"s3://npm-registry-packages-npm-production"}},"2.0.11":{"name":"truecopy","version":"2.0.11","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.11","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"00b0b20d07f50f3cb80c630bf31c28fbb06f3396","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.11.tgz","fileCount":98,"integrity":"sha512-yS5NlcJzl/FnFihww9ql47Majudex3JJQFEHRC4wHGoD9nm/yFFEvqynOHYvrTFbub58yk8znwbyuehMbpDwnw==","signatures":[{"sig":"MEUCIGBwDA0WX7jHyp5gcw2N/2ftUzdXmFWKbEKggEn+ZJNFAiEAzTrK8RGqIU8M6veIN8teFgbMOl2E34tTORfOXTLMyao=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIAqdcZvmJr3/VdRFXBOAJgoA+7LtLxmzFNN5M5jYCdGiAiEA+svqJCd6B0mbzfH6oqolJPBDx/lMi5ZYY1c5l8egHrs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.11","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":640767},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./anchor":{"types":"./dist/anchor.d.ts","import":"./dist/anchor.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"1c424a93790f003d4f70e17dc731f890af77cb7a","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","audit":"npm audit --omit=dev --audit-level=high","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","paquet":"node scripts/paquet-publie.mjs","secrets":"gitleaks detect --source . --redact --no-banner","verifier":"npm run gate && npm run audit && npm run secrets && npm run paquet","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^6.33.0","jscpd":"^5.0.16","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.11_1788884158147_0.28414427706249956","host":"s3://npm-registry-packages-npm-production"}},"2.0.12":{"name":"truecopy","version":"2.0.12","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","_id":"truecopy@2.0.12","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"homepage":"https://truecopy.dev","bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"dist":{"shasum":"77b9a42f530d1167d76177a5b80ca1675840f5bb","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.12.tgz","fileCount":98,"integrity":"sha512-YymOPPMRcUh8YqgoSulw3AKOilJ3RPHC+RAtOYZU24E8oI8m0rnz75ysyNxvvF/ECdruiuGXvLfKh5qqNqLZjQ==","signatures":[{"sig":"MEYCIQCv1M01gcpk+ZRe/g7LhrO8EEQ3Hhu59p1NDeG8PT/SLwIhAK7g2CCEBY7PMIZEKO8W1my5ctrKCaT0O5sgsBTgjEgV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDKBkZvXI+UqbRmkfRwWfwpDQdRCA7sFfdwjrFBUgHq6wIhAIaaT+3o/C19tNl3pt4HeklKyCqge8oZWVFx2ddOkcBF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.12","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":644035},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./anchor":{"types":"./dist/anchor.d.ts","import":"./dist/anchor.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"be7df3c5e83e4939efe18cc06c80480012075ee0","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","audit":"npm audit --omit=dev --audit-level=high","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","paquet":"node scripts/paquet-publie.mjs","secrets":"gitleaks detect --source . --redact --no-banner","verifier":"npm run gate && npm run audit && npm run secrets && npm run paquet","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^6.33.0","jscpd":"^5.0.16","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/truecopy_2.0.12_1788888659969_0.33284320695349434","host":"s3://npm-registry-packages-npm-production"}},"2.0.13":{"_id":"truecopy@2.0.13","bin":{"truecopy":"bin/truecopy.mjs","truecopy-mcp":"bin/truecopy-mcp.mjs"},"bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"dist":{"shasum":"a027782c4160460ebd9030d39fd1d74d34295cae","tarball":"https://registry.npmjs.org/truecopy/-/truecopy-2.0.13.tgz","fileCount":98,"integrity":"sha512-/DcjT3S2rpWXynv/B7cm4PgKTwdXlT44XWNc0RQGnIWzXwUN4VNHPtH3K+Yqj37k7FLBbqxTJOjZAPiUVZUoUQ==","signatures":[{"sig":"MEUCIHQjyhUVxVtqLau6wsuzk24LFogIRNbKvUBtsJ/MZeSSAiEAlMhYwL2KjiyagBeZI5sMw1m3mWWrsMxOwM6xRWMkrp4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBjeJ8n0N7m+Gme7N0Y5kshqv+r2lXtsAT4wpGOitWhxAiEA17uZnjlgV2wAc9gwGiSXC9g+LTQ5Qs5hr1y3xnOvzKE="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/truecopy@2.0.13","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":647523},"name":"truecopy","type":"module","types":"./dist/index.d.ts","author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./kit":{"types":"./dist/kit.d.ts","import":"./dist/kit.js"},"./mcp":{"types":"./dist/mcp.d.ts","import":"./dist/mcp.js"},"./cite":{"types":"./dist/cite.d.ts","import":"./dist/cite.js"},"./open":{"types":"./dist/open.d.ts","import":"./dist/open.js"},"./roles":{"types":"./dist/roles.d.ts","import":"./dist/roles.js"},"./table":{"types":"./dist/table.d.ts","import":"./dist/table.js"},"./anchor":{"types":"./dist/anchor.d.ts","import":"./dist/anchor.js"},"./labels":{"types":"./dist/labels.d.ts","import":"./dist/labels.js"},"./layout":{"types":"./dist/layout.d.ts","import":"./dist/layout.js"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js"},"./columns":{"types":"./dist/columns.d.ts","import":"./dist/columns.js"},"./explain":{"types":"./dist/explain.d.ts","import":"./dist/explain.js"},"./pattern":{"types":"./dist/pattern.d.ts","import":"./dist/pattern.js"},"./records":{"types":"./dist/records.d.ts","import":"./dist/records.js"},"./classify":{"types":"./dist/classify.d.ts","import":"./dist/classify.js"},"./contract":{"types":"./dist/contract.d.ts","import":"./dist/contract.js"},"./notation":{"types":"./dist/notation.d.ts","import":"./dist/notation.js"},"./signature":{"types":"./dist/signature.d.ts","import":"./dist/signature.js"},"./package.json":"./package.json"},"gitHead":"5498ffda4e9153b8de22c2c99e2caf3d827b34c6","license":"MIT","scripts":{"api":"node scripts/api-surface.mjs","dup":"jscpd src","gate":"npm run format:check && npm run dashes && npm run lint && npm run check && npm run build && npm run api && npm run skill && npm run knip && npm run dup && npm run test:coverage","knip":"knip","lint":"eslint . --max-warnings 0","test":"vitest run","audit":"npm audit --omit=dev --audit-level=high","build":"rimraf dist && tsc -p tsconfig.build.json","check":"tsc --noEmit","skill":"node scripts/skill.mjs","dashes":"node scripts/dashes.mjs","format":"prettier --write .","paquet":"node scripts/paquet-publie.mjs","secrets":"gitleaks detect --source . --redact --no-banner","verifier":"npm run gate && npm run audit && npm run secrets && npm run paquet","format:check":"prettier --check .","test:coverage":"vitest run --coverage","prepublishOnly":"npm run gate"},"version":"2.0.13","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:756e6cb5-cb8f-4f46-ad6b-fb218c516f4c"}},"homepage":"https://truecopy.dev","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"_npmVersion":"11.19.0","description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","directories":{},"maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"knip":"^6.33.0","jscpd":"^5.0.16","eslint":"^10.4.1","rimraf":"^6.0.1","vitest":"^4.1.9","prettier":"^3.9.6","@eslint/js":"^10.0.1","pdfjs-dist":"^6.2.108","typescript":"^6.0.3","typescript-eslint":"^8.60.1","@vitest/coverage-v8":"^4.1.9","eslint-plugin-regexp":"^3.1.1","eslint-plugin-sonarjs":"^4.2.0","eslint-config-prettier":"^10.1.8"},"peerDependencies":{"pdfjs-dist":"^6.2.108"},"peerDependenciesMeta":{"pdfjs-dist":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/truecopy_2.0.13_1788896232129_0.43996880725509757"}}},"time":{"created":"2026-08-02T21:27:27.321Z","modified":"2026-09-08T19:37:12.637Z","0.0.1":"2026-08-02T21:27:27.583Z","0.0.2":"2026-08-02T21:47:50.694Z","0.0.3":"2026-08-02T23:20:17.272Z","0.0.4":"2026-08-03T00:03:24.226Z","0.0.5":"2026-08-03T00:17:55.646Z","0.1.0":"2026-08-03T00:51:25.128Z","0.1.1":"2026-08-03T01:03:38.867Z","0.1.2":"2026-08-03T01:29:58.715Z","1.0.0":"2026-08-03T20:39:05.112Z","1.0.1":"2026-08-09T17:03:06.865Z","1.0.2":"2026-08-11T14:43:14.297Z","1.0.3":"2026-08-12T17:37:15.228Z","1.0.4":"2026-08-12T19:15:08.305Z","2.0.0":"2026-08-19T00:20:43.546Z","2.0.1":"2026-08-19T11:10:09.713Z","2.0.2":"2026-08-19T14:05:07.155Z","2.0.3":"2026-08-19T23:33:42.820Z","2.0.4":"2026-08-23T17:35:39.827Z","2.0.5":"2026-08-24T11:38:43.593Z","2.0.6":"2026-08-25T20:17:44.496Z","2.0.7":"2026-08-26T19:48:46.485Z","2.0.8":"2026-08-28T12:27:48.534Z","2.0.9":"2026-08-29T17:00:44.569Z","2.0.10":"2026-08-31T15:14:38.304Z","2.0.11":"2026-09-08T16:15:58.232Z","2.0.12":"2026-09-08T17:31:00.083Z","2.0.13":"2026-09-08T19:37:12.221Z"},"bugs":{"url":"https://github.com/truecopydev/truecopy/issues"},"author":{"name":"Florian Mousseau","email":"florian.mousseau@gmail.com"},"license":"MIT","homepage":"https://truecopy.dev","keywords":["pdf","pdf-parser","pdf-parsing","pdf-table","table-extraction","extract-tables","document-parsing","data-extraction","bank-statement","invoice","schema","validation","typescript","browser"],"repository":{"url":"git+https://github.com/truecopydev/truecopy.git","type":"git"},"description":"Extract tables from a PDF, a Word document, a paste or a CSV in TypeScript, and know when the extraction cannot be trusted. Learns each document's own shape, so a new issuer needs no new configuration.","maintainers":[{"name":"florianmousseau","email":"florian.mousseau@gmail.com"}],"readme":"# truecopy\n\n**Extract tables from a PDF in TypeScript, and know when the extraction is wrong.**\n\nTurn a document into rows, and refuse the readings you cannot trust. A PDF, a Word or OpenDocument file, a paste, a CSV, an OCR page: one engine reads all of them.\n\n[![npm](https://img.shields.io/npm/v/truecopy)](https://www.npmjs.com/package/truecopy)\n[![gate](https://github.com/truecopydev/truecopy/actions/workflows/gate.yml/badge.svg)](https://github.com/truecopydev/truecopy/actions/workflows/gate.yml)\n[![license](https://img.shields.io/npm/l/truecopy)](LICENSE)\n\nA parser that returns a plausible-looking table from a document it misread is worse than one that returns nothing, because nobody checks a table that looks right. truecopy is the pipeline around whichever reader you write: the door bytes come through, the checks that catch a wrong reading, a way to **see** what it decided, and a conformance kit that goes red the day the reading stops being honest.\n\n## Try it on your worst document, right now\n\n```sh\nnpx -y -p truecopy -p pdfjs-dist truecopy a-statement.pdf\n```\n\nNo install, no project, no line of code. The engine is named on the line because it is an **optional** peer dependency and npm does not fetch one on its own: a project that only ever reads a paste or a CSV never downloads a PDF reader, and for those `npx truecopy the-file.csv` is the whole command. Left out on a PDF it says `no-engine` rather than guessing. It prints the cut it made, what each column holds, how often it is filled, and then, on its own, **what it could not vouch for**.\n\n```\npage 1 - cut at 68, 229, 356, 411, 490\n\nwhat this reading cannot vouch for:\n  - column 5 of page 1 is filled on only 2% of its rows - the cut may have invented it\n  - the pages disagree on how many columns there are (6 on 2, 7 on 1)\n```\n\n```sh\nnpm install truecopy\n```\n\n## Rows, in two lines\n\n```ts\nimport { readTable } from 'truecopy';\n\nconst { rows, warnings, findings } = await readTable(file);\n// rows     [['02/05/2026', 'CARTE AMAZON', '12,40'], …]\n// warnings ['column 3 of page 2 is filled on only 8% of its rows - the cut may have invented it']\n// findings [{ code: 'thin-column', page: 2, column: 3, shareFilled: 0.08, message: '…' }]\n```\n\nNo `kindOf`, no thresholds, no roles. If you only want the cells, destructure `rows` and go.\n\n`file` is whatever was dropped. **The cut does not care which ruler measured the page**, so the same two lines read a PDF, a table pasted out of one, a CSV and a TSV:\n\n| What was dropped                        | Where a column starts                                     |\n| --------------------------------------- | --------------------------------------------------------- |\n| a PDF                                   | the item's **x**, in points                               |\n| a table pasted with spaces              | the **character** the field starts at                     |\n| a file written with a delimiter         | the field's **index**: a CSV lines nothing up             |\n| prose, or a file that quotes its fields | nowhere: the row comes back whole, and `warnings` says so |\n\nThat last line is the rule and not the exception. A quoted CSV field may hold the delimiter itself, so splitting on it anyway would shift every column after it. truecopy hands the rows back uncut instead, because half-parsing is the failure this library exists to prevent.\n\n`explainDocument` names the ruler, so a cut is never a bare list of numbers: `cut at 100, 290` on a page, `cut at characters 7, 22` on a paste, `cut on the delimiter` on a CSV, where the columns _are_ the fields and their indices would tell you nothing.\n\nThe second field is why this is not just another extractor. **An empty `warnings` is not a promise that the reading is right**: it means nothing looked wrong from the shape of the page, which is a much smaller claim. Every warning is computed without knowing anything about your document: a page with no columns at all, a column that is almost always empty, pages cut differently from one another, a blank page in the middle.\n\n`findings` is that same list with a `code` on it, plus the page and the column it is about. A person reads the sentence; a program branches on the code, and never on English that could be reworded tomorrow.\n\nWhen the rows have to be **trusted** (when something downstream acts on them), the rest of this page is how.\n\n**A complete reader that runs, in one file and one command:**\n\n```sh\nnode example/read-a-statement.mjs\n```\n\n[`example/read-a-statement.mjs`](example/read-a-statement.mjs) builds a real PDF, opens it, prints what the reading decided, and drives it through the contract. Nothing in it is stubbed, and it needs no document from you: it makes its own.\n\n## See what the reading decided\n\nThe first thing you need when a reading comes out wrong is not a better parser. It is knowing **which of the three things** broke: the document is odd, the cut into columns is wrong, or your rule is wrong. Each calls for a different fix.\n\n```ts\nimport { openDocument, explainDocument } from 'truecopy';\n\nconst document = await openDocument(file);\n\nconsole.log(\n\texplainDocument(document, {\n\t\tsignature: {\n\t\t\tkindOf: (cell) => (isDate(cell) ? 'date' : isAmount(cell) ? 'amount' : 'text'),\n\t\t\tthresholds: {\n\t\t\t\tdate: { share: 0.6, emptyIsAnomalyAbove: 0.7 },\n\t\t\t\tamount: { share: 0.6 },\n\t\t\t\ttext: { share: 0.6 }\n\t\t\t}\n\t\t},\n\t\troles: [\n\t\t\t{ role: 'when', kind: 'date', minimum: 0.6, take: 'best' },\n\t\t\t{ role: 'money', kind: 'amount', minimum: 0.6, take: 'each' }\n\t\t]\n\t})\n);\n```\n\n```\ntruecopy - statement-2026-05.pdf\npdf, 1 page(s), 6 row(s)\n\npage 1 - cut at 100, 290\n\n3 column(s), 6 row(s)\n\ncol  kind        filled  role\n  0  date           83%  when\n  1  text          100%  -\n  2  amount        100%  money\n\n   1   02/05/2026 | CARTE 28/04 AMAZON EU> | 12,40\n   2   03/05/2026 | VIR SEPA LOYER MAI     | 750,00\n   3   05/05/2026 | CARTE 03/05 SNCF CONN> | 68,00\n   4   09/05/2026 | PRLV EDF               | 91,32\n   5   12/05/2026 | CARTE 11/05 LE BOULAN> | 7,90\n   6 !            | TOTAL DES DEBITS       | 929,62   <- column 0 (date) is empty\n```\n\nText, not an image: it goes into a terminal, a CI log, a bug report, a test's expected value. It needs no canvas and no headless browser.\n\n## No configuration per issuer\n\nThe usual way to read a table is to tune settings until one issuer's layout comes out right. It works, and it stops working at the second issuer: every new bank, every new format, every redesign is another block of settings that only its author understands.\n\ntruecopy learns the table from the table. A column full of dates **is** the date column, whatever its header says; a row that breaks what every other row does is a total, a balance, a footer.\n\n```ts\nimport { findRowAnomalies } from 'truecopy/signature';\n\n// Which rows fall outside the signature the table itself sets.\nconst anomalies = findRowAnomalies(rows, signature);\n```\n\nIt reads no label, so it survives an issuer you have never seen. A list of forbidden words only recognises yesterday's documents.\n\n### Where that stops, measured\n\nWhat reads no label is the **judgement**: which rows belong to the table, which column holds what. The **cut** is a different problem, and it is the one that still needs help.\n\nMeasured on a real bank statement whose header labels were deliberately hidden: the page-wide spread of x proposed **twelve** columns where the table had five, because it counts the letterhead, the address block and the footer as evidence of where a column starts. Cut on the rows that share the table's shape instead (the ones carrying a date and an amount), it proposed five, and three of the five roles were named from content alone.\n\n**`boundariesFromRecurrence` is the general answer**, and `readTable` uses it: keep only the x that come back row after row, because a real column's left edge recurs and a word inside a description does not. On the statement above it took the cut from twelve columns to seven, and named the rest as thin. Where the page gives you something better to trust (a header row, a rule), `boundariesFromAnchors` takes it.\n\nAnd whatever you do, keep the self-check. On that same statement the reading still came back **wrong**, and the only reason that was visible is that the sum of the rows did not match the balances the document itself declares.\n\n**That is the honest shape of this library.** It does not promise to read an unknown layout correctly. It promises to tell you when it did not.\n\n## Every value knows where it came from\n\nA value you cannot point at is a value nobody can check. Handed a list of figures, a person has to hunt through the document again; handed a **place**, they jump to it, and that difference is what makes a correction screen used or abandoned.\n\n```ts\nimport { cellsOf, placesOf } from 'truecopy/layout';\n\nconst cells = cellsOf(page); // cells[3][1] is what the fourth row holds\nconst places = placesOf(page); // places[3][1] is where to find it\n// { page: 1, x: 430, y: 700, width: 30 }\n```\n\nThe two are laid out identically, so they are read together. A cell nothing fell into has **no place**: `null`, not a rectangle of nothing. `ReviewableRow.where` carries the same thing for the rows a person is asked to confirm.\n\nNo height, because none is known: a text item carries no height here, and inventing a line spacing would draw a rectangle the document never had.\n\n## Notation is not domain\n\nThat `1 234,50` and `1,234.50` are the same quantity, that `(123,45)` is negative and so is `123,45-`, that `25/01` is a day before a month here and after it there: none of that says anything about banks or invoices. It says how the page was typeset, and it is the part everybody rewrites and everybody gets wrong once.\n\n```ts\nimport { readNumber, findNumbers, readLeadingDate } from 'truecopy/notation';\n\nreadNumber('27800.50'); // 27800.5   - not 2 780 050\nreadNumber('(123,45)'); // -123.45   - the accounting negative\nreadNumber(\"1'234.56\"); // 1234.56\n\n// Never starts a match inside another number: a date glued to a figure\n// reads as one figure, not as \"026 300,00\".\nfindNumbers('30/05/2026 300,00', 2); // [{ value: 300, ... }]\n\nreadLeadingDate('25 janv. 2026 GROCERIES', { dateOrder: 'DMY', months });\n// { date, length: 13 }  - so the caller strips it and keeps the wording\n```\n\nIt says `null` rather than guess. On figures somebody will act upon, a refusal costs a correction and a wrong reading costs a decision.\n\n**None of this needs a PDF.** `truecopy/notation` takes strings, so an API field, an HTML scrape or a pasted email gets the same reading as a page, and `pdfjs-dist` is never loaded. It is the layer worth reaching for before writing a pattern of your own - because the pattern everybody writes instead has a defect nobody sees:\n\n```ts\nimport { accentFree } from 'truecopy/notation';\n\n// `\\w` is [A-Za-z0-9_] in JavaScript, whatever the document is written in.\n/d[ée]tach\\w+/.test('détaché'); // false - the suffix is an accented letter\n/d[ée]tach\\p{L}*/u.test('détaché'); // true\naccentFree('Détaché'); // 'detache' - or fold first and compare plainly\n```\n\nNothing fails there: the pattern compiles, runs, and returns a plausible fraction of the matches, which then reads as a fact about the documents rather than a defect in the rule.\n\n## A refusal you can say in your own language\n\n```ts\ntry {\n\tawait openDocument(file);\n} catch (error) {\n\tif (error instanceof UnreadableDocument) {\n\t\t// 'empty' | 'too-big' | 'no-text' | 'too-slow' | 'no-engine' | 'not-opened'\n\t\tshowInYourOwnWords(error.reason);\n\t}\n}\n```\n\nThe reason is named so the sentence is not. A library that ships only English prose forces an application that speaks anything else to keep its own copy of the door.\n\n`no-engine` and `not-opened` are kept apart on purpose, and the difference is not cosmetic: one says _install `pdfjs-dist`_, the other says _this file will not open, look for its password_. Told the wrong one, a person hunts for a lock that does not exist and an agent writes that the document is protected. `pdfjs-dist` is a peer dependency so that a project reading only pastes and CSV does not download a PDF engine it will never call.\n\n## One declaration, two outputs\n\nWrite the schema once and get both the check and the record type. A shape declared twice drifts, and the half that drifts silently is always the check.\n\n```ts\nimport { schemaOf, validate, type RecordOf } from 'truecopy/schema';\n\nexport const CAREER = schemaOf({\n\tname: 'career-record',\n\tfields: {\n\t\tyear: { format: 'year', minimum: 1930, maximum: 2030, required: true },\n\t\tquarters: { format: 'integer', minimum: 0, maximum: 4, required: false },\n\t\tpay: { format: 'number', minimum: 0, required: false }\n\t},\n\tminimumRecords: 5,\n\tkey: 'year'\n});\n\nexport type CareerRow = RecordOf<typeof CAREER>;\n//   { year: number; quarters: number | null; pay: number | null }\n\nconst violation = validate(CAREER, rows);\n// null, or { cause: 'too-few-records', conforming: 1, expected: 5 }\n```\n\nThe schema is **pure data**: no accessor, no closure, nothing that does not survive JSON. It can be served, versioned, refined by whoever reads the documents, and swapped for another market without a deploy. What is missing is named; your application writes the sentence in its own voice.\n\n**Already declared that row type in Zod, Valibot or ArkType?** Do not declare it twice. Any [Standard Schema](https://standardschema.dev) works, and truecopy adds the part a per-record validator cannot know: how many well-formed records make a document.\n\n```ts\nimport { validateWith } from 'truecopy/schema';\n\nvalidateWith(myZodSchema, rows, { minimumRecords: 5, key: 'year' });\n```\n\n## Why refusing matters\n\nThe research world arrived at the same place from the other side, and gave it a name: **calibrated abstention**. [Zero Hallucination, by Construction](https://arxiv.org/abs/2607.17883) (Raduta et al., 2026) makes it one of six layers of an architecture for enterprise document AI (_\"the system declines rather than guesses when grounding is insufficient\"_), paired with an evidence-based confidence that checks what was produced against the source document. Those are `refuse` and `selfCheck`, layer for layer.\n\nIt stays rare for a reason that is not technical: a benchmark rewards a confident guess and scores an abstention as a miss, so the whole machine is tuned to guess. A deterministic parser has no excuse to inherit that.\n\nThe five laws a reader is written to:\n\n1. **The document checks itself.** A bank statement carries `opening + Σ = closing`; a career record announces its own total of quarters. Setting your reading against what the document declares is the only check that depends on no layout.\n2. **Refusing beats returning a plausible table.** The worst defect is not missing an anomaly; it is inventing twenty-two of them out of a document you misread.\n3. **Counting is not measuring.** Running two readings and keeping \"the one that finds more rows\" always picks the worse: a reader that cuts badly turns footnotes into data.\n4. **The reader proposes, the person confirms.** The correction is part of the product, not the recovery path.\n5. **Every quantifier is bounded.** These patterns run over a whole document, line by line.\n\n## When a model does the reading\n\nA model that turns cells into records fails one visible way - it misses a record - and one invisible way: it returns a **plausible value the document never printed**. A town deduced from a postcode, a rounded figure, a recomposed date, each reading exactly like a successful extraction. That failure has a deterministic answer, and it does not need a better model:\n\n**The model never sees the PDF.** It receives the rows this library cut, numbered. It returns records that **cite the row numbers** they came from. And every value is then looked up in those rows and nowhere else - so the model cannot produce a fact, only point at one the document already carries.\n\n```ts\nimport { numberedRows, citedText, carriesText, carriesNumber } from 'truecopy/cite';\n\nconst prompt = rules + '\\n' + numberedRows(page); // what the model sees\nconst source = citedText(page, record.rows); // what it claims to have read\n\ncarriesText(source, record.town); // all its words, in order - never a substring\ncarriesNumber(source, record.surface, mark); // the page's numbers - never a digit soup\n```\n\nBoth lookups were measured against their naive forms on a real corpus before they were written this way. A contiguous substring refused 104 of one document's 111 records, because layouts throw the tail of a name past the figure columns - the words are all there, in order, never in one piece. And flattening the source into one run of digits found a surface **three times** in a row that carries no such figure: a guard that looked strong exactly where it protected nothing.\n\nWhat stays yours is policy, not mechanics: which fields are figures, which single field anchors a record, and the rule that a failed side field is dropped and counted rather than fatal. `checkExtraction` (`truecopy/contract`) is the arithmetic half - the sum of what came back, against the totals the document declares about itself.\n\n## When the value outlives its reading\n\nA document read once, offline, into values a site then serves for months cannot\nre-run its extraction per reader. What proves such a value is not the\nextraction: it is the SENTENCE, stored nowhere, found again in the document at\ndisplay time from a short **anchor** kept beside the value. Nothing recopies the\ntext, so a value cannot drift from it; and the day the document is revised, the\nanchor stops falling and the absence is the alarm.\n\n```ts\nimport { anchoredPassage, missingFigures, proofSpan } from 'truecopy/anchor';\n\n// stored once: { value: '9 m', anchor: 'hauteur maximale de 9' }\nconst passage = anchoredPassage(article, rule.anchor, { units: 'lines', depth: 'outline' });\n// A null passage is the alarm: the document was revised since it was read.\nif (passage === null) return null; // never a value without its sentence\n\nconst quoted = [...passage.heading, passage.line, ...passage.opened].join(' ');\nmissingFigures(quoted, rule.value, { decimal: mark }); // [] or the figures it does not carry\nproofSpan(quoted, rule.value, { decimal: mark }); // how far a reader travels to the proof\n```\n\n**A paragraph quoted alone is exact and says nothing.** `- under two years of\nservice: one month` has lost `- for technicians`, which is half the rule, and\nthe sentence above it, which is the other half: quoted alone it reads as\neveryone's notice period. So a passage is the paragraph, its ancestors, AND the\nlist it opens, and the three arrive apart because which of them a narrow screen\nsheds is a display decision.\n\nAnd an anchor that still falls proves the paragraph exists, never what it SAYS.\nMeasured on one planning code: a rule displayed as `35 m from the axis` sat\nbeside a sentence about the same road reading `a minimum setback of 10 metres`.\n`missingFigures` is what sees that; `proofSpan` is what says whether the reader\nreaches the figure before the screen cuts the citation off.\n\n## The kit that makes it compulsory\n\nAn interface is dodged with a `return null`; an assertion is not. Drop the kit into your gate with a corpus of your own:\n\n```ts\nimport { checkContract, contractReport, failures, pdfWithText } from 'truecopy/kit';\n\nit('holds the reading contract', async () => {\n\tconst results = await checkContract(\n\t\tmyReader,\n\t\t[\n\t\t\t{ name: 'balances', document: aSoundDocument, expected: 'read' },\n\t\t\t{ name: 'does not balance', document: aWrongDocument, expected: 'needs-review' }\n\t\t],\n\t\t{\n\t\t\treferencePdf: pdfWithText([{ word: '2018', x: 50, y: 700 }]),\n\t\t\t// YOUR door, not the kit's: what is measured is your reader,\n\t\t\t// extraction included.\n\t\t\topen: openLikeTheApp,\n\t\t\tforeign: [{ name: 'a payslip', document: aPayslip }]\n\t\t}\n\t);\n\n\texpect(failures(results)).toEqual([]);\n\twriteFileSync('contract.txt', contractReport(results));\n});\n```\n\nThe six rules, numbered on their own: the laws above are what a reader is written to, these are what a corpus checks it against from the outside.\n\n1. The verdict the corpus announces is the verdict returned.\n2. A reading that contradicts its document **never** comes back as sound.\n3. Everything read is reviewable by the person.\n4. The chain from bytes to records really runs, on a **real** PDF (`pdfWithText` builds one, xref table included).\n5. A document without substance is **refused**, not silently returned empty.\n6. A document of **another kind** is refused: you supply the corpus of what it must be told apart from, because only you know.\n\n`contractReport` turns the run into a file you commit. A reading that quietly falls from twenty-six records to twenty-four passes every rule and no assertion notices; the diff does.\n\nThe fifth law (every quantifier bounded) is not in the kit, because a naive source scan produces false positives. It is held by `eslint-plugin-regexp` and its `no-super-linear-backtracking` and `no-super-linear-move` rules, in your own gate.\n\n## Three methods, not five\n\nA reader implements `read`, `selfCheck` and `rowsToReview`. Those three carry the doctrine: the work, the first law, and the person's place in it.\n\n`repair` and `refuse` are **optional**, and their defaults err the only direction a default may err in: toward refusing. `repair` attempts nothing, because an honest gap beats a patch-up. `refuse` refuses a reading that produced no record.\n\nFive methods before anything runs is a wall, and a wall in front of an interface gets `return null` written five times. That is the dodge [`kit.ts`](src/kit.ts) exists to catch, and the likeliest author of it is now a model writing from the types.\n\n## The mechanisms\n\nEach one is also its own entry point, so a project that wants one pays for one.\n\n| Module                             | `truecopy/…` | What it does                                                                          |\n| ---------------------------------- | ------------ | ------------------------------------------------------------------------------------- |\n| [`open.ts`](src/open.ts)           | `open`       | bytes → pages → rows: size cap, page cap, deadline, engine released, engine swappable |\n| [`layout.ts`](src/layout.ts)       | `layout`     | the pure geometry: rows, columns, cells, places, no engine, no bytes, no clock        |\n| [`table.ts`](src/table.ts)         | `table`      | `readTable(file)`: the two-line path, and what it will not vouch for                  |\n| [`notation.ts`](src/notation.ts)   | `notation`   | how the page writes a number and a date, never what they mean                         |\n| [`classify.ts`](src/classify.ts)   | `classify`   | is this the kind of document expected, precedence included                            |\n| [`columns.ts`](src/columns.ts)     | `columns`    | what each column contains, counted once                                               |\n| [`roles.ts`](src/roles.ts)         | `roles`      | what each column is, deduced from that                                                |\n| [`records.ts`](src/records.ts)     | `records`    | which rows belong to the same record, when a printed row is not one                   |\n| [`labels.ts`](src/labels.ts)       | `labels`     | which cells could be the value a label announces, closest first                       |\n| [`signature.ts`](src/signature.ts) | `signature`  | which rows break the table's own type signature                                       |\n| [`schema.ts`](src/schema.ts)       | `schema`     | the fields, formats and count a reading must satisfy                                  |\n| [`cite.ts`](src/cite.ts)           | `cite`       | the rows a model cited, and whether they really carry each value                      |\n| [`anchor.ts`](src/anchor.ts)       | `anchor`     | the passage a stored value came from, found again in the document                     |\n| [`explain.ts`](src/explain.ts)     | `explain`    | what all of the above decided, in words                                               |\n| [`pattern.ts`](src/pattern.ts)     | `pattern`    | domain knowledge as **data**, compiled behind a ReDoS guard                           |\n| [`contract.ts`](src/contract.ts)   | `contract`   | what an honest reading looks like                                                     |\n| [`kit.ts`](src/kit.ts)             | `kit`        | what makes it compulsory                                                              |\n\n## Precedence, and why it is stated rather than ordered\n\nA bank statement quotes the word _invoice_ in a transaction label. Read in the wrong order it is filed as an invoice, and every operation it carries leaves the budget with it. An IBAN, or the debit/credit/balance vocabulary, settles the question before the word invoice is even looked at.\n\nThree notions and no more: a **pattern set** (all of its patterns), a **requirement** (any one of its sets), a **kind** (all of its requirements, first match wins). `absent` inverts a requirement, so _an invoice only when there is no IBAN_ is stated rather than smuggled into an ordering that means something else.\n\n## It knows nothing about your documents\n\nIt has never heard of a date, an amount, a debit or a quarter. You name the **kind** of a cell and the **role** you want back; this library counts, divides, compares, and says which rule broke.\n\nThat is deliberate. A library that shipped the meaning would force the next project to describe its document in a vocabulary designed for someone else's.\n\nEverything that varies by market, by issuer or by document family is a **value**, not a branch; see `pattern.ts`. A value can be served by a backend, refined by whoever reads the documents, versioned, and swapped for another market without a deploy. A branch can only be changed by whoever can change the code. Profiles carry regular expressions and JSON does not, so they travel as `{ source, flags }` and are rebuilt here, which is exactly where the danger is, and where the guard goes. A rejected pattern compiles to one that never matches, so the feature degrades and the page stays alive.\n\n## One reader, or two\n\nA project plugs in one reader, or two. A statement reader may run a positional one when there are coordinates and a line grammar when there are not, and an OCR page is exactly where both apply and the richer read wins. That competition is your business; everything around it is not.\n\n`readTable` is a reader, the default one, so that the first minute costs nothing. It is the on-ramp, not the product. The product is the pipeline and the guarantees around whichever reader ends up doing the work, and every mechanism is exposed on its own precisely so that yours can replace the default one piece at a time.\n\n## What it will never do\n\nA library with no stated limit grows one every release. These are refusals, not a roadmap.\n\n- **It will never ship the meaning of your documents.** No date, no amount, no debit, no quarter, no issuer. Domain knowledge travels as **data** (`pattern.ts`, `schemaOf`), because a value can be versioned and swapped for another market, and a branch can only be changed by whoever can change the code.\n- **It will never grow per-issuer configuration.** Tuning settings until one bank comes out right is the approach this library exists to replace. A layout it reads badly is a defect or a documented limit, never a preset.\n- **It will never become a CSV parser.** It splits on four delimiters, and only where the count recurs line after line. A quoted file is handed back whole with a warning, because half-parsing a quoted CSV is exactly the plausible-but-wrong reading argued against everywhere else here. Reach for a real CSV library; this door exists for a paste, an export, an OCR line.\n- **It will never become a validation library.** `schemaOf` bounds a reading: formats, and how many records make a document. Anything richer belongs to Zod or Valibot, and `validateWith` takes theirs rather than competing with it.\n- **It will never carry an engine of its own.** PDFs go through `pdfjs-dist`, which stays an **optional** peer dependency; a `.docx` and a `.odt` are ZIPs of XML, so they are read with what the platform already has and cost no dependency at all. No OCR engine, no spreadsheet reader, no legacy `.doc`. Anything else, you hand over as bytes or text - and bytes it cannot read are refused by name rather than decoded into mojibake.\n- **It will never touch the filesystem, the network or a clock you did not pass in.** It runs in a browser. `bin/truecopy.mjs` is the single exception, and it is a command, not the library.\n- **It will never grow a second cut.** One vote on which left edges recur, one set of thresholds, three rulers. A format that needs its own algorithm needs its own library.\n\n## Requirements\n\nNode 20+, ESM. `pdfjs-dist` is an **optional** peer dependency, loaded on demand and only for PDFs: reading text, a paste or a CSV needs nothing.\n\npdf.js is used through its **legacy** build, deliberately: the modern one refuses to run outside a browser, which would make the whole chain untestable. **In Node, pass no engine at all** and that build is imported for you. Nine ingestion scripts across two consumers import it by hand and pass it as `pdfjs`, which works and is redundant; the option is there for a browser reader under a byte budget, which is the one case where the modern build is worth its own import.\n\nIf you want the worker, resolve its URL yourself and pass it in, because every bundler spells that differently and picking one here would lock you into it:\n\n```ts\nimport workerSrc from 'pdfjs-dist/legacy/build/pdf.worker.mjs?url'; // Vite\nawait openDocument(file, { workerSrc, maximumPages: 200 });\n```\n\nA batch script raises the limits, and is meant to: `DEFAULT_LIMITS` (20 MB, 40 pages, 30 s) protects a browser tab, not an ingestion that runs once a year. Two consumers reading annual reports settled on 80 to 200 MB and 600 to 2000 pages. Reach for `keepPage` before `maximumPages`: it cuts at the right end of a long document.\n\n## Use it from an assistant, with nothing installed\n\nAn agent holding a terminal already has the command above, and one that can import a module has the library. Neither is what most assistants are: a host that speaks MCP reaches a tool call and nothing else. So the same pipeline is an MCP server, over stdio, on the machine the document is already on.\n\n```json\n{\n\t\"mcpServers\": {\n\t\t\"truecopy\": {\n\t\t\t\"command\": \"npx\",\n\t\t\t\"args\": [\"-y\", \"-p\", \"truecopy\", \"-p\", \"pdfjs-dist\", \"truecopy-mcp\"]\n\t\t}\n\t}\n}\n```\n\nTwo tools, and the second is the one that is hard to get anywhere else:\n\n- **`read_table`** turns a PDF, a CSV, a TSV or a saved paste into rows: the cut, how often each column is filled, the rows numbered, and what the reading **could not vouch for**. Bounded at 200 rows a call, and what it left is counted rather than dropped.\n- **`check_citations`** takes the records a model claims to have read, each citing the rows it came from, and says which values the cited rows do not print. A JSON number is checked as a figure with the document's own decimal mark, a JSON string as its words in order. It answers \"was this read or invented\", never \"is this complete\", and it says so.\n\n**Nothing is uploaded, because there is nowhere to upload it to.** The server runs where the file already is, makes no network call, and opens no file it was not handed. A statement, a payslip and a career record are the worst documents there are to send anywhere, and a server has nothing to compute on them that this does not compute in place. Set `TRUECOPY_MCP_ROOT` and it opens nothing outside that directory, symbolic links resolved before the check.\n\nIt speaks the 2026-07-28 revision and the ones before it, so a host that opens with `initialize` and a host that goes straight to `server/discover` both work.\n\nServing these tools from something larger - a server of your own, another transport - is [`truecopy/mcp`](src/mcp.ts): `TOOLS` are the descriptors, and `respond` answers one JSON-RPC message given a way to turn a path into a `File`.\n\n## For a coding agent\n\nThis library was published after every model in service was trained, so a model\nwriting against it invents the API unless it is handed one. Two ways to hand it\nover, both version-matched to what you installed:\n\n```sh\n# already on disk once you install the package\ncp -r node_modules/truecopy/skills/truecopy ~/.claude/skills/\n\n# or, to follow the repository\nclaude plugin marketplace add truecopydev/truecopy\nclaude plugin install truecopy@truecopy\n```\n\n[`skills/truecopy/SKILL.md`](skills/truecopy/SKILL.md) is plain markdown and\ncarries no Claude-specific instruction beyond its frontmatter, so it works as an\n`AGENTS.md` for any other agent that reads one. `npm run skill` fails when it\nnames an export this package no longer has.\n\nThe documentation site serves every page as markdown at the same path with\n`.md`, which is what [`llms.txt`](https://truecopy.dev/llms.txt) links to.\n\n## Gate\n\n```sh\nnpm run gate\n```\n\nFormat, no typographic dash, lint (zero warnings, sonarjs + regexp), typecheck, build, knip, jscpd, tests, coverage **100 %**, ratchets that only ever go up. A kit that measures others measures itself first.\n\nThe same command runs in CI, on every push and every pull request. If it is green on your machine it is green here.\n\n## Contributing\n\n[`CONTRIBUTING.md`](CONTRIBUTING.md): what a change needs, and how it lands. Found a document that reads wrong? Open an issue with what `npx truecopy` printed, never the document itself.\n\n[`RELEASING.md`](RELEASING.md): what a version number here will and will not do to you. The short version: releases are patches, the second digit stays put, and nothing is ever unpublished.\n\nSecurity: [`SECURITY.md`](SECURITY.md). The library makes no network call, touches no filesystem and ships no runtime dependency, which leaves a small and specific surface: it is described there.\n\n## Licence\n\nMIT © Florian Mousseau\n","readmeFilename":"README.md"}