@sweberdev/witness 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/ai-sdk.cjs.map +1 -1
- package/dist/ai-sdk.js +1 -1
- package/dist/bin.cjs +294 -6
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +3 -2
- package/dist/bin.js.map +1 -1
- package/dist/chunk-F7OWVTCS.js +307 -0
- package/dist/chunk-F7OWVTCS.js.map +1 -0
- package/dist/{chunk-APXU3MTX.js → chunk-GXMGYIOK.js} +3 -1
- package/dist/chunk-GXMGYIOK.js.map +1 -0
- package/dist/{chunk-UBRK4CTM.js → chunk-PT57EYD7.js} +14 -10
- package/dist/chunk-PT57EYD7.js.map +1 -0
- package/dist/cli.cjs +294 -6
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/index.cjs +297 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -2
- package/dist/index.d.ts +45 -2
- package/dist/index.js +13 -1
- package/package.json +2 -2
- package/src/cli.ts +9 -7
- package/src/image.ts +4 -3
- package/src/index.ts +13 -0
- package/src/media.ts +460 -0
- package/dist/chunk-APXU3MTX.js.map +0 -1
- package/dist/chunk-UBRK4CTM.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @sweberdev/witness
|
|
2
2
|
|
|
3
|
-
AI transparency toolkit for Article 50 of the EU AI Act: chatbot notice and AI label custom elements, IPTC/XMP marking for PNG, JPEG and
|
|
3
|
+
AI transparency toolkit for Article 50 of the EU AI Act: chatbot notice and AI label custom elements, IPTC/XMP marking for PNG, JPEG, WebP, MP3, WAV and MP4, an invisible text watermark, schema.org metadata, Vercel AI SDK middleware and a CLI. Wording in English, German, French and Italian. No runtime dependencies.
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
pnpm add @sweberdev/witness
|
package/dist/ai-sdk.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ai-sdk.ts","../src/inflate.ts","../src/marking.ts","../src/image.ts","../src/watermark.ts"],"sourcesContent":["/**\n * Middleware for the Vercel AI SDK (`ai` 5, 6 and 7). It marks what a model produces:\n *\n * - `witnessMiddleware` appends the invisible text watermark to every text part, for\n * `generateText` and `streamText`, and adds `providerMetadata.witness`.\n * - `witnessImageMiddleware` writes XMP with the IPTC Digital Source Type into every image\n * from `generateImage`.\n *\n * The types are structural, so this module has no dependency on `ai`.\n */\n\nimport { type MarkImageOptions, markImage } from \"./image.js\";\nimport { createMarking, iptcSourceType } from \"./marking.js\";\nimport type { ContentKind, Marking } from \"./types.js\";\nimport { watermarkSuffix, watermarkText } from \"./watermark.js\";\n\ntype SpecVersion = \"v2\" | \"v3\" | \"v4\";\n\ninterface ModelInfo {\n provider: string;\n modelId: string;\n}\n\nexport interface WitnessMarkedEvent {\n type: \"text\" | \"image\";\n marking: Marking;\n /** For text: the id of the text part in a stream, if any. */\n partId?: string;\n /** For images: what happened to each image. */\n status?: string;\n}\n\nexport interface WitnessMiddlewareOptions {\n /**\n * The AI SDK middleware specification. `v4` for `ai` 7 (default), `v3` for `ai` 6, `v2`\n * for `ai` 5.\n */\n specificationVersion?: SpecVersion;\n /** Name written into the marking. Default: `provider/modelId` of the wrapped model. */\n generator?: string | ((model: ModelInfo) => string);\n /** Default `generated`. */\n kind?: ContentKind;\n /** Your company or product, written into the marking. */\n provider?: string;\n /** Append the invisible text watermark. Default `true`. */\n watermark?: boolean;\n /** A reference written into the watermark, e.g. a log id. */\n id?: () => string;\n /** Called once per marked text part or image, e.g. to write an audit log entry. */\n onMarked?: (event: WitnessMarkedEvent) => void;\n}\n\ninterface TextPart {\n type: string;\n text?: string;\n}\n\ninterface GenerateResult {\n content: TextPart[];\n providerMetadata?: Record<string, unknown>;\n}\n\ninterface StreamPart {\n type: string;\n id?: string;\n delta?: string;\n providerMetadata?: Record<string, unknown>;\n}\n\ninterface StreamResult {\n stream: ReadableStream<StreamPart>;\n}\n\n/** The `witness` entry added to `providerMetadata`. */\nexport function witnessProviderMetadata(marking: Marking): Record<string, string | boolean> {\n return {\n aiGenerated: true,\n kind: marking.kind,\n sourceType: iptcSourceType(marking.sourceType),\n createdAt: marking.createdAt,\n ...(marking.generator ? { generator: marking.generator } : {}),\n ...(marking.provider ? { provider: marking.provider } : {}),\n };\n}\n\n/** Language model middleware. Pass it to `wrapLanguageModel`. */\nexport function witnessMiddleware(options: WitnessMiddlewareOptions = {}) {\n const watermark = options.watermark ?? true;\n\n const markingFor = (model: ModelInfo): Marking =>\n createMarking({\n kind: options.kind ?? \"generated\",\n generator: generatorFor(options.generator, model),\n ...(options.provider ? { provider: options.provider } : {}),\n });\n\n const watermarkFor = (marking: Marking) => ({\n ...(marking.generator ? { generator: marking.generator } : {}),\n createdAt: marking.createdAt,\n ...(options.id ? { id: options.id() } : {}),\n });\n\n return {\n specificationVersion: options.specificationVersion ?? \"v4\",\n\n async wrapGenerate<R extends GenerateResult>({\n doGenerate,\n model,\n }: {\n doGenerate: () => PromiseLike<R>;\n model: ModelInfo;\n }): Promise<R> {\n const result = await doGenerate();\n const marking = markingFor(model);\n const content = result.content.map((part) => {\n if (part.type !== \"text\" || typeof part.text !== \"string\" || part.text.length === 0) {\n return part;\n }\n options.onMarked?.({ type: \"text\", marking });\n return watermark\n ? { ...part, text: watermarkText(part.text, watermarkFor(marking)) }\n : part;\n });\n return {\n ...result,\n content,\n providerMetadata: { ...result.providerMetadata, witness: witnessProviderMetadata(marking) },\n };\n },\n\n async wrapStream<R extends StreamResult>({\n doStream,\n model,\n }: {\n doStream: () => PromiseLike<R>;\n model: ModelInfo;\n }): Promise<R> {\n const result = await doStream();\n const marking = markingFor(model);\n const withText = new Set<string>();\n const transform = new TransformStream<StreamPart, StreamPart>({\n transform(part, controller) {\n const id = part.id ?? \"\";\n if (\n part.type === \"text-delta\" &&\n typeof part.delta === \"string\" &&\n part.delta.length > 0\n ) {\n withText.add(id);\n }\n if (part.type === \"text-end\" && withText.has(id)) {\n withText.delete(id);\n options.onMarked?.({ type: \"text\", marking, partId: id });\n if (watermark) {\n controller.enqueue({\n type: \"text-delta\",\n id,\n delta: watermarkSuffix(watermarkFor(marking)),\n });\n }\n }\n if (part.type === \"finish\") {\n controller.enqueue({\n ...part,\n providerMetadata: {\n ...part.providerMetadata,\n witness: witnessProviderMetadata(marking),\n },\n });\n return;\n }\n controller.enqueue(part);\n },\n });\n return { ...result, stream: result.stream.pipeThrough(transform) };\n },\n };\n}\n\nexport interface WitnessImageMiddlewareOptions\n extends Pick<WitnessMiddlewareOptions, \"generator\" | \"kind\" | \"provider\" | \"onMarked\">,\n MarkImageOptions {\n /** `v4` for `ai` 7 (default), `v3` for `ai` 6. */\n specificationVersion?: \"v3\" | \"v4\";\n}\n\ninterface ImageResult {\n images: string[] | Uint8Array[];\n warnings: unknown[];\n}\n\n/** Image model middleware. Pass it to `wrapImageModel`. */\nexport function witnessImageMiddleware(options: WitnessImageMiddlewareOptions = {}) {\n return {\n specificationVersion: options.specificationVersion ?? \"v4\",\n\n async wrapGenerate<R extends ImageResult>({\n doGenerate,\n model,\n }: {\n doGenerate: () => PromiseLike<R>;\n model: ModelInfo;\n }): Promise<R> {\n const result = await doGenerate();\n const marking = createMarking({\n kind: options.kind ?? \"generated\",\n generator: generatorFor(options.generator, model),\n ...(options.provider ? { provider: options.provider } : {}),\n });\n const warnings = [...result.warnings];\n const markOne = (bytes: Uint8Array): Uint8Array => {\n const marked = markImage(bytes, marking, options.c2pa ? { c2pa: options.c2pa } : {});\n options.onMarked?.({ type: \"image\", marking, status: marked.status });\n if (marked.status !== \"marked\") {\n warnings.push({\n type: \"other\",\n message:\n marked.status === \"skipped-c2pa\"\n ? \"Witness: image already carries a C2PA manifest and was left unchanged.\"\n : \"Witness: image format not supported (PNG, JPEG, WebP); image is not marked.\",\n });\n }\n return marked.bytes;\n };\n const images = result.images.map((image: string | Uint8Array) =>\n typeof image === \"string\" ? toBase64(markOne(fromBase64(image))) : markOne(image),\n ) as R[\"images\"];\n return { ...result, images, warnings };\n },\n };\n}\n\nfunction generatorFor(option: WitnessMiddlewareOptions[\"generator\"], model: ModelInfo): string {\n if (typeof option === \"function\") return option(model);\n return option ?? `${model.provider}/${model.modelId}`;\n}\n\nfunction fromBase64(value: string): Uint8Array {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = \"\";\n const step = 0x8000;\n for (let i = 0; i < bytes.length; i += step) {\n binary += String.fromCharCode(...bytes.subarray(i, i + step));\n }\n return btoa(binary);\n}\n","/**\n * A small synchronous zlib inflater (RFC 1950/1951), enough to read compressed XMP from PNG\n * zTXt and iTXt chunks in any JavaScript runtime. Based on the structure of tinf by\n * Jørgen Ibsen (zlib licence).\n */\n\ninterface Tree {\n counts: Uint16Array;\n symbols: Uint16Array;\n}\n\nconst LENGTH_BASE = [\n 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,\n 163, 195, 227, 258,\n];\nconst LENGTH_EXTRA = [\n 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,\n];\nconst DIST_BASE = [\n 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049,\n 3073, 4097, 6145, 8193, 12289, 16385, 24577,\n];\nconst DIST_EXTRA = [\n 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,\n];\nconst CODE_LENGTH_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];\n\nfunction buildTree(lengths: ArrayLike<number>, offset: number, count: number): Tree {\n const tree: Tree = { counts: new Uint16Array(16), symbols: new Uint16Array(count) };\n for (let i = 0; i < count; i++) {\n const length = lengths[offset + i] ?? 0;\n tree.counts[length] = (tree.counts[length] ?? 0) + 1;\n }\n tree.counts[0] = 0;\n const offsets = new Uint16Array(16);\n let sum = 0;\n for (let i = 0; i < 16; i++) {\n offsets[i] = sum;\n sum += tree.counts[i] ?? 0;\n }\n for (let i = 0; i < count; i++) {\n const length = lengths[offset + i] ?? 0;\n if (length) {\n const at = offsets[length] ?? 0;\n tree.symbols[at] = i;\n offsets[length] = at + 1;\n }\n }\n return tree;\n}\n\nlet fixed: { lit: Tree; dist: Tree } | null = null;\nfunction fixedTrees(): { lit: Tree; dist: Tree } {\n if (!fixed) {\n const lengths = new Uint8Array(288);\n lengths.fill(8, 0, 144);\n lengths.fill(9, 144, 256);\n lengths.fill(7, 256, 280);\n lengths.fill(8, 280, 288);\n fixed = { lit: buildTree(lengths, 0, 288), dist: buildTree(new Uint8Array(30).fill(5), 0, 30) };\n }\n return fixed;\n}\n\nclass Reader {\n pos = 0;\n bit = 0;\n bits = 0;\n constructor(readonly data: Uint8Array) {}\n\n getBit(): number {\n if (this.bits === 0) {\n if (this.pos >= this.data.length) throw new Error(\"inflate: unexpected end of data\");\n this.bit = this.data[this.pos++] ?? 0;\n this.bits = 8;\n }\n const value = this.bit & 1;\n this.bit >>>= 1;\n this.bits--;\n return value;\n }\n\n read(count: number, base = 0): number {\n let value = 0;\n for (let i = 0; i < count; i++) value |= this.getBit() << i;\n return value + base;\n }\n\n decode(tree: Tree): number {\n let sum = 0;\n let cur = 0;\n let len = 0;\n do {\n cur = 2 * cur + this.getBit();\n len++;\n if (len > 15) throw new Error(\"inflate: invalid code\");\n sum += tree.counts[len] ?? 0;\n cur -= tree.counts[len] ?? 0;\n } while (cur >= 0);\n return tree.symbols[sum + cur] ?? 0;\n }\n}\n\nfunction dynamicTrees(r: Reader): { lit: Tree; dist: Tree } {\n const hlit = r.read(5, 257);\n const hdist = r.read(5, 1);\n const hclen = r.read(4, 4);\n const codeLengths = new Uint8Array(19);\n for (let i = 0; i < hclen; i++) codeLengths[CODE_LENGTH_ORDER[i] ?? 0] = r.read(3);\n const codeTree = buildTree(codeLengths, 0, 19);\n const lengths = new Uint8Array(hlit + hdist);\n for (let n = 0; n < hlit + hdist; ) {\n const sym = r.decode(codeTree);\n if (sym < 16) {\n lengths[n++] = sym;\n continue;\n }\n let repeat: number;\n let value = 0;\n if (sym === 16) {\n if (n === 0) throw new Error(\"inflate: invalid repeat\");\n value = lengths[n - 1] ?? 0;\n repeat = r.read(2, 3);\n } else if (sym === 17) {\n repeat = r.read(3, 3);\n } else {\n repeat = r.read(7, 11);\n }\n while (repeat-- > 0) lengths[n++] = value;\n }\n return { lit: buildTree(lengths, 0, hlit), dist: buildTree(lengths, hlit, hdist) };\n}\n\n/** Inflates zlib-wrapped data. Throws on corrupt input or when `maxLength` is exceeded. */\nexport function inflateZlib(data: Uint8Array, maxLength = 16 * 1024 * 1024): Uint8Array {\n if (\n data.length < 2 ||\n ((data[0] ?? 0) & 0x0f) !== 8 ||\n (((data[0] ?? 0) << 8) | (data[1] ?? 0)) % 31 !== 0\n ) {\n throw new Error(\"inflate: not a zlib stream\");\n }\n const r = new Reader(data);\n r.pos = 2;\n let out = new Uint8Array(Math.max(1024, data.length * 4));\n let length = 0;\n const push = (byte: number) => {\n if (length >= out.length) {\n if (out.length >= maxLength) throw new Error(\"inflate: output too large\");\n const next = new Uint8Array(Math.min(maxLength, out.length * 2));\n next.set(out);\n out = next;\n }\n out[length++] = byte;\n };\n\n let final = 0;\n do {\n final = r.getBit();\n const type = r.read(2);\n if (type === 0) {\n r.bits = 0;\n if (r.pos + 4 > data.length) throw new Error(\"inflate: unexpected end of data\");\n const len = (data[r.pos] ?? 0) | ((data[r.pos + 1] ?? 0) << 8);\n r.pos += 4;\n if (r.pos + len > data.length) throw new Error(\"inflate: unexpected end of data\");\n for (let i = 0; i < len; i++) push(data[r.pos++] ?? 0);\n } else if (type === 1 || type === 2) {\n const { lit, dist } = type === 1 ? fixedTrees() : dynamicTrees(r);\n for (;;) {\n const sym = r.decode(lit);\n if (sym === 256) break;\n if (sym < 256) {\n push(sym);\n continue;\n }\n const index = sym - 257;\n const len = r.read(LENGTH_EXTRA[index] ?? 0, LENGTH_BASE[index] ?? 0);\n const distSym = r.decode(dist);\n const offset = r.read(DIST_EXTRA[distSym] ?? 0, DIST_BASE[distSym] ?? 0);\n if (offset > length) throw new Error(\"inflate: invalid distance\");\n for (let i = 0; i < len; i++) push(out[length - offset] ?? 0);\n }\n } else {\n throw new Error(\"inflate: invalid block type\");\n }\n } while (!final);\n return out.subarray(0, length);\n}\n","import { format, getMessages } from \"./i18n.js\";\nimport type { ContentKind, LocaleOverride, Marking, MarkingInput, SourceType } from \"./types.js\";\n\nconst IPTC_BASE = \"http://cv.iptc.org/newscodes/digitalsourcetype/\";\n\nconst SCHEMA_ORG: Record<SourceType, string> = {\n trainedAlgorithmicMedia: \"https://schema.org/TrainedAlgorithmicMediaDigitalSource\",\n compositeWithTrainedAlgorithmicMedia:\n \"https://schema.org/CompositeWithTrainedAlgorithmicMediaDigitalSource\",\n algorithmicallyEnhanced: \"https://schema.org/AlgorithmicallyEnhancedDigitalSource\",\n algorithmicMedia: \"https://schema.org/AlgorithmicMediaDigitalSource\",\n compositeSynthetic: \"https://schema.org/CompositeSyntheticDigitalSource\",\n};\n\nconst DEFAULT_SOURCE: Record<ContentKind, SourceType> = {\n generated: \"trainedAlgorithmicMedia\",\n edited: \"compositeWithTrainedAlgorithmicMedia\",\n deepfake: \"trainedAlgorithmicMedia\",\n};\n\n/** The IPTC Digital Source Type URI, e.g. for XMP or `data-ai-source-type`. */\nexport function iptcSourceType(type: SourceType): string {\n return IPTC_BASE + type;\n}\n\n/** The schema.org `IPTCDigitalSourceEnumeration` member for JSON-LD. */\nexport function schemaOrgSourceType(type: SourceType): string {\n return SCHEMA_ORG[type];\n}\n\n/** Reads a source type from an IPTC or schema.org URI, or from the bare name. */\nexport function parseSourceType(value: string | null | undefined): SourceType | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n const name = trimmed.startsWith(IPTC_BASE) ? trimmed.slice(IPTC_BASE.length) : trimmed;\n if (name in SCHEMA_ORG) return name as SourceType;\n for (const [type, uri] of Object.entries(SCHEMA_ORG)) {\n if (uri === trimmed) return type as SourceType;\n }\n return undefined;\n}\n\n/** True for source types that mean \"made or changed by a trained AI model\". */\nexport function isAiSourceType(type: SourceType | undefined): boolean {\n return (\n type === \"trainedAlgorithmicMedia\" ||\n type === \"compositeWithTrainedAlgorithmicMedia\" ||\n type === \"algorithmicallyEnhanced\"\n );\n}\n\n/** Applies defaults to a marking. */\nexport function createMarking(input: MarkingInput = {}): Marking {\n const kind = input.kind ?? \"generated\";\n const createdAt =\n input.createdAt instanceof Date\n ? input.createdAt.toISOString()\n : (input.createdAt ?? new Date().toISOString());\n const marking: Marking = {\n kind,\n sourceType: input.sourceType ?? DEFAULT_SOURCE[kind],\n createdAt,\n humanReviewed: input.humanReviewed ?? false,\n };\n if (input.generator) marking.generator = input.generator;\n if (input.generatorVersion) marking.generatorVersion = input.generatorVersion;\n if (input.provider) marking.provider = input.provider;\n if (input.disclosureUrl) marking.disclosureUrl = input.disclosureUrl;\n if (input.description) marking.description = input.description;\n return marking;\n}\n\n/**\n * `data-*` attributes that mark an element's content as AI-generated. Spread them on the\n * element that wraps the content.\n */\nexport function markingAttributes(input: Marking | MarkingInput): Record<string, string> {\n const m = normalise(input);\n const attributes: Record<string, string> = {\n \"data-ai-generated\": \"true\",\n \"data-ai-kind\": m.kind,\n \"data-ai-source-type\": iptcSourceType(m.sourceType),\n \"data-ai-created\": m.createdAt,\n };\n if (m.generator) attributes[\"data-ai-generator\"] = generatorName(m);\n if (m.provider) attributes[\"data-ai-provider\"] = m.provider;\n if (m.humanReviewed) attributes[\"data-ai-reviewed\"] = \"true\";\n return attributes;\n}\n\n/**\n * Page-level `<meta>` tags for a page whose main content is AI-generated. There is no\n * standardised meta tag yet, so these are a convention; pair them with {@link markingJsonLd}.\n */\nexport function markingMetaTags(\n input: Marking | MarkingInput,\n): Array<{ name: string; content: string }> {\n const m = normalise(input);\n const tags = [\n { name: \"ai-generated\", content: m.kind },\n { name: \"ai-source-type\", content: iptcSourceType(m.sourceType) },\n ];\n if (m.generator) tags.push({ name: \"ai-generator\", content: generatorName(m) });\n if (m.humanReviewed) tags.push({ name: \"ai-reviewed\", content: \"true\" });\n return tags;\n}\n\n/** The meta tags as an HTML string. */\nexport function renderMetaTags(input: Marking | MarkingInput): string {\n return markingMetaTags(input)\n .map((tag) => `<meta name=\"${escapeHtml(tag.name)}\" content=\"${escapeHtml(tag.content)}\">`)\n .join(\"\\n\");\n}\n\n/** The meta tags in the shape of Next.js `metadata.other`. */\nexport function nextMetadata(input: Marking | MarkingInput): { other: Record<string, string> } {\n return {\n other: Object.fromEntries(markingMetaTags(input).map((tag) => [tag.name, tag.content])),\n };\n}\n\n/**\n * schema.org JSON-LD for a creative work, with `digitalSourceType` set. Merge `extra` to add\n * your own properties such as `headline` or `@type: \"NewsArticle\"`.\n */\nexport function markingJsonLd(\n input: Marking | MarkingInput,\n extra: Record<string, unknown> = {},\n): Record<string, unknown> {\n const m = normalise(input);\n const data: Record<string, unknown> = {\n \"@context\": \"https://schema.org\",\n \"@type\": \"CreativeWork\",\n digitalSourceType: schemaOrgSourceType(m.sourceType),\n dateCreated: m.createdAt,\n };\n if (m.generator) {\n data.creator = {\n \"@type\": \"SoftwareApplication\",\n name: m.generator,\n ...(m.generatorVersion ? { softwareVersion: m.generatorVersion } : {}),\n };\n }\n if (m.provider) data.publisher = { \"@type\": \"Organization\", name: m.provider };\n if (m.description) data.description = m.description;\n return { ...data, ...extra };\n}\n\n/** The JSON-LD as a `<script type=\"application/ld+json\">` tag. */\nexport function renderJsonLd(\n input: Marking | MarkingInput,\n extra: Record<string, unknown> = {},\n): string {\n const json = JSON.stringify(markingJsonLd(input, extra)).replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/ld+json\">${json}</script>`;\n}\n\nexport interface LabelHtmlOptions {\n locale?: string | readonly string[];\n messages?: LocaleOverride;\n /** Where the visible label goes. Text should be labelled at the top. Default `top`. */\n position?: \"top\" | \"bottom\";\n /** Element that wraps label and content. Default `div`. */\n tag?: \"div\" | \"section\" | \"article\" | \"figure\" | \"aside\";\n}\n\n/**\n * Wraps server-rendered HTML in an element that carries the marking attributes and a visible\n * label. Works without JavaScript; style it with `@sweberdev/witness/styles.css` or your own\n * CSS for `.witness-label`.\n */\nexport function labelHtml(\n html: string,\n input: Marking | MarkingInput,\n options: LabelHtmlOptions = {},\n): string {\n const m = normalise(input);\n const tag = options.tag ?? \"div\";\n const attributes = Object.entries(markingAttributes(m))\n .map(([name, value]) => ` ${name}=\"${escapeHtml(value)}\"`)\n .join(\"\");\n const label = renderLabelLine(m, options);\n const body = options.position === \"bottom\" ? `${html}${label}` : `${label}${html}`;\n return `<${tag} class=\"witness-content\"${attributes}>${body}</${tag}>`;\n}\n\n/** One line of visible label text, e.g. \"KI-generiert · Erzeugt mit Claude\". */\nexport function labelText(\n input: Marking | MarkingInput,\n options: Pick<LabelHtmlOptions, \"locale\" | \"messages\"> = {},\n): string {\n const m = normalise(input);\n const messages = getMessages(options.locale, options.messages);\n const parts = [messages.kinds[m.kind].label];\n if (m.generator) {\n parts.push(format(messages.ui.generatedWith, { generator: generatorName(m) }));\n }\n if (m.humanReviewed) parts.push(messages.ui.humanReviewed);\n return parts.join(\" · \");\n}\n\nfunction renderLabelLine(m: Marking, options: LabelHtmlOptions): string {\n const messages = getMessages(options.locale, options.messages);\n const text = escapeHtml(labelText(m, options));\n const link = m.disclosureUrl\n ? ` <a class=\"witness-label__link\" href=\"${escapeHtml(m.disclosureUrl)}\">${escapeHtml(messages.ui.moreInfo)}</a>`\n : \"\";\n return `<p class=\"witness-label\" role=\"note\"><span class=\"witness-label__icon\" aria-hidden=\"true\">AI</span> <span class=\"witness-label__text\">${text}</span>${link}</p>`;\n}\n\n/** \"Model 1.2\" when a version is known. */\nexport function generatorName(m: Pick<Marking, \"generator\" | \"generatorVersion\">): string {\n if (!m.generator) return \"\";\n return m.generatorVersion ? `${m.generator} ${m.generatorVersion}` : m.generator;\n}\n\nfunction normalise(input: Marking | MarkingInput): Marking {\n return isMarking(input) ? input : createMarking(input);\n}\n\nfunction isMarking(input: Marking | MarkingInput): input is Marking {\n return (\n typeof input.kind === \"string\" &&\n typeof input.sourceType === \"string\" &&\n typeof input.createdAt === \"string\" &&\n typeof input.humanReviewed === \"boolean\"\n );\n}\n\nexport function escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n","/**\n * Machine-readable AI marking for images: an XMP packet with the IPTC Digital Source Type,\n * written into PNG, JPEG and WebP files without re-encoding the pixels.\n *\n * This is unsigned metadata. It is what IPTC, Google and most photo tools read today, but it\n * is not a C2PA manifest and is easy to strip. Files that already carry a C2PA manifest are\n * left untouched by default, because rewriting them would break the manifest's hash binding.\n */\n\nimport { inflateZlib } from \"./inflate.js\";\nimport {\n createMarking,\n generatorName,\n iptcSourceType,\n isAiSourceType,\n parseSourceType,\n} from \"./marking.js\";\nimport type { Marking, MarkingInput, SourceType } from \"./types.js\";\n\nexport type ImageFormat = \"png\" | \"jpeg\" | \"webp\";\n\nexport interface MarkImageOptions {\n /**\n * What to do with files that already carry a C2PA manifest. `skip` (default) returns them\n * unchanged; `overwrite` writes the XMP anyway and breaks the manifest's hash binding.\n */\n c2pa?: \"skip\" | \"overwrite\";\n}\n\nexport interface MarkImageResult {\n bytes: Uint8Array;\n status: \"marked\" | \"skipped-c2pa\" | \"unsupported\";\n format: ImageFormat | null;\n}\n\nexport interface ImageMarkingInfo {\n format: ImageFormat | null;\n /** The XMP packet, if any. */\n xmp: string | null;\n /** IPTC Digital Source Type from the XMP. */\n sourceType?: SourceType;\n /** The source type says the image was made or changed by a trained AI model. */\n aiGenerated: boolean;\n /** `Iptc4xmpExt:AISystemUsed` or `xmp:CreatorTool`. */\n generator?: string;\n /** Written by Witness. */\n witness: boolean;\n /** A C2PA manifest is embedded. Witness does not verify it. */\n c2pa: boolean;\n}\n\nconst XMP_NS = \"http://ns.adobe.com/xap/1.0/\\0\";\nconst WITNESS_NS = \"https://packages.sweber.dev/witness/ns/1.0/\";\n\n/** Detects PNG, JPEG or WebP from the first bytes. */\nexport function detectImageFormat(bytes: Uint8Array): ImageFormat | null {\n if (bytes.length >= 8 && bytes[0] === 0x89 && ascii(bytes, 1, 3) === \"PNG\") return \"png\";\n if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {\n return \"jpeg\";\n }\n if (bytes.length >= 12 && ascii(bytes, 0, 4) === \"RIFF\" && ascii(bytes, 8, 4) === \"WEBP\") {\n return \"webp\";\n }\n return null;\n}\n\n/** Writes the marking as XMP into a PNG, JPEG or WebP file. */\nexport function markImage(\n bytes: Uint8Array,\n input: Marking | MarkingInput = {},\n options: MarkImageOptions = {},\n): MarkImageResult {\n const format = detectImageFormat(bytes);\n if (!format) return { bytes, status: \"unsupported\", format };\n if (options.c2pa !== \"overwrite\" && hasC2pa(bytes, format)) {\n return { bytes, status: \"skipped-c2pa\", format };\n }\n const marking =\n \"sourceType\" in input && \"humanReviewed\" in input ? (input as Marking) : createMarking(input);\n const existing = readXmp(bytes, format);\n const xmp = buildXmp(marking, existing);\n const out =\n format === \"png\"\n ? writePng(bytes, xmp)\n : format === \"jpeg\"\n ? writeJpeg(bytes, xmp)\n : writeWebp(bytes, xmp);\n return { bytes: out, status: \"marked\", format };\n}\n\n/** Reads the AI marking of an image, whoever wrote it. */\nexport function readImageMarking(bytes: Uint8Array): ImageMarkingInfo {\n const format = detectImageFormat(bytes);\n if (!format) return { format, xmp: null, aiGenerated: false, witness: false, c2pa: false };\n const xmp = readXmp(bytes, format);\n const sourceType = xmp\n ? parseSourceType(xmpProperty(xmp, \"Iptc4xmpExt:DigitalSourceType\"))\n : undefined;\n const generator = xmp\n ? (xmpProperty(xmp, \"Iptc4xmpExt:AISystemUsed\") ?? xmpProperty(xmp, \"xmp:CreatorTool\"))\n : undefined;\n const info: ImageMarkingInfo = {\n format,\n xmp,\n aiGenerated: isAiSourceType(sourceType),\n witness: xmp?.includes(WITNESS_NS) ?? false,\n c2pa: hasC2pa(bytes, format),\n };\n if (sourceType) info.sourceType = sourceType;\n if (generator) info.generator = generator;\n return info;\n}\n\n/** The XMP packet Witness writes, merged into an existing packet if there is one. */\nexport function buildXmp(marking: Marking, existing?: string | null): string {\n const description = buildDescription(marking);\n if (existing?.includes(\"</rdf:RDF>\")) {\n // Drop the description an earlier run wrote, in its self-closing or its paired form.\n const cleaned = existing\n .replace(/<rdf:Description\\b[^>]*witness:marker=\"1\"[^>]*\\/>\\s*/g, \"\")\n .replace(\n /<rdf:Description\\b[^>]*witness:marker=\"1\"[^>]*>[\\s\\S]*?<\\/rdf:Description>\\s*/g,\n \"\",\n );\n // Our description declares its own namespaces, so it can sit next to any other.\n return cleaned.replace(\"</rdf:RDF>\", `${description}\\n</rdf:RDF>`);\n }\n return [\n '<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>',\n '<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">',\n '<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">',\n description,\n \"</rdf:RDF>\",\n \"</x:xmpmeta>\",\n '<?xpacket end=\"w\"?>',\n ].join(\"\\n\");\n}\n\nfunction buildDescription(m: Marking): string {\n const attributes: Array<[string, string]> = [\n [\"rdf:about\", \"\"],\n [\"xmlns:Iptc4xmpExt\", \"http://iptc.org/std/Iptc4xmpExt/2008-02-29/\"],\n [\"xmlns:xmp\", \"http://ns.adobe.com/xap/1.0/\"],\n [\"xmlns:dc\", \"http://purl.org/dc/elements/1.1/\"],\n [\"xmlns:witness\", WITNESS_NS],\n [\"witness:marker\", \"1\"],\n [\"witness:kind\", m.kind],\n [\"Iptc4xmpExt:DigitalSourceType\", iptcSourceType(m.sourceType)],\n [\"xmp:CreateDate\", m.createdAt],\n ];\n if (m.generator) {\n attributes.push([\"Iptc4xmpExt:AISystemUsed\", m.generator]);\n attributes.push([\"xmp:CreatorTool\", generatorName(m)]);\n }\n if (m.generatorVersion) attributes.push([\"Iptc4xmpExt:AISystemVersionUsed\", m.generatorVersion]);\n if (m.provider) attributes.push([\"witness:provider\", m.provider]);\n if (m.disclosureUrl) attributes.push([\"witness:disclosureUrl\", m.disclosureUrl]);\n if (m.humanReviewed) attributes.push([\"witness:humanReviewed\", \"True\"]);\n const attrs = attributes.map(([name, value]) => `\\n ${name}=\"${escapeXml(value)}\"`).join(\"\");\n const description = m.description\n ? `\\n <dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">${escapeXml(m.description)}</rdf:li></rdf:Alt></dc:description>\\n`\n : \"\";\n return description\n ? `<rdf:Description${attrs}>${description}</rdf:Description>`\n : `<rdf:Description${attrs}/>`;\n}\n\n/** Reads a simple property in attribute or element form. */\nfunction xmpProperty(xmp: string, name: string): string | undefined {\n const escaped = name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const attribute = new RegExp(`${escaped}=\"([^\"]*)\"`).exec(xmp);\n if (attribute?.[1] !== undefined) return unescapeXml(attribute[1]);\n const element = new RegExp(\n `<${escaped}(?:\\\\s+rdf:resource=\"([^\"]*)\")?\\\\s*(?:/>|>([\\\\s\\\\S]*?)</${escaped}>)`,\n ).exec(xmp);\n if (!element) return undefined;\n if (element[1] !== undefined) return unescapeXml(element[1]);\n const inner = element[2] ?? \"\";\n const li = /<rdf:li[^>]*>([\\s\\S]*?)<\\/rdf:li>/.exec(inner);\n const value = (li ? li[1] : inner)?.trim();\n return value ? unescapeXml(value) : undefined;\n}\n\n// ---------------------------------------------------------------------------- PNG\n\nfunction writePng(bytes: Uint8Array, xmp: string): Uint8Array {\n const chunks = pngChunks(bytes).filter((chunk) => !isPngXmp(bytes, chunk));\n const itxt = pngChunk(\n \"iTXt\",\n concat(latin1(\"XML:com.adobe.xmp\"), new Uint8Array([0, 0, 0, 0, 0]), utf8(xmp)),\n );\n const parts: Uint8Array[] = [bytes.subarray(0, 8)];\n for (const chunk of chunks) {\n parts.push(bytes.subarray(chunk.offset, chunk.end));\n if (chunk.type === \"IHDR\") parts.push(itxt);\n }\n return concat(...parts);\n}\n\ninterface PngChunk {\n type: string;\n offset: number;\n dataStart: number;\n dataEnd: number;\n end: number;\n}\n\nfunction pngChunks(bytes: Uint8Array): PngChunk[] {\n const chunks: PngChunk[] = [];\n let offset = 8;\n while (offset + 12 <= bytes.length) {\n const length = readU32BE(bytes, offset);\n const type = ascii(bytes, offset + 4, 4);\n const dataStart = offset + 8;\n const dataEnd = dataStart + length;\n const end = dataEnd + 4;\n if (end > bytes.length) throw new Error(\"Witness: truncated PNG chunk\");\n chunks.push({ type, offset, dataStart, dataEnd, end });\n offset = end;\n if (type === \"IEND\") break;\n }\n return chunks;\n}\n\n/** XMP lives in iTXt per the XMP spec; libvips and some other tools write zTXt instead. */\nfunction isPngXmp(bytes: Uint8Array, chunk: PngChunk): boolean {\n return (\n (chunk.type === \"iTXt\" || chunk.type === \"zTXt\") &&\n ascii(bytes, chunk.dataStart, 18) === \"XML:com.adobe.xmp\\0\"\n );\n}\n\nfunction readPngXmp(bytes: Uint8Array): string | null {\n for (const chunk of pngChunks(bytes)) {\n if (!isPngXmp(bytes, chunk)) continue;\n let p = chunk.dataStart + 18;\n let compressed: boolean;\n if (chunk.type === \"zTXt\") {\n compressed = true;\n p += 1; // compression method\n } else {\n compressed = bytes[p] === 1;\n p += 2;\n while (p < chunk.dataEnd && bytes[p] !== 0) p++; // language tag\n p++;\n while (p < chunk.dataEnd && bytes[p] !== 0) p++; // translated keyword\n p++;\n }\n const data = bytes.subarray(p, chunk.dataEnd);\n try {\n return new TextDecoder().decode(compressed ? inflateZlib(data) : data);\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction pngChunk(type: string, data: Uint8Array): Uint8Array {\n const out = new Uint8Array(12 + data.length);\n writeU32BE(out, 0, data.length);\n out.set(latin1(type), 4);\n out.set(data, 8);\n writeU32BE(out, 8 + data.length, crc32(out.subarray(4, 8 + data.length)));\n return out;\n}\n\n// ---------------------------------------------------------------------------- JPEG\n\ninterface JpegSegment {\n marker: number;\n offset: number;\n dataStart: number;\n end: number;\n}\n\nfunction jpegSegments(bytes: Uint8Array): { segments: JpegSegment[]; scanStart: number } {\n const segments: JpegSegment[] = [];\n let offset = 2;\n while (offset + 4 <= bytes.length) {\n if (bytes[offset] !== 0xff) throw new Error(\"Witness: invalid JPEG marker\");\n let markerOffset = offset;\n while (bytes[markerOffset + 1] === 0xff) markerOffset++; // fill bytes\n const marker = bytes[markerOffset + 1] ?? 0;\n if (marker === 0xda || marker === 0xd9) return { segments, scanStart: offset };\n const length = readU16BE(bytes, markerOffset + 2);\n const end = markerOffset + 2 + length;\n if (end > bytes.length) throw new Error(\"Witness: truncated JPEG segment\");\n segments.push({ marker, offset, dataStart: markerOffset + 4, end });\n offset = end;\n }\n return { segments, scanStart: offset };\n}\n\nfunction isJpegXmp(bytes: Uint8Array, segment: JpegSegment): boolean {\n return segment.marker === 0xe1 && ascii(bytes, segment.dataStart, XMP_NS.length) === XMP_NS;\n}\n\nfunction writeJpeg(bytes: Uint8Array, xmp: string): Uint8Array {\n const { segments, scanStart } = jpegSegments(bytes);\n const payload = concat(latin1(XMP_NS), utf8(xmp));\n if (payload.length + 2 > 0xffff) throw new Error(\"Witness: XMP packet too large for JPEG\");\n const app1 = new Uint8Array(4 + payload.length);\n app1[0] = 0xff;\n app1[1] = 0xe1;\n app1[2] = ((payload.length + 2) >> 8) & 0xff;\n app1[3] = (payload.length + 2) & 0xff;\n app1.set(payload, 4);\n\n const kept = segments.filter((segment) => !isJpegXmp(bytes, segment));\n // Keep JFIF (APP0) and Exif (APP1) first, as readers expect them there.\n let insertAt = 0;\n while (insertAt < kept.length) {\n const segment = kept[insertAt];\n if (!segment) break;\n const isJfif = segment.marker === 0xe0;\n const isExif = segment.marker === 0xe1 && ascii(bytes, segment.dataStart, 4) === \"Exif\";\n if (!isJfif && !isExif) break;\n insertAt++;\n }\n const parts: Uint8Array[] = [bytes.subarray(0, 2)];\n kept.forEach((segment, index) => {\n if (index === insertAt) parts.push(app1);\n parts.push(bytes.subarray(segment.offset, segment.end));\n });\n if (insertAt >= kept.length) parts.push(app1);\n parts.push(bytes.subarray(scanStart));\n return concat(...parts);\n}\n\nfunction readJpegXmp(bytes: Uint8Array): string | null {\n for (const segment of jpegSegments(bytes).segments) {\n if (isJpegXmp(bytes, segment)) {\n return new TextDecoder().decode(\n bytes.subarray(segment.dataStart + XMP_NS.length, segment.end),\n );\n }\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------- WebP\n\ninterface RiffChunk {\n fourcc: string;\n offset: number;\n dataStart: number;\n size: number;\n end: number;\n}\n\nfunction webpChunks(bytes: Uint8Array): RiffChunk[] {\n const chunks: RiffChunk[] = [];\n const riffEnd = Math.min(bytes.length, 8 + readU32LE(bytes, 4));\n let offset = 12;\n while (offset + 8 <= riffEnd) {\n const fourcc = ascii(bytes, offset, 4);\n const size = readU32LE(bytes, offset + 4);\n const dataStart = offset + 8;\n const end = dataStart + size + (size % 2);\n if (dataStart + size > bytes.length) throw new Error(\"Witness: truncated WebP chunk\");\n chunks.push({ fourcc, offset, dataStart, size, end: Math.min(end, bytes.length) });\n offset = end;\n }\n return chunks;\n}\n\nfunction writeWebp(bytes: Uint8Array, xmp: string): Uint8Array {\n const chunks = webpChunks(bytes).filter((chunk) => chunk.fourcc !== \"XMP \");\n const first = chunks[0];\n if (!first) throw new Error(\"Witness: empty WebP file\");\n const parts: Uint8Array[] = [];\n if (first.fourcc === \"VP8X\") {\n const vp8x = bytes.slice(first.offset, first.end);\n vp8x[8] = (vp8x[8] ?? 0) | 0x04; // XMP flag\n parts.push(vp8x);\n for (const chunk of chunks.slice(1)) parts.push(bytes.subarray(chunk.offset, chunk.end));\n } else {\n const { width, height, alpha } = webpCanvas(bytes, first);\n const data = new Uint8Array(10);\n data[0] = 0x04 | (alpha ? 0x10 : 0);\n writeU24LE(data, 4, width - 1);\n writeU24LE(data, 7, height - 1);\n parts.push(riffChunk(\"VP8X\", data));\n for (const chunk of chunks) parts.push(bytes.subarray(chunk.offset, chunk.end));\n }\n parts.push(riffChunk(\"XMP \", utf8(xmp)));\n const body = concat(...parts);\n const out = new Uint8Array(12 + body.length);\n out.set(latin1(\"RIFF\"), 0);\n writeU32LE(out, 4, 4 + body.length);\n out.set(latin1(\"WEBP\"), 8);\n out.set(body, 12);\n return out;\n}\n\nfunction webpCanvas(\n bytes: Uint8Array,\n chunk: RiffChunk,\n): { width: number; height: number; alpha: boolean } {\n const d = chunk.dataStart;\n if (chunk.fourcc === \"VP8 \") {\n if (bytes[d + 3] !== 0x9d || bytes[d + 4] !== 0x01 || bytes[d + 5] !== 0x2a) {\n throw new Error(\"Witness: invalid VP8 frame\");\n }\n return {\n width: readU16LE(bytes, d + 6) & 0x3fff,\n height: readU16LE(bytes, d + 8) & 0x3fff,\n alpha: false,\n };\n }\n if (chunk.fourcc === \"VP8L\") {\n if (bytes[d] !== 0x2f) throw new Error(\"Witness: invalid VP8L frame\");\n const bits = readU32LE(bytes, d + 1);\n return {\n width: (bits & 0x3fff) + 1,\n height: ((bits >>> 14) & 0x3fff) + 1,\n alpha: ((bits >>> 28) & 1) === 1,\n };\n }\n throw new Error(`Witness: unexpected WebP chunk ${chunk.fourcc}`);\n}\n\nfunction readWebpXmp(bytes: Uint8Array): string | null {\n const chunk = webpChunks(bytes).find((c) => c.fourcc === \"XMP \");\n return chunk\n ? new TextDecoder().decode(bytes.subarray(chunk.dataStart, chunk.dataStart + chunk.size))\n : null;\n}\n\nfunction riffChunk(fourcc: string, data: Uint8Array): Uint8Array {\n const out = new Uint8Array(8 + data.length + (data.length % 2));\n out.set(latin1(fourcc), 0);\n writeU32LE(out, 4, data.length);\n out.set(data, 8);\n return out;\n}\n\n// ---------------------------------------------------------------------------- shared\n\nfunction readXmp(bytes: Uint8Array, format: ImageFormat): string | null {\n if (format === \"png\") return readPngXmp(bytes);\n if (format === \"jpeg\") return readJpegXmp(bytes);\n return readWebpXmp(bytes);\n}\n\n/** C2PA manifests live in caBX (PNG), APP11 JUMBF (JPEG) or C2PA (WebP) chunks. */\nfunction hasC2pa(bytes: Uint8Array, format: ImageFormat): boolean {\n if (format === \"png\") return pngChunks(bytes).some((chunk) => chunk.type === \"caBX\");\n if (format === \"webp\") return webpChunks(bytes).some((chunk) => chunk.fourcc === \"C2PA\");\n return jpegSegments(bytes).segments.some(\n (segment) =>\n segment.marker === 0xeb &&\n ascii(bytes, segment.dataStart, Math.min(64, segment.end - segment.dataStart)).includes(\n \"c2pa\",\n ),\n );\n}\n\nfunction ascii(bytes: Uint8Array, offset: number, length: number): string {\n let out = \"\";\n for (let i = offset; i < offset + length && i < bytes.length; i++) {\n out += String.fromCharCode(bytes[i] ?? 0);\n }\n return out;\n}\n\nfunction latin1(text: string): Uint8Array {\n const out = new Uint8Array(text.length);\n for (let i = 0; i < text.length; i++) out[i] = text.charCodeAt(i) & 0xff;\n return out;\n}\n\nfunction utf8(text: string): Uint8Array {\n return new TextEncoder().encode(text);\n}\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n const out = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n return out;\n}\n\nfunction readU16BE(b: Uint8Array, o: number): number {\n return ((b[o] ?? 0) << 8) | (b[o + 1] ?? 0);\n}\nfunction readU16LE(b: Uint8Array, o: number): number {\n return (b[o] ?? 0) | ((b[o + 1] ?? 0) << 8);\n}\nfunction readU32BE(b: Uint8Array, o: number): number {\n return (\n (((b[o] ?? 0) << 24) | ((b[o + 1] ?? 0) << 16) | ((b[o + 2] ?? 0) << 8) | (b[o + 3] ?? 0)) >>> 0\n );\n}\nfunction readU32LE(b: Uint8Array, o: number): number {\n return (\n ((b[o] ?? 0) | ((b[o + 1] ?? 0) << 8) | ((b[o + 2] ?? 0) << 16) | ((b[o + 3] ?? 0) << 24)) >>> 0\n );\n}\nfunction writeU32BE(b: Uint8Array, o: number, v: number): void {\n b[o] = (v >>> 24) & 0xff;\n b[o + 1] = (v >>> 16) & 0xff;\n b[o + 2] = (v >>> 8) & 0xff;\n b[o + 3] = v & 0xff;\n}\nfunction writeU32LE(b: Uint8Array, o: number, v: number): void {\n b[o] = v & 0xff;\n b[o + 1] = (v >>> 8) & 0xff;\n b[o + 2] = (v >>> 16) & 0xff;\n b[o + 3] = (v >>> 24) & 0xff;\n}\nfunction writeU24LE(b: Uint8Array, o: number, v: number): void {\n b[o] = v & 0xff;\n b[o + 1] = (v >>> 8) & 0xff;\n b[o + 2] = (v >>> 16) & 0xff;\n}\n\nlet crcTable: Uint32Array | null = null;\nfunction crc32(data: Uint8Array): number {\n if (!crcTable) {\n crcTable = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n crcTable[n] = c >>> 0;\n }\n }\n let crc = 0xffffffff;\n for (const byte of data) crc = (crcTable[(crc ^ byte) & 0xff] ?? 0) ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction unescapeXml(value: string): string {\n return value\n .replace(/"/g, '\"')\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/'/g, \"'\")\n .replace(/&/g, \"&\");\n}\n","/**\n * An invisible, machine-readable marker for AI-generated text.\n *\n * The payload is written as Unicode variation selectors (U+FE00–U+FE0F and\n * U+E0100–U+E01EF). They are default-ignorable code points: browsers do not render them and\n * screen readers skip them, and they survive copy and paste in most applications. They do\n * not survive sanitisers that strip unusual code points, retyping, or paraphrasing, so treat\n * this as one marking layer next to visible labels and metadata, not as a robust watermark.\n */\n\nconst MAGIC = [0x57, 0x31]; // \"W1\"\nconst MAX_PAYLOAD = 255;\n\nexport interface TextWatermark {\n /** Name of the AI system. */\n generator?: string;\n /** ISO 8601 timestamp. */\n createdAt?: string;\n /** Your own reference, e.g. a message or log id. */\n id?: string;\n}\n\nexport interface ReadTextWatermark extends TextWatermark {\n /** The raw payload as written. */\n raw: string;\n}\n\n/**\n * Appends an invisible watermark to `text`. An existing Witness watermark is replaced. Empty\n * text is returned unchanged.\n */\nexport function watermarkText(text: string, mark: TextWatermark = {}): string {\n if (text.length === 0) return text;\n return stripTextWatermark(text) + watermarkSuffix(mark);\n}\n\n/**\n * Only the invisible characters, for appending to a stream. They attach to whatever character\n * precedes them, so emit them after at least one visible character.\n */\nexport function watermarkSuffix(mark: TextWatermark = {}): string {\n const payload = encodePayload(mark);\n return [...MAGIC, payload.length, ...payload].map(byteToSelector).join(\"\");\n}\n\n/** Reads the first Witness watermark in `text`, or `null`. */\nexport function readTextWatermark(text: string): ReadTextWatermark | null {\n for (const run of selectorRuns(text)) {\n const found = findInRun(run.bytes);\n if (found) {\n const raw = new TextDecoder().decode(new Uint8Array(found.payload));\n return { ...decodePayload(raw), raw };\n }\n }\n return null;\n}\n\n/** True when `text` carries a Witness watermark. */\nexport function hasTextWatermark(text: string): boolean {\n return readTextWatermark(text) !== null;\n}\n\n/**\n * Removes Witness watermarks and leaves all other characters, including the variation\n * selectors that belong to emoji, untouched.\n */\nexport function stripTextWatermark(text: string): string {\n const chars = [...text];\n const remove = new Set<number>();\n for (const run of selectorRuns(text)) {\n let offset = 0;\n while (offset < run.bytes.length) {\n const found = findInRun(run.bytes.slice(offset));\n if (!found) break;\n const start = offset + found.start;\n const end = offset + found.end;\n for (let i = start; i < end; i++) remove.add(run.start + i);\n offset = end;\n }\n }\n if (remove.size === 0) return text;\n return chars.filter((_, index) => !remove.has(index)).join(\"\");\n}\n\nfunction encodePayload(mark: TextWatermark): number[] {\n const fields: string[] = [];\n if (mark.generator) fields.push(`g=${encodeURIComponent(mark.generator)}`);\n if (mark.createdAt) fields.push(`t=${encodeURIComponent(mark.createdAt)}`);\n if (mark.id) fields.push(`i=${encodeURIComponent(mark.id)}`);\n let bytes = [...new TextEncoder().encode(fields.join(\";\"))];\n if (bytes.length > MAX_PAYLOAD) {\n // Keep whole fields only, so a truncated payload still parses.\n while (fields.length > 0 && bytes.length > MAX_PAYLOAD) {\n fields.pop();\n bytes = [...new TextEncoder().encode(fields.join(\";\"))];\n }\n }\n return bytes;\n}\n\nfunction decodePayload(raw: string): TextWatermark {\n const result: TextWatermark = {};\n for (const field of raw.split(\";\")) {\n const index = field.indexOf(\"=\");\n if (index < 1) continue;\n const key = field.slice(0, index);\n let value: string;\n try {\n value = decodeURIComponent(field.slice(index + 1));\n } catch {\n continue;\n }\n if (key === \"g\") result.generator = value;\n else if (key === \"t\") result.createdAt = value;\n else if (key === \"i\") result.id = value;\n }\n return result;\n}\n\nfunction byteToSelector(byte: number): string {\n return byte < 16\n ? String.fromCodePoint(0xfe00 + byte)\n : String.fromCodePoint(0xe0100 + (byte - 16));\n}\n\nfunction selectorToByte(codePoint: number): number | null {\n if (codePoint >= 0xfe00 && codePoint <= 0xfe0f) return codePoint - 0xfe00;\n if (codePoint >= 0xe0100 && codePoint <= 0xe01ef) return codePoint - 0xe0100 + 16;\n return null;\n}\n\n/** Consecutive variation selectors, with their index in code points. */\nfunction selectorRuns(text: string): Array<{ start: number; bytes: number[] }> {\n const runs: Array<{ start: number; bytes: number[] }> = [];\n let current: { start: number; bytes: number[] } | null = null;\n let index = 0;\n for (const char of text) {\n const byte = selectorToByte(char.codePointAt(0) ?? 0);\n if (byte === null) {\n current = null;\n } else {\n if (!current) {\n current = { start: index, bytes: [] };\n runs.push(current);\n }\n current.bytes.push(byte);\n }\n index++;\n }\n return runs;\n}\n\n/** Finds MAGIC, length and payload inside a run. Positions are indexes into `bytes`. */\nfunction findInRun(bytes: number[]): { start: number; end: number; payload: number[] } | null {\n for (let i = 0; i + MAGIC.length < bytes.length; i++) {\n if (bytes[i] !== MAGIC[0] || bytes[i + 1] !== MAGIC[1]) continue;\n const length = bytes[i + 2];\n if (length === undefined) continue;\n const start = i + 3;\n const end = start + length;\n if (end > bytes.length) continue;\n return { start: i, end, payload: bytes.slice(start, end) };\n }\n return null;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/ai-sdk.ts","../src/inflate.ts","../src/marking.ts","../src/image.ts","../src/watermark.ts"],"sourcesContent":["/**\n * Middleware for the Vercel AI SDK (`ai` 5, 6 and 7). It marks what a model produces:\n *\n * - `witnessMiddleware` appends the invisible text watermark to every text part, for\n * `generateText` and `streamText`, and adds `providerMetadata.witness`.\n * - `witnessImageMiddleware` writes XMP with the IPTC Digital Source Type into every image\n * from `generateImage`.\n *\n * The types are structural, so this module has no dependency on `ai`.\n */\n\nimport { type MarkImageOptions, markImage } from \"./image.js\";\nimport { createMarking, iptcSourceType } from \"./marking.js\";\nimport type { ContentKind, Marking } from \"./types.js\";\nimport { watermarkSuffix, watermarkText } from \"./watermark.js\";\n\ntype SpecVersion = \"v2\" | \"v3\" | \"v4\";\n\ninterface ModelInfo {\n provider: string;\n modelId: string;\n}\n\nexport interface WitnessMarkedEvent {\n type: \"text\" | \"image\";\n marking: Marking;\n /** For text: the id of the text part in a stream, if any. */\n partId?: string;\n /** For images: what happened to each image. */\n status?: string;\n}\n\nexport interface WitnessMiddlewareOptions {\n /**\n * The AI SDK middleware specification. `v4` for `ai` 7 (default), `v3` for `ai` 6, `v2`\n * for `ai` 5.\n */\n specificationVersion?: SpecVersion;\n /** Name written into the marking. Default: `provider/modelId` of the wrapped model. */\n generator?: string | ((model: ModelInfo) => string);\n /** Default `generated`. */\n kind?: ContentKind;\n /** Your company or product, written into the marking. */\n provider?: string;\n /** Append the invisible text watermark. Default `true`. */\n watermark?: boolean;\n /** A reference written into the watermark, e.g. a log id. */\n id?: () => string;\n /** Called once per marked text part or image, e.g. to write an audit log entry. */\n onMarked?: (event: WitnessMarkedEvent) => void;\n}\n\ninterface TextPart {\n type: string;\n text?: string;\n}\n\ninterface GenerateResult {\n content: TextPart[];\n providerMetadata?: Record<string, unknown>;\n}\n\ninterface StreamPart {\n type: string;\n id?: string;\n delta?: string;\n providerMetadata?: Record<string, unknown>;\n}\n\ninterface StreamResult {\n stream: ReadableStream<StreamPart>;\n}\n\n/** The `witness` entry added to `providerMetadata`. */\nexport function witnessProviderMetadata(marking: Marking): Record<string, string | boolean> {\n return {\n aiGenerated: true,\n kind: marking.kind,\n sourceType: iptcSourceType(marking.sourceType),\n createdAt: marking.createdAt,\n ...(marking.generator ? { generator: marking.generator } : {}),\n ...(marking.provider ? { provider: marking.provider } : {}),\n };\n}\n\n/** Language model middleware. Pass it to `wrapLanguageModel`. */\nexport function witnessMiddleware(options: WitnessMiddlewareOptions = {}) {\n const watermark = options.watermark ?? true;\n\n const markingFor = (model: ModelInfo): Marking =>\n createMarking({\n kind: options.kind ?? \"generated\",\n generator: generatorFor(options.generator, model),\n ...(options.provider ? { provider: options.provider } : {}),\n });\n\n const watermarkFor = (marking: Marking) => ({\n ...(marking.generator ? { generator: marking.generator } : {}),\n createdAt: marking.createdAt,\n ...(options.id ? { id: options.id() } : {}),\n });\n\n return {\n specificationVersion: options.specificationVersion ?? \"v4\",\n\n async wrapGenerate<R extends GenerateResult>({\n doGenerate,\n model,\n }: {\n doGenerate: () => PromiseLike<R>;\n model: ModelInfo;\n }): Promise<R> {\n const result = await doGenerate();\n const marking = markingFor(model);\n const content = result.content.map((part) => {\n if (part.type !== \"text\" || typeof part.text !== \"string\" || part.text.length === 0) {\n return part;\n }\n options.onMarked?.({ type: \"text\", marking });\n return watermark\n ? { ...part, text: watermarkText(part.text, watermarkFor(marking)) }\n : part;\n });\n return {\n ...result,\n content,\n providerMetadata: { ...result.providerMetadata, witness: witnessProviderMetadata(marking) },\n };\n },\n\n async wrapStream<R extends StreamResult>({\n doStream,\n model,\n }: {\n doStream: () => PromiseLike<R>;\n model: ModelInfo;\n }): Promise<R> {\n const result = await doStream();\n const marking = markingFor(model);\n const withText = new Set<string>();\n const transform = new TransformStream<StreamPart, StreamPart>({\n transform(part, controller) {\n const id = part.id ?? \"\";\n if (\n part.type === \"text-delta\" &&\n typeof part.delta === \"string\" &&\n part.delta.length > 0\n ) {\n withText.add(id);\n }\n if (part.type === \"text-end\" && withText.has(id)) {\n withText.delete(id);\n options.onMarked?.({ type: \"text\", marking, partId: id });\n if (watermark) {\n controller.enqueue({\n type: \"text-delta\",\n id,\n delta: watermarkSuffix(watermarkFor(marking)),\n });\n }\n }\n if (part.type === \"finish\") {\n controller.enqueue({\n ...part,\n providerMetadata: {\n ...part.providerMetadata,\n witness: witnessProviderMetadata(marking),\n },\n });\n return;\n }\n controller.enqueue(part);\n },\n });\n return { ...result, stream: result.stream.pipeThrough(transform) };\n },\n };\n}\n\nexport interface WitnessImageMiddlewareOptions\n extends Pick<WitnessMiddlewareOptions, \"generator\" | \"kind\" | \"provider\" | \"onMarked\">,\n MarkImageOptions {\n /** `v4` for `ai` 7 (default), `v3` for `ai` 6. */\n specificationVersion?: \"v3\" | \"v4\";\n}\n\ninterface ImageResult {\n images: string[] | Uint8Array[];\n warnings: unknown[];\n}\n\n/** Image model middleware. Pass it to `wrapImageModel`. */\nexport function witnessImageMiddleware(options: WitnessImageMiddlewareOptions = {}) {\n return {\n specificationVersion: options.specificationVersion ?? \"v4\",\n\n async wrapGenerate<R extends ImageResult>({\n doGenerate,\n model,\n }: {\n doGenerate: () => PromiseLike<R>;\n model: ModelInfo;\n }): Promise<R> {\n const result = await doGenerate();\n const marking = createMarking({\n kind: options.kind ?? \"generated\",\n generator: generatorFor(options.generator, model),\n ...(options.provider ? { provider: options.provider } : {}),\n });\n const warnings = [...result.warnings];\n const markOne = (bytes: Uint8Array): Uint8Array => {\n const marked = markImage(bytes, marking, options.c2pa ? { c2pa: options.c2pa } : {});\n options.onMarked?.({ type: \"image\", marking, status: marked.status });\n if (marked.status !== \"marked\") {\n warnings.push({\n type: \"other\",\n message:\n marked.status === \"skipped-c2pa\"\n ? \"Witness: image already carries a C2PA manifest and was left unchanged.\"\n : \"Witness: image format not supported (PNG, JPEG, WebP); image is not marked.\",\n });\n }\n return marked.bytes;\n };\n const images = result.images.map((image: string | Uint8Array) =>\n typeof image === \"string\" ? toBase64(markOne(fromBase64(image))) : markOne(image),\n ) as R[\"images\"];\n return { ...result, images, warnings };\n },\n };\n}\n\nfunction generatorFor(option: WitnessMiddlewareOptions[\"generator\"], model: ModelInfo): string {\n if (typeof option === \"function\") return option(model);\n return option ?? `${model.provider}/${model.modelId}`;\n}\n\nfunction fromBase64(value: string): Uint8Array {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = \"\";\n const step = 0x8000;\n for (let i = 0; i < bytes.length; i += step) {\n binary += String.fromCharCode(...bytes.subarray(i, i + step));\n }\n return btoa(binary);\n}\n","/**\n * A small synchronous zlib inflater (RFC 1950/1951), enough to read compressed XMP from PNG\n * zTXt and iTXt chunks in any JavaScript runtime. Based on the structure of tinf by\n * Jørgen Ibsen (zlib licence).\n */\n\ninterface Tree {\n counts: Uint16Array;\n symbols: Uint16Array;\n}\n\nconst LENGTH_BASE = [\n 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,\n 163, 195, 227, 258,\n];\nconst LENGTH_EXTRA = [\n 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,\n];\nconst DIST_BASE = [\n 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049,\n 3073, 4097, 6145, 8193, 12289, 16385, 24577,\n];\nconst DIST_EXTRA = [\n 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,\n];\nconst CODE_LENGTH_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];\n\nfunction buildTree(lengths: ArrayLike<number>, offset: number, count: number): Tree {\n const tree: Tree = { counts: new Uint16Array(16), symbols: new Uint16Array(count) };\n for (let i = 0; i < count; i++) {\n const length = lengths[offset + i] ?? 0;\n tree.counts[length] = (tree.counts[length] ?? 0) + 1;\n }\n tree.counts[0] = 0;\n const offsets = new Uint16Array(16);\n let sum = 0;\n for (let i = 0; i < 16; i++) {\n offsets[i] = sum;\n sum += tree.counts[i] ?? 0;\n }\n for (let i = 0; i < count; i++) {\n const length = lengths[offset + i] ?? 0;\n if (length) {\n const at = offsets[length] ?? 0;\n tree.symbols[at] = i;\n offsets[length] = at + 1;\n }\n }\n return tree;\n}\n\nlet fixed: { lit: Tree; dist: Tree } | null = null;\nfunction fixedTrees(): { lit: Tree; dist: Tree } {\n if (!fixed) {\n const lengths = new Uint8Array(288);\n lengths.fill(8, 0, 144);\n lengths.fill(9, 144, 256);\n lengths.fill(7, 256, 280);\n lengths.fill(8, 280, 288);\n fixed = { lit: buildTree(lengths, 0, 288), dist: buildTree(new Uint8Array(30).fill(5), 0, 30) };\n }\n return fixed;\n}\n\nclass Reader {\n pos = 0;\n bit = 0;\n bits = 0;\n constructor(readonly data: Uint8Array) {}\n\n getBit(): number {\n if (this.bits === 0) {\n if (this.pos >= this.data.length) throw new Error(\"inflate: unexpected end of data\");\n this.bit = this.data[this.pos++] ?? 0;\n this.bits = 8;\n }\n const value = this.bit & 1;\n this.bit >>>= 1;\n this.bits--;\n return value;\n }\n\n read(count: number, base = 0): number {\n let value = 0;\n for (let i = 0; i < count; i++) value |= this.getBit() << i;\n return value + base;\n }\n\n decode(tree: Tree): number {\n let sum = 0;\n let cur = 0;\n let len = 0;\n do {\n cur = 2 * cur + this.getBit();\n len++;\n if (len > 15) throw new Error(\"inflate: invalid code\");\n sum += tree.counts[len] ?? 0;\n cur -= tree.counts[len] ?? 0;\n } while (cur >= 0);\n return tree.symbols[sum + cur] ?? 0;\n }\n}\n\nfunction dynamicTrees(r: Reader): { lit: Tree; dist: Tree } {\n const hlit = r.read(5, 257);\n const hdist = r.read(5, 1);\n const hclen = r.read(4, 4);\n const codeLengths = new Uint8Array(19);\n for (let i = 0; i < hclen; i++) codeLengths[CODE_LENGTH_ORDER[i] ?? 0] = r.read(3);\n const codeTree = buildTree(codeLengths, 0, 19);\n const lengths = new Uint8Array(hlit + hdist);\n for (let n = 0; n < hlit + hdist; ) {\n const sym = r.decode(codeTree);\n if (sym < 16) {\n lengths[n++] = sym;\n continue;\n }\n let repeat: number;\n let value = 0;\n if (sym === 16) {\n if (n === 0) throw new Error(\"inflate: invalid repeat\");\n value = lengths[n - 1] ?? 0;\n repeat = r.read(2, 3);\n } else if (sym === 17) {\n repeat = r.read(3, 3);\n } else {\n repeat = r.read(7, 11);\n }\n while (repeat-- > 0) lengths[n++] = value;\n }\n return { lit: buildTree(lengths, 0, hlit), dist: buildTree(lengths, hlit, hdist) };\n}\n\n/** Inflates zlib-wrapped data. Throws on corrupt input or when `maxLength` is exceeded. */\nexport function inflateZlib(data: Uint8Array, maxLength = 16 * 1024 * 1024): Uint8Array {\n if (\n data.length < 2 ||\n ((data[0] ?? 0) & 0x0f) !== 8 ||\n (((data[0] ?? 0) << 8) | (data[1] ?? 0)) % 31 !== 0\n ) {\n throw new Error(\"inflate: not a zlib stream\");\n }\n const r = new Reader(data);\n r.pos = 2;\n let out = new Uint8Array(Math.max(1024, data.length * 4));\n let length = 0;\n const push = (byte: number) => {\n if (length >= out.length) {\n if (out.length >= maxLength) throw new Error(\"inflate: output too large\");\n const next = new Uint8Array(Math.min(maxLength, out.length * 2));\n next.set(out);\n out = next;\n }\n out[length++] = byte;\n };\n\n let final = 0;\n do {\n final = r.getBit();\n const type = r.read(2);\n if (type === 0) {\n r.bits = 0;\n if (r.pos + 4 > data.length) throw new Error(\"inflate: unexpected end of data\");\n const len = (data[r.pos] ?? 0) | ((data[r.pos + 1] ?? 0) << 8);\n r.pos += 4;\n if (r.pos + len > data.length) throw new Error(\"inflate: unexpected end of data\");\n for (let i = 0; i < len; i++) push(data[r.pos++] ?? 0);\n } else if (type === 1 || type === 2) {\n const { lit, dist } = type === 1 ? fixedTrees() : dynamicTrees(r);\n for (;;) {\n const sym = r.decode(lit);\n if (sym === 256) break;\n if (sym < 256) {\n push(sym);\n continue;\n }\n const index = sym - 257;\n const len = r.read(LENGTH_EXTRA[index] ?? 0, LENGTH_BASE[index] ?? 0);\n const distSym = r.decode(dist);\n const offset = r.read(DIST_EXTRA[distSym] ?? 0, DIST_BASE[distSym] ?? 0);\n if (offset > length) throw new Error(\"inflate: invalid distance\");\n for (let i = 0; i < len; i++) push(out[length - offset] ?? 0);\n }\n } else {\n throw new Error(\"inflate: invalid block type\");\n }\n } while (!final);\n return out.subarray(0, length);\n}\n","import { format, getMessages } from \"./i18n.js\";\nimport type { ContentKind, LocaleOverride, Marking, MarkingInput, SourceType } from \"./types.js\";\n\nconst IPTC_BASE = \"http://cv.iptc.org/newscodes/digitalsourcetype/\";\n\nconst SCHEMA_ORG: Record<SourceType, string> = {\n trainedAlgorithmicMedia: \"https://schema.org/TrainedAlgorithmicMediaDigitalSource\",\n compositeWithTrainedAlgorithmicMedia:\n \"https://schema.org/CompositeWithTrainedAlgorithmicMediaDigitalSource\",\n algorithmicallyEnhanced: \"https://schema.org/AlgorithmicallyEnhancedDigitalSource\",\n algorithmicMedia: \"https://schema.org/AlgorithmicMediaDigitalSource\",\n compositeSynthetic: \"https://schema.org/CompositeSyntheticDigitalSource\",\n};\n\nconst DEFAULT_SOURCE: Record<ContentKind, SourceType> = {\n generated: \"trainedAlgorithmicMedia\",\n edited: \"compositeWithTrainedAlgorithmicMedia\",\n deepfake: \"trainedAlgorithmicMedia\",\n};\n\n/** The IPTC Digital Source Type URI, e.g. for XMP or `data-ai-source-type`. */\nexport function iptcSourceType(type: SourceType): string {\n return IPTC_BASE + type;\n}\n\n/** The schema.org `IPTCDigitalSourceEnumeration` member for JSON-LD. */\nexport function schemaOrgSourceType(type: SourceType): string {\n return SCHEMA_ORG[type];\n}\n\n/** Reads a source type from an IPTC or schema.org URI, or from the bare name. */\nexport function parseSourceType(value: string | null | undefined): SourceType | undefined {\n if (!value) return undefined;\n const trimmed = value.trim();\n const name = trimmed.startsWith(IPTC_BASE) ? trimmed.slice(IPTC_BASE.length) : trimmed;\n if (name in SCHEMA_ORG) return name as SourceType;\n for (const [type, uri] of Object.entries(SCHEMA_ORG)) {\n if (uri === trimmed) return type as SourceType;\n }\n return undefined;\n}\n\n/** True for source types that mean \"made or changed by a trained AI model\". */\nexport function isAiSourceType(type: SourceType | undefined): boolean {\n return (\n type === \"trainedAlgorithmicMedia\" ||\n type === \"compositeWithTrainedAlgorithmicMedia\" ||\n type === \"algorithmicallyEnhanced\"\n );\n}\n\n/** Applies defaults to a marking. */\nexport function createMarking(input: MarkingInput = {}): Marking {\n const kind = input.kind ?? \"generated\";\n const createdAt =\n input.createdAt instanceof Date\n ? input.createdAt.toISOString()\n : (input.createdAt ?? new Date().toISOString());\n const marking: Marking = {\n kind,\n sourceType: input.sourceType ?? DEFAULT_SOURCE[kind],\n createdAt,\n humanReviewed: input.humanReviewed ?? false,\n };\n if (input.generator) marking.generator = input.generator;\n if (input.generatorVersion) marking.generatorVersion = input.generatorVersion;\n if (input.provider) marking.provider = input.provider;\n if (input.disclosureUrl) marking.disclosureUrl = input.disclosureUrl;\n if (input.description) marking.description = input.description;\n return marking;\n}\n\n/**\n * `data-*` attributes that mark an element's content as AI-generated. Spread them on the\n * element that wraps the content.\n */\nexport function markingAttributes(input: Marking | MarkingInput): Record<string, string> {\n const m = normalise(input);\n const attributes: Record<string, string> = {\n \"data-ai-generated\": \"true\",\n \"data-ai-kind\": m.kind,\n \"data-ai-source-type\": iptcSourceType(m.sourceType),\n \"data-ai-created\": m.createdAt,\n };\n if (m.generator) attributes[\"data-ai-generator\"] = generatorName(m);\n if (m.provider) attributes[\"data-ai-provider\"] = m.provider;\n if (m.humanReviewed) attributes[\"data-ai-reviewed\"] = \"true\";\n return attributes;\n}\n\n/**\n * Page-level `<meta>` tags for a page whose main content is AI-generated. There is no\n * standardised meta tag yet, so these are a convention; pair them with {@link markingJsonLd}.\n */\nexport function markingMetaTags(\n input: Marking | MarkingInput,\n): Array<{ name: string; content: string }> {\n const m = normalise(input);\n const tags = [\n { name: \"ai-generated\", content: m.kind },\n { name: \"ai-source-type\", content: iptcSourceType(m.sourceType) },\n ];\n if (m.generator) tags.push({ name: \"ai-generator\", content: generatorName(m) });\n if (m.humanReviewed) tags.push({ name: \"ai-reviewed\", content: \"true\" });\n return tags;\n}\n\n/** The meta tags as an HTML string. */\nexport function renderMetaTags(input: Marking | MarkingInput): string {\n return markingMetaTags(input)\n .map((tag) => `<meta name=\"${escapeHtml(tag.name)}\" content=\"${escapeHtml(tag.content)}\">`)\n .join(\"\\n\");\n}\n\n/** The meta tags in the shape of Next.js `metadata.other`. */\nexport function nextMetadata(input: Marking | MarkingInput): { other: Record<string, string> } {\n return {\n other: Object.fromEntries(markingMetaTags(input).map((tag) => [tag.name, tag.content])),\n };\n}\n\n/**\n * schema.org JSON-LD for a creative work, with `digitalSourceType` set. Merge `extra` to add\n * your own properties such as `headline` or `@type: \"NewsArticle\"`.\n */\nexport function markingJsonLd(\n input: Marking | MarkingInput,\n extra: Record<string, unknown> = {},\n): Record<string, unknown> {\n const m = normalise(input);\n const data: Record<string, unknown> = {\n \"@context\": \"https://schema.org\",\n \"@type\": \"CreativeWork\",\n digitalSourceType: schemaOrgSourceType(m.sourceType),\n dateCreated: m.createdAt,\n };\n if (m.generator) {\n data.creator = {\n \"@type\": \"SoftwareApplication\",\n name: m.generator,\n ...(m.generatorVersion ? { softwareVersion: m.generatorVersion } : {}),\n };\n }\n if (m.provider) data.publisher = { \"@type\": \"Organization\", name: m.provider };\n if (m.description) data.description = m.description;\n return { ...data, ...extra };\n}\n\n/** The JSON-LD as a `<script type=\"application/ld+json\">` tag. */\nexport function renderJsonLd(\n input: Marking | MarkingInput,\n extra: Record<string, unknown> = {},\n): string {\n const json = JSON.stringify(markingJsonLd(input, extra)).replace(/</g, \"\\\\u003c\");\n return `<script type=\"application/ld+json\">${json}</script>`;\n}\n\nexport interface LabelHtmlOptions {\n locale?: string | readonly string[];\n messages?: LocaleOverride;\n /** Where the visible label goes. Text should be labelled at the top. Default `top`. */\n position?: \"top\" | \"bottom\";\n /** Element that wraps label and content. Default `div`. */\n tag?: \"div\" | \"section\" | \"article\" | \"figure\" | \"aside\";\n}\n\n/**\n * Wraps server-rendered HTML in an element that carries the marking attributes and a visible\n * label. Works without JavaScript; style it with `@sweberdev/witness/styles.css` or your own\n * CSS for `.witness-label`.\n */\nexport function labelHtml(\n html: string,\n input: Marking | MarkingInput,\n options: LabelHtmlOptions = {},\n): string {\n const m = normalise(input);\n const tag = options.tag ?? \"div\";\n const attributes = Object.entries(markingAttributes(m))\n .map(([name, value]) => ` ${name}=\"${escapeHtml(value)}\"`)\n .join(\"\");\n const label = renderLabelLine(m, options);\n const body = options.position === \"bottom\" ? `${html}${label}` : `${label}${html}`;\n return `<${tag} class=\"witness-content\"${attributes}>${body}</${tag}>`;\n}\n\n/** One line of visible label text, e.g. \"KI-generiert · Erzeugt mit Claude\". */\nexport function labelText(\n input: Marking | MarkingInput,\n options: Pick<LabelHtmlOptions, \"locale\" | \"messages\"> = {},\n): string {\n const m = normalise(input);\n const messages = getMessages(options.locale, options.messages);\n const parts = [messages.kinds[m.kind].label];\n if (m.generator) {\n parts.push(format(messages.ui.generatedWith, { generator: generatorName(m) }));\n }\n if (m.humanReviewed) parts.push(messages.ui.humanReviewed);\n return parts.join(\" · \");\n}\n\nfunction renderLabelLine(m: Marking, options: LabelHtmlOptions): string {\n const messages = getMessages(options.locale, options.messages);\n const text = escapeHtml(labelText(m, options));\n const link = m.disclosureUrl\n ? ` <a class=\"witness-label__link\" href=\"${escapeHtml(m.disclosureUrl)}\">${escapeHtml(messages.ui.moreInfo)}</a>`\n : \"\";\n return `<p class=\"witness-label\" role=\"note\"><span class=\"witness-label__icon\" aria-hidden=\"true\">AI</span> <span class=\"witness-label__text\">${text}</span>${link}</p>`;\n}\n\n/** \"Model 1.2\" when a version is known. */\nexport function generatorName(m: Pick<Marking, \"generator\" | \"generatorVersion\">): string {\n if (!m.generator) return \"\";\n return m.generatorVersion ? `${m.generator} ${m.generatorVersion}` : m.generator;\n}\n\nfunction normalise(input: Marking | MarkingInput): Marking {\n return isMarking(input) ? input : createMarking(input);\n}\n\nfunction isMarking(input: Marking | MarkingInput): input is Marking {\n return (\n typeof input.kind === \"string\" &&\n typeof input.sourceType === \"string\" &&\n typeof input.createdAt === \"string\" &&\n typeof input.humanReviewed === \"boolean\"\n );\n}\n\nexport function escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n","/**\n * Machine-readable AI marking for images: an XMP packet with the IPTC Digital Source Type,\n * written into PNG, JPEG and WebP files without re-encoding the pixels.\n *\n * This is unsigned metadata. It is what IPTC, Google and most photo tools read today, but it\n * is not a C2PA manifest and is easy to strip. Files that already carry a C2PA manifest are\n * left untouched by default, because rewriting them would break the manifest's hash binding.\n */\n\nimport { inflateZlib } from \"./inflate.js\";\nimport {\n createMarking,\n generatorName,\n iptcSourceType,\n isAiSourceType,\n parseSourceType,\n} from \"./marking.js\";\nimport type { Marking, MarkingInput, SourceType } from \"./types.js\";\n\nexport type ImageFormat = \"png\" | \"jpeg\" | \"webp\";\n\nexport interface MarkImageOptions {\n /**\n * What to do with files that already carry a C2PA manifest. `skip` (default) returns them\n * unchanged; `overwrite` writes the XMP anyway and breaks the manifest's hash binding.\n */\n c2pa?: \"skip\" | \"overwrite\";\n}\n\nexport interface MarkImageResult {\n bytes: Uint8Array;\n status: \"marked\" | \"skipped-c2pa\" | \"unsupported\";\n format: ImageFormat | null;\n}\n\nexport interface ImageMarkingInfo {\n format: ImageFormat | null;\n /** The XMP packet, if any. */\n xmp: string | null;\n /** IPTC Digital Source Type from the XMP. */\n sourceType?: SourceType;\n /** The source type says the image was made or changed by a trained AI model. */\n aiGenerated: boolean;\n /** `Iptc4xmpExt:AISystemUsed` or `xmp:CreatorTool`. */\n generator?: string;\n /** Written by Witness. */\n witness: boolean;\n /** A C2PA manifest is embedded. Witness does not verify it. */\n c2pa: boolean;\n}\n\nconst XMP_NS = \"http://ns.adobe.com/xap/1.0/\\0\";\n/** @internal */\nexport const WITNESS_NS = \"https://packages.sweber.dev/witness/ns/1.0/\";\n\n/** Detects PNG, JPEG or WebP from the first bytes. */\nexport function detectImageFormat(bytes: Uint8Array): ImageFormat | null {\n if (bytes.length >= 8 && bytes[0] === 0x89 && ascii(bytes, 1, 3) === \"PNG\") return \"png\";\n if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {\n return \"jpeg\";\n }\n if (bytes.length >= 12 && ascii(bytes, 0, 4) === \"RIFF\" && ascii(bytes, 8, 4) === \"WEBP\") {\n return \"webp\";\n }\n return null;\n}\n\n/** Writes the marking as XMP into a PNG, JPEG or WebP file. */\nexport function markImage(\n bytes: Uint8Array,\n input: Marking | MarkingInput = {},\n options: MarkImageOptions = {},\n): MarkImageResult {\n const format = detectImageFormat(bytes);\n if (!format) return { bytes, status: \"unsupported\", format };\n if (options.c2pa !== \"overwrite\" && hasC2pa(bytes, format)) {\n return { bytes, status: \"skipped-c2pa\", format };\n }\n const marking =\n \"sourceType\" in input && \"humanReviewed\" in input ? (input as Marking) : createMarking(input);\n const existing = readXmp(bytes, format);\n const xmp = buildXmp(marking, existing);\n const out =\n format === \"png\"\n ? writePng(bytes, xmp)\n : format === \"jpeg\"\n ? writeJpeg(bytes, xmp)\n : writeWebp(bytes, xmp);\n return { bytes: out, status: \"marked\", format };\n}\n\n/** Reads the AI marking of an image, whoever wrote it. */\nexport function readImageMarking(bytes: Uint8Array): ImageMarkingInfo {\n const format = detectImageFormat(bytes);\n if (!format) return { format, xmp: null, aiGenerated: false, witness: false, c2pa: false };\n const xmp = readXmp(bytes, format);\n const sourceType = xmp\n ? parseSourceType(xmpProperty(xmp, \"Iptc4xmpExt:DigitalSourceType\"))\n : undefined;\n const generator = xmp\n ? (xmpProperty(xmp, \"Iptc4xmpExt:AISystemUsed\") ?? xmpProperty(xmp, \"xmp:CreatorTool\"))\n : undefined;\n const info: ImageMarkingInfo = {\n format,\n xmp,\n aiGenerated: isAiSourceType(sourceType),\n witness: xmp?.includes(WITNESS_NS) ?? false,\n c2pa: hasC2pa(bytes, format),\n };\n if (sourceType) info.sourceType = sourceType;\n if (generator) info.generator = generator;\n return info;\n}\n\n/** The XMP packet Witness writes, merged into an existing packet if there is one. */\nexport function buildXmp(marking: Marking, existing?: string | null): string {\n const description = buildDescription(marking);\n if (existing?.includes(\"</rdf:RDF>\")) {\n // Drop the description an earlier run wrote, in its self-closing or its paired form.\n const cleaned = existing\n .replace(/<rdf:Description\\b[^>]*witness:marker=\"1\"[^>]*\\/>\\s*/g, \"\")\n .replace(\n /<rdf:Description\\b[^>]*witness:marker=\"1\"[^>]*>[\\s\\S]*?<\\/rdf:Description>\\s*/g,\n \"\",\n );\n // Our description declares its own namespaces, so it can sit next to any other.\n return cleaned.replace(\"</rdf:RDF>\", `${description}\\n</rdf:RDF>`);\n }\n return [\n '<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>',\n '<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">',\n '<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">',\n description,\n \"</rdf:RDF>\",\n \"</x:xmpmeta>\",\n '<?xpacket end=\"w\"?>',\n ].join(\"\\n\");\n}\n\nfunction buildDescription(m: Marking): string {\n const attributes: Array<[string, string]> = [\n [\"rdf:about\", \"\"],\n [\"xmlns:Iptc4xmpExt\", \"http://iptc.org/std/Iptc4xmpExt/2008-02-29/\"],\n [\"xmlns:xmp\", \"http://ns.adobe.com/xap/1.0/\"],\n [\"xmlns:dc\", \"http://purl.org/dc/elements/1.1/\"],\n [\"xmlns:witness\", WITNESS_NS],\n [\"witness:marker\", \"1\"],\n [\"witness:kind\", m.kind],\n [\"Iptc4xmpExt:DigitalSourceType\", iptcSourceType(m.sourceType)],\n [\"xmp:CreateDate\", m.createdAt],\n ];\n if (m.generator) {\n attributes.push([\"Iptc4xmpExt:AISystemUsed\", m.generator]);\n attributes.push([\"xmp:CreatorTool\", generatorName(m)]);\n }\n if (m.generatorVersion) attributes.push([\"Iptc4xmpExt:AISystemVersionUsed\", m.generatorVersion]);\n if (m.provider) attributes.push([\"witness:provider\", m.provider]);\n if (m.disclosureUrl) attributes.push([\"witness:disclosureUrl\", m.disclosureUrl]);\n if (m.humanReviewed) attributes.push([\"witness:humanReviewed\", \"True\"]);\n const attrs = attributes.map(([name, value]) => `\\n ${name}=\"${escapeXml(value)}\"`).join(\"\");\n const description = m.description\n ? `\\n <dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">${escapeXml(m.description)}</rdf:li></rdf:Alt></dc:description>\\n`\n : \"\";\n return description\n ? `<rdf:Description${attrs}>${description}</rdf:Description>`\n : `<rdf:Description${attrs}/>`;\n}\n\n/** Reads a simple property in attribute or element form. @internal */\nexport function xmpProperty(xmp: string, name: string): string | undefined {\n const escaped = name.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const attribute = new RegExp(`${escaped}=\"([^\"]*)\"`).exec(xmp);\n if (attribute?.[1] !== undefined) return unescapeXml(attribute[1]);\n const element = new RegExp(\n `<${escaped}(?:\\\\s+rdf:resource=\"([^\"]*)\")?\\\\s*(?:/>|>([\\\\s\\\\S]*?)</${escaped}>)`,\n ).exec(xmp);\n if (!element) return undefined;\n if (element[1] !== undefined) return unescapeXml(element[1]);\n const inner = element[2] ?? \"\";\n const li = /<rdf:li[^>]*>([\\s\\S]*?)<\\/rdf:li>/.exec(inner);\n const value = (li ? li[1] : inner)?.trim();\n return value ? unescapeXml(value) : undefined;\n}\n\n// ---------------------------------------------------------------------------- PNG\n\nfunction writePng(bytes: Uint8Array, xmp: string): Uint8Array {\n const chunks = pngChunks(bytes).filter((chunk) => !isPngXmp(bytes, chunk));\n const itxt = pngChunk(\n \"iTXt\",\n concat(latin1(\"XML:com.adobe.xmp\"), new Uint8Array([0, 0, 0, 0, 0]), utf8(xmp)),\n );\n const parts: Uint8Array[] = [bytes.subarray(0, 8)];\n for (const chunk of chunks) {\n parts.push(bytes.subarray(chunk.offset, chunk.end));\n if (chunk.type === \"IHDR\") parts.push(itxt);\n }\n return concat(...parts);\n}\n\ninterface PngChunk {\n type: string;\n offset: number;\n dataStart: number;\n dataEnd: number;\n end: number;\n}\n\nfunction pngChunks(bytes: Uint8Array): PngChunk[] {\n const chunks: PngChunk[] = [];\n let offset = 8;\n while (offset + 12 <= bytes.length) {\n const length = readU32BE(bytes, offset);\n const type = ascii(bytes, offset + 4, 4);\n const dataStart = offset + 8;\n const dataEnd = dataStart + length;\n const end = dataEnd + 4;\n if (end > bytes.length) throw new Error(\"Witness: truncated PNG chunk\");\n chunks.push({ type, offset, dataStart, dataEnd, end });\n offset = end;\n if (type === \"IEND\") break;\n }\n return chunks;\n}\n\n/** XMP lives in iTXt per the XMP spec; libvips and some other tools write zTXt instead. */\nfunction isPngXmp(bytes: Uint8Array, chunk: PngChunk): boolean {\n return (\n (chunk.type === \"iTXt\" || chunk.type === \"zTXt\") &&\n ascii(bytes, chunk.dataStart, 18) === \"XML:com.adobe.xmp\\0\"\n );\n}\n\nfunction readPngXmp(bytes: Uint8Array): string | null {\n for (const chunk of pngChunks(bytes)) {\n if (!isPngXmp(bytes, chunk)) continue;\n let p = chunk.dataStart + 18;\n let compressed: boolean;\n if (chunk.type === \"zTXt\") {\n compressed = true;\n p += 1; // compression method\n } else {\n compressed = bytes[p] === 1;\n p += 2;\n while (p < chunk.dataEnd && bytes[p] !== 0) p++; // language tag\n p++;\n while (p < chunk.dataEnd && bytes[p] !== 0) p++; // translated keyword\n p++;\n }\n const data = bytes.subarray(p, chunk.dataEnd);\n try {\n return new TextDecoder().decode(compressed ? inflateZlib(data) : data);\n } catch {\n return null;\n }\n }\n return null;\n}\n\nfunction pngChunk(type: string, data: Uint8Array): Uint8Array {\n const out = new Uint8Array(12 + data.length);\n writeU32BE(out, 0, data.length);\n out.set(latin1(type), 4);\n out.set(data, 8);\n writeU32BE(out, 8 + data.length, crc32(out.subarray(4, 8 + data.length)));\n return out;\n}\n\n// ---------------------------------------------------------------------------- JPEG\n\ninterface JpegSegment {\n marker: number;\n offset: number;\n dataStart: number;\n end: number;\n}\n\nfunction jpegSegments(bytes: Uint8Array): { segments: JpegSegment[]; scanStart: number } {\n const segments: JpegSegment[] = [];\n let offset = 2;\n while (offset + 4 <= bytes.length) {\n if (bytes[offset] !== 0xff) throw new Error(\"Witness: invalid JPEG marker\");\n let markerOffset = offset;\n while (bytes[markerOffset + 1] === 0xff) markerOffset++; // fill bytes\n const marker = bytes[markerOffset + 1] ?? 0;\n if (marker === 0xda || marker === 0xd9) return { segments, scanStart: offset };\n const length = readU16BE(bytes, markerOffset + 2);\n const end = markerOffset + 2 + length;\n if (end > bytes.length) throw new Error(\"Witness: truncated JPEG segment\");\n segments.push({ marker, offset, dataStart: markerOffset + 4, end });\n offset = end;\n }\n return { segments, scanStart: offset };\n}\n\nfunction isJpegXmp(bytes: Uint8Array, segment: JpegSegment): boolean {\n return segment.marker === 0xe1 && ascii(bytes, segment.dataStart, XMP_NS.length) === XMP_NS;\n}\n\nfunction writeJpeg(bytes: Uint8Array, xmp: string): Uint8Array {\n const { segments, scanStart } = jpegSegments(bytes);\n const payload = concat(latin1(XMP_NS), utf8(xmp));\n if (payload.length + 2 > 0xffff) throw new Error(\"Witness: XMP packet too large for JPEG\");\n const app1 = new Uint8Array(4 + payload.length);\n app1[0] = 0xff;\n app1[1] = 0xe1;\n app1[2] = ((payload.length + 2) >> 8) & 0xff;\n app1[3] = (payload.length + 2) & 0xff;\n app1.set(payload, 4);\n\n const kept = segments.filter((segment) => !isJpegXmp(bytes, segment));\n // Keep JFIF (APP0) and Exif (APP1) first, as readers expect them there.\n let insertAt = 0;\n while (insertAt < kept.length) {\n const segment = kept[insertAt];\n if (!segment) break;\n const isJfif = segment.marker === 0xe0;\n const isExif = segment.marker === 0xe1 && ascii(bytes, segment.dataStart, 4) === \"Exif\";\n if (!isJfif && !isExif) break;\n insertAt++;\n }\n const parts: Uint8Array[] = [bytes.subarray(0, 2)];\n kept.forEach((segment, index) => {\n if (index === insertAt) parts.push(app1);\n parts.push(bytes.subarray(segment.offset, segment.end));\n });\n if (insertAt >= kept.length) parts.push(app1);\n parts.push(bytes.subarray(scanStart));\n return concat(...parts);\n}\n\nfunction readJpegXmp(bytes: Uint8Array): string | null {\n for (const segment of jpegSegments(bytes).segments) {\n if (isJpegXmp(bytes, segment)) {\n return new TextDecoder().decode(\n bytes.subarray(segment.dataStart + XMP_NS.length, segment.end),\n );\n }\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------- WebP\n\ninterface RiffChunk {\n fourcc: string;\n offset: number;\n dataStart: number;\n size: number;\n end: number;\n}\n\nfunction webpChunks(bytes: Uint8Array): RiffChunk[] {\n const chunks: RiffChunk[] = [];\n const riffEnd = Math.min(bytes.length, 8 + readU32LE(bytes, 4));\n let offset = 12;\n while (offset + 8 <= riffEnd) {\n const fourcc = ascii(bytes, offset, 4);\n const size = readU32LE(bytes, offset + 4);\n const dataStart = offset + 8;\n const end = dataStart + size + (size % 2);\n if (dataStart + size > bytes.length) throw new Error(\"Witness: truncated WebP chunk\");\n chunks.push({ fourcc, offset, dataStart, size, end: Math.min(end, bytes.length) });\n offset = end;\n }\n return chunks;\n}\n\nfunction writeWebp(bytes: Uint8Array, xmp: string): Uint8Array {\n const chunks = webpChunks(bytes).filter((chunk) => chunk.fourcc !== \"XMP \");\n const first = chunks[0];\n if (!first) throw new Error(\"Witness: empty WebP file\");\n const parts: Uint8Array[] = [];\n if (first.fourcc === \"VP8X\") {\n const vp8x = bytes.slice(first.offset, first.end);\n vp8x[8] = (vp8x[8] ?? 0) | 0x04; // XMP flag\n parts.push(vp8x);\n for (const chunk of chunks.slice(1)) parts.push(bytes.subarray(chunk.offset, chunk.end));\n } else {\n const { width, height, alpha } = webpCanvas(bytes, first);\n const data = new Uint8Array(10);\n data[0] = 0x04 | (alpha ? 0x10 : 0);\n writeU24LE(data, 4, width - 1);\n writeU24LE(data, 7, height - 1);\n parts.push(riffChunk(\"VP8X\", data));\n for (const chunk of chunks) parts.push(bytes.subarray(chunk.offset, chunk.end));\n }\n parts.push(riffChunk(\"XMP \", utf8(xmp)));\n const body = concat(...parts);\n const out = new Uint8Array(12 + body.length);\n out.set(latin1(\"RIFF\"), 0);\n writeU32LE(out, 4, 4 + body.length);\n out.set(latin1(\"WEBP\"), 8);\n out.set(body, 12);\n return out;\n}\n\nfunction webpCanvas(\n bytes: Uint8Array,\n chunk: RiffChunk,\n): { width: number; height: number; alpha: boolean } {\n const d = chunk.dataStart;\n if (chunk.fourcc === \"VP8 \") {\n if (bytes[d + 3] !== 0x9d || bytes[d + 4] !== 0x01 || bytes[d + 5] !== 0x2a) {\n throw new Error(\"Witness: invalid VP8 frame\");\n }\n return {\n width: readU16LE(bytes, d + 6) & 0x3fff,\n height: readU16LE(bytes, d + 8) & 0x3fff,\n alpha: false,\n };\n }\n if (chunk.fourcc === \"VP8L\") {\n if (bytes[d] !== 0x2f) throw new Error(\"Witness: invalid VP8L frame\");\n const bits = readU32LE(bytes, d + 1);\n return {\n width: (bits & 0x3fff) + 1,\n height: ((bits >>> 14) & 0x3fff) + 1,\n alpha: ((bits >>> 28) & 1) === 1,\n };\n }\n throw new Error(`Witness: unexpected WebP chunk ${chunk.fourcc}`);\n}\n\nfunction readWebpXmp(bytes: Uint8Array): string | null {\n const chunk = webpChunks(bytes).find((c) => c.fourcc === \"XMP \");\n return chunk\n ? new TextDecoder().decode(bytes.subarray(chunk.dataStart, chunk.dataStart + chunk.size))\n : null;\n}\n\nfunction riffChunk(fourcc: string, data: Uint8Array): Uint8Array {\n const out = new Uint8Array(8 + data.length + (data.length % 2));\n out.set(latin1(fourcc), 0);\n writeU32LE(out, 4, data.length);\n out.set(data, 8);\n return out;\n}\n\n// ---------------------------------------------------------------------------- shared\n\nfunction readXmp(bytes: Uint8Array, format: ImageFormat): string | null {\n if (format === \"png\") return readPngXmp(bytes);\n if (format === \"jpeg\") return readJpegXmp(bytes);\n return readWebpXmp(bytes);\n}\n\n/** C2PA manifests live in caBX (PNG), APP11 JUMBF (JPEG) or C2PA (WebP) chunks. */\nfunction hasC2pa(bytes: Uint8Array, format: ImageFormat): boolean {\n if (format === \"png\") return pngChunks(bytes).some((chunk) => chunk.type === \"caBX\");\n if (format === \"webp\") return webpChunks(bytes).some((chunk) => chunk.fourcc === \"C2PA\");\n return jpegSegments(bytes).segments.some(\n (segment) =>\n segment.marker === 0xeb &&\n ascii(bytes, segment.dataStart, Math.min(64, segment.end - segment.dataStart)).includes(\n \"c2pa\",\n ),\n );\n}\n\nfunction ascii(bytes: Uint8Array, offset: number, length: number): string {\n let out = \"\";\n for (let i = offset; i < offset + length && i < bytes.length; i++) {\n out += String.fromCharCode(bytes[i] ?? 0);\n }\n return out;\n}\n\nfunction latin1(text: string): Uint8Array {\n const out = new Uint8Array(text.length);\n for (let i = 0; i < text.length; i++) out[i] = text.charCodeAt(i) & 0xff;\n return out;\n}\n\nfunction utf8(text: string): Uint8Array {\n return new TextEncoder().encode(text);\n}\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n const out = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n return out;\n}\n\nfunction readU16BE(b: Uint8Array, o: number): number {\n return ((b[o] ?? 0) << 8) | (b[o + 1] ?? 0);\n}\nfunction readU16LE(b: Uint8Array, o: number): number {\n return (b[o] ?? 0) | ((b[o + 1] ?? 0) << 8);\n}\nfunction readU32BE(b: Uint8Array, o: number): number {\n return (\n (((b[o] ?? 0) << 24) | ((b[o + 1] ?? 0) << 16) | ((b[o + 2] ?? 0) << 8) | (b[o + 3] ?? 0)) >>> 0\n );\n}\nfunction readU32LE(b: Uint8Array, o: number): number {\n return (\n ((b[o] ?? 0) | ((b[o + 1] ?? 0) << 8) | ((b[o + 2] ?? 0) << 16) | ((b[o + 3] ?? 0) << 24)) >>> 0\n );\n}\nfunction writeU32BE(b: Uint8Array, o: number, v: number): void {\n b[o] = (v >>> 24) & 0xff;\n b[o + 1] = (v >>> 16) & 0xff;\n b[o + 2] = (v >>> 8) & 0xff;\n b[o + 3] = v & 0xff;\n}\nfunction writeU32LE(b: Uint8Array, o: number, v: number): void {\n b[o] = v & 0xff;\n b[o + 1] = (v >>> 8) & 0xff;\n b[o + 2] = (v >>> 16) & 0xff;\n b[o + 3] = (v >>> 24) & 0xff;\n}\nfunction writeU24LE(b: Uint8Array, o: number, v: number): void {\n b[o] = v & 0xff;\n b[o + 1] = (v >>> 8) & 0xff;\n b[o + 2] = (v >>> 16) & 0xff;\n}\n\nlet crcTable: Uint32Array | null = null;\nfunction crc32(data: Uint8Array): number {\n if (!crcTable) {\n crcTable = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n crcTable[n] = c >>> 0;\n }\n }\n let crc = 0xffffffff;\n for (const byte of data) crc = (crcTable[(crc ^ byte) & 0xff] ?? 0) ^ (crc >>> 8);\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction unescapeXml(value: string): string {\n return value\n .replace(/"/g, '\"')\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/'/g, \"'\")\n .replace(/&/g, \"&\");\n}\n","/**\n * An invisible, machine-readable marker for AI-generated text.\n *\n * The payload is written as Unicode variation selectors (U+FE00–U+FE0F and\n * U+E0100–U+E01EF). They are default-ignorable code points: browsers do not render them and\n * screen readers skip them, and they survive copy and paste in most applications. They do\n * not survive sanitisers that strip unusual code points, retyping, or paraphrasing, so treat\n * this as one marking layer next to visible labels and metadata, not as a robust watermark.\n */\n\nconst MAGIC = [0x57, 0x31]; // \"W1\"\nconst MAX_PAYLOAD = 255;\n\nexport interface TextWatermark {\n /** Name of the AI system. */\n generator?: string;\n /** ISO 8601 timestamp. */\n createdAt?: string;\n /** Your own reference, e.g. a message or log id. */\n id?: string;\n}\n\nexport interface ReadTextWatermark extends TextWatermark {\n /** The raw payload as written. */\n raw: string;\n}\n\n/**\n * Appends an invisible watermark to `text`. An existing Witness watermark is replaced. Empty\n * text is returned unchanged.\n */\nexport function watermarkText(text: string, mark: TextWatermark = {}): string {\n if (text.length === 0) return text;\n return stripTextWatermark(text) + watermarkSuffix(mark);\n}\n\n/**\n * Only the invisible characters, for appending to a stream. They attach to whatever character\n * precedes them, so emit them after at least one visible character.\n */\nexport function watermarkSuffix(mark: TextWatermark = {}): string {\n const payload = encodePayload(mark);\n return [...MAGIC, payload.length, ...payload].map(byteToSelector).join(\"\");\n}\n\n/** Reads the first Witness watermark in `text`, or `null`. */\nexport function readTextWatermark(text: string): ReadTextWatermark | null {\n for (const run of selectorRuns(text)) {\n const found = findInRun(run.bytes);\n if (found) {\n const raw = new TextDecoder().decode(new Uint8Array(found.payload));\n return { ...decodePayload(raw), raw };\n }\n }\n return null;\n}\n\n/** True when `text` carries a Witness watermark. */\nexport function hasTextWatermark(text: string): boolean {\n return readTextWatermark(text) !== null;\n}\n\n/**\n * Removes Witness watermarks and leaves all other characters, including the variation\n * selectors that belong to emoji, untouched.\n */\nexport function stripTextWatermark(text: string): string {\n const chars = [...text];\n const remove = new Set<number>();\n for (const run of selectorRuns(text)) {\n let offset = 0;\n while (offset < run.bytes.length) {\n const found = findInRun(run.bytes.slice(offset));\n if (!found) break;\n const start = offset + found.start;\n const end = offset + found.end;\n for (let i = start; i < end; i++) remove.add(run.start + i);\n offset = end;\n }\n }\n if (remove.size === 0) return text;\n return chars.filter((_, index) => !remove.has(index)).join(\"\");\n}\n\nfunction encodePayload(mark: TextWatermark): number[] {\n const fields: string[] = [];\n if (mark.generator) fields.push(`g=${encodeURIComponent(mark.generator)}`);\n if (mark.createdAt) fields.push(`t=${encodeURIComponent(mark.createdAt)}`);\n if (mark.id) fields.push(`i=${encodeURIComponent(mark.id)}`);\n let bytes = [...new TextEncoder().encode(fields.join(\";\"))];\n if (bytes.length > MAX_PAYLOAD) {\n // Keep whole fields only, so a truncated payload still parses.\n while (fields.length > 0 && bytes.length > MAX_PAYLOAD) {\n fields.pop();\n bytes = [...new TextEncoder().encode(fields.join(\";\"))];\n }\n }\n return bytes;\n}\n\nfunction decodePayload(raw: string): TextWatermark {\n const result: TextWatermark = {};\n for (const field of raw.split(\";\")) {\n const index = field.indexOf(\"=\");\n if (index < 1) continue;\n const key = field.slice(0, index);\n let value: string;\n try {\n value = decodeURIComponent(field.slice(index + 1));\n } catch {\n continue;\n }\n if (key === \"g\") result.generator = value;\n else if (key === \"t\") result.createdAt = value;\n else if (key === \"i\") result.id = value;\n }\n return result;\n}\n\nfunction byteToSelector(byte: number): string {\n return byte < 16\n ? String.fromCodePoint(0xfe00 + byte)\n : String.fromCodePoint(0xe0100 + (byte - 16));\n}\n\nfunction selectorToByte(codePoint: number): number | null {\n if (codePoint >= 0xfe00 && codePoint <= 0xfe0f) return codePoint - 0xfe00;\n if (codePoint >= 0xe0100 && codePoint <= 0xe01ef) return codePoint - 0xe0100 + 16;\n return null;\n}\n\n/** Consecutive variation selectors, with their index in code points. */\nfunction selectorRuns(text: string): Array<{ start: number; bytes: number[] }> {\n const runs: Array<{ start: number; bytes: number[] }> = [];\n let current: { start: number; bytes: number[] } | null = null;\n let index = 0;\n for (const char of text) {\n const byte = selectorToByte(char.codePointAt(0) ?? 0);\n if (byte === null) {\n current = null;\n } else {\n if (!current) {\n current = { start: index, bytes: [] };\n runs.push(current);\n }\n current.bytes.push(byte);\n }\n index++;\n }\n return runs;\n}\n\n/** Finds MAGIC, length and payload inside a run. Positions are indexes into `bytes`. */\nfunction findInRun(bytes: number[]): { start: number; end: number; payload: number[] } | null {\n for (let i = 0; i + MAGIC.length < bytes.length; i++) {\n if (bytes[i] !== MAGIC[0] || bytes[i + 1] !== MAGIC[1]) continue;\n const length = bytes[i + 2];\n if (length === undefined) continue;\n const start = i + 3;\n const end = start + length;\n if (end > bytes.length) continue;\n return { start: i, end, payload: bytes.slice(start, end) };\n }\n return null;\n}\n"],"mappings":"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","names":[]}
|