{"_id":"@capseal/provenance","name":"@capseal/provenance","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@capseal/provenance","version":"0.1.0","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run"},"devDependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"description":"Read what a file says about its own origin: C2PA manifests, EXIF, XMP and container structure, with verdicts graded by how they were reached.","keywords":["c2pa","provenance","content-credentials","exif","xmp","jumbf","ai-detection","image-forensics","deepfake","metadata"],"license":"SEE LICENSE IN LICENSE","author":{"name":"SYPTime Pty Ltd"},"homepage":"https://capseal.ai/developers","repository":{"type":"git","url":"git+https://github.com/uozef/capseal.ai.git","directory":"packages/provenance"},"bugs":{"url":"https://github.com/uozef/capseal.ai/issues"},"publishConfig":{"access":"public"},"_id":"@capseal/provenance@0.1.0","gitHead":"27a76fc504de60e45017691cf78e299bce424a42","_nodeVersion":"23.8.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-dV91C+nxzIVt42hhpcqPHHEEli3AEZNWZCq146O6vFTmghS9a71YxNw9RoBj5Zp27KVhcG4qkmM0vjIaofC1tg==","shasum":"97fed7daf85bed8ef1834e94bef01446e3227e50","tarball":"https://registry.npmjs.org/@capseal/provenance/-/provenance-0.1.0.tgz","fileCount":46,"unpackedSize":172420,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIH4AZ9EQ4U0/6pxjRrYIKfTJ0oSj+sj84RWWt2jTO0UbAiBBQU7wMgeUa7CAfehEahJE38kyGcw8OOzsY2zVrF3Jdw=="}]},"_npmUser":{"name":"uozef","email":"yousef.hosseini@gmail.com"},"directories":{},"maintainers":[{"name":"uozef","email":"yousef.hosseini@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/provenance_0.1.0_1786358042482_0.42099056756940856"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-10T10:34:02.344Z","0.1.0":"2026-08-10T10:34:02.641Z","modified":"2026-08-10T10:34:02.901Z"},"maintainers":[{"name":"uozef","email":"yousef.hosseini@gmail.com"}],"description":"Read what a file says about its own origin: C2PA manifests, EXIF, XMP and container structure, with verdicts graded by how they were reached.","homepage":"https://capseal.ai/developers","keywords":["c2pa","provenance","content-credentials","exif","xmp","jumbf","ai-detection","image-forensics","deepfake","metadata"],"repository":{"type":"git","url":"git+https://github.com/uozef/capseal.ai.git","directory":"packages/provenance"},"author":{"name":"SYPTime Pty Ltd"},"bugs":{"url":"https://github.com/uozef/capseal.ai/issues"},"license":"SEE LICENSE IN LICENSE","readme":"# @capseal/provenance\n\nRead what a file says about its own origin. C2PA manifests, EXIF, XMP, container\nstructure - and a verdict that tells you **how** it was reached rather than a\nconfidence score pulled from nowhere.\n\nZero dependencies. Runs in Node, the browser, Cloudflare Workers, Deno and Bun.\n\n```bash\nnpm install @capseal/provenance\n```\n\n```ts\nimport { inspect, classify } from \"@capseal/provenance\";\n\nconst report = await inspect(new Uint8Array(await file.arrayBuffer()));\nconst verdict = classify(report);\n\nconsole.log(verdict.verdict);   // \"AI_GENERATED\"\nconsole.log(verdict.basis);     // \"declared\"\nconsole.log(verdict.headline);  // \"This file says it was generated by Adobe Firefly.\"\n```\n\n## The thing that makes it different\n\nMost tools answer \"is this real?\" with a percentage. This one answers with a\n**basis** - how the answer was arrived at - because for a large share of real\nfiles the honest answer is that nothing can be established.\n\n| `basis` | meaning |\n| --- | --- |\n| `proven` | cryptography settles it |\n| `declared` | the file says so, and a signature backs the file |\n| `claimed` | the file says so, and nothing backs the claim |\n| `indicative` | metadata leans one way and could be wrong |\n| `unknown` | the file does not say, and neither will we |\n\nAn unsigned JPEG is a grid of pixels. If it carries no manifest and no metadata,\nnothing in the bytes distinguishes a genuine photograph that a messaging app\nstripped from an edit or from generated content. Anything that returns a\nconfidence score for that case is guessing, and a screenshot plus a re-encode\ndefeats it. This returns `NO_PROVENANCE` / `unknown` and explains why.\n\nBuild your routing on `basis`, not on a number:\n\n```ts\nimport { toDecision } from \"@capseal/provenance\";\n\nconst { actionable } = toDecision(verdict);\nif (!actionable) sendToHuman();   // \"claimed\", \"indicative\" and \"unknown\"\n```\n\n## What it reads\n\n**Containers** JPEG, PNG, WebP, GIF, TIFF, HEIC, AVIF, MP4, QuickTime, WebM,\nPDF, SVG - detected by magic bytes, never by filename.\n\n**C2PA** The full JUMBF box tree, CBOR claims, every assertion, actions,\ningredients, and the COSE signature algorithm. Multi-segment APP11 manifests are\nreassembled - a manifest routinely exceeds JPEG's 64KB segment limit, and a\nparser that reads only the first segment reports a valid file as corrupt.\n\n**EXIF** Every IFD0, ExifIFD and GPS tag, with the ones that matter for\nprovenance surfaced: camera make and model, MakerNote presence, Software,\ncapture and modify times, coordinates.\n\n**XMP** CreatorTool, edit history, and the IPTC `digitalSourceType` vocabulary -\nthe standard way a generative model declares itself.\n\n**PDF** Producer and Creator strings, and the count of appended revisions, which\nis direct evidence of modification after writing.\n\n## It expects hostile input\n\nEvery parser here reads files chosen by whoever uploaded them. Bounds-checked\ncursors, depth and item limits on CBOR and JUMBF, cycle detection on EXIF IFD\npointers, and a fuzz test that truncates a file at every length and requires it\nnot to throw. A malformed length field is the expected input, not an edge case.\n\n## Reading is not verifying\n\nThis package reads manifests. It does **not** validate signatures or certificate\nchains - that needs a trust list and hard-binding recomputation, which is what\n[`c2pa-rs`](https://github.com/contentauth/c2pa-rs) does and what CapSeal depends\non for it. \"This file carries a manifest saying X\" and \"this manifest is\ncryptographically valid\" are different claims, and the report never conflates\nthem.\n\nFor the cryptographic answer, see [`@capseal/wasm`](https://capseal.ai/developers)\nor `POST https://capseal.ai/api/inspect`.\n\n## Try it without installing anything\n\n```bash\ncurl -X POST --data-binary @photo.jpg https://capseal.ai/api/inspect\n```\n\nOr drop a file into [capseal.ai/check](https://capseal.ai/check).\n\n---\n\nBy [SYPTime Pty Ltd](https://capseal.ai). See LICENSE.\n","readmeFilename":"README.md","_rev":"1-81c9e60ad3c9301c8ed3fbdaa68ed7cf"}