npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@governancer-foundation/art50-disclosure-sdk

v0.3.0

Published

The transparency duties of Article 50 of the EU AI Act as code: work out which paragraphs bind a system and why, render the disclosure notices in six languages, and emit a machine-readable record of both.

Readme

@governancer-foundation/art50-disclosure-sdk

CI OpenSSF Scorecard REUSE compliant License: Apache-2.0 npm version

Which Article 50 transparency duties bind your AI system, why, and what to show the user — as a function, not a PDF.

Article 50 of Regulation (EU) 2024/1689 — the EU AI Act — has applied since 2 August 2026. It is short, it is not limited to high-risk systems, and it is easy to get subtly wrong: its exemptions do not line up paragraph to paragraph, and one of them is narrower than it first reads.

This package takes a description of what your system does and returns which paragraphs bind you, on what reasoning, what to display, where, in which language, what a provenance tool should embed — and a machine-readable record of the whole assessment.

Quick start

npm install @governancer-foundation/art50-disclosure-sdk
import { planDisclosures } from "@governancer-foundation/art50-disclosure-sdk";

const plan = planDisclosures(
  { systemName: "support-bot", interactsWithPersons: true },
  { locale: "de" },
);

plan.notices;
// [{ paragraph: "50(1)", placement: "first-interaction",
//    text: "Sie interagieren mit einem KI-System." }]

plan.report.obligations.find((o) => o.paragraph === "50(2)");
// { applies: false,
//   reason: "The system does not generate synthetic audio, image, video or text.", … }

What it does

Five functions, in the order you need them.

resolveObligations(profile) — which of 50(1) to 50(4) bind this system, who bears each one (provider or deployer), and the reasoning behind every verdict, including the negative ones. A paragraph that does not apply is reported with the reason it does not, because that is the part you have to defend later.

planDisclosures(profile, options) — the notices to show, each tagged with where it belongs: before the first interaction, restated periodically, attached to the content, or embedded machine-readably. Wording ships in English, German, French, Spanish, Italian and Swedish.

buildMarkingClaim(profile, options) — the two values a provenance manifest needs to satisfy 50(2): the IPTC digital-source-type term describing how the media came about, and the corresponding action. Both drop straight into a C2PA manifest. Returns nothing when the duty does not bind, because marking output you have no duty to mark asserts something about your own system that may not be true.

buildMarkingClaim({ generatesSyntheticContent: ["image"] });
// { digitalSourceType:
//     "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia",
//   action: "c2pa.created",
//   modalities: ["image"], applicableFrom: "2026-08-02", … }

The Regulation names no standard — it is technology-neutral — but interoperability is one of the four adjectives it uses, so the package speaks the published vocabulary rather than a private one. It does not apply the mark: embedding and signing is a cryptographic and media-format problem, and a package that pretended to discharge the duty by returning an object would be worse than one that declines to.

buildAttestation(profile, options) — the same assessment as an in-toto statement, so it can be signed, transported and verified by the tooling that already carries build provenance and component inventories. The record's shape belongs to a separate, axis-agnostic package, and this package's own suite checks every branch it can produce against that package's validator. That ecosystem answers what a thing is made of and who built it; nothing in it answers which regulatory requirements it meets, which is the gap this fills — as a predicate, not as a new envelope. The package emits the payload; signing is DSSE's job and is not done here.

A duty that binds is recorded as open, never as met: identifying an obligation is not discharging it. Every record declares what the tool could not know.

buildManifest(profile, options) — the assessment as data: the profile it rests on, every verdict with its reasoning, the notices undertaken, and the date each duty binds. Deterministic for a given input, so it can be committed and diffed. The timestamp is supplied by the caller, not read from the clock — a record that stamps itself is not reproducible.

The lines worth getting right

Three places where a careless reading gives the wrong answer, each held by a test:

  • The law-enforcement exemption lifts the interaction duty — except for a system the public uses to report a criminal offence, which owes the disclosure anyway.
  • Editorial responsibility over published text answers the text branch of 50(4) and leaves the deepfake branch standing. Two triggers, one exemption between them.
  • An artistic, creative, satirical or fictional work does not escape the duty; it discharges it in a form that does not hamper the display of the work.

Dates

| | Applies from | |---|---| | 50(1), 50(3), 50(4) | 2026-08-02 | | 50(2) marking, system placed on the market before that date | 2026-12-02 |

Content generated before the application date is not labelled retroactively.

What this is not

It is not legal advice, and it is not a safe harbour. It encodes a reading of the Regulation, and every verdict carries the paragraph and reasoning behind it precisely so the reading can be checked rather than trusted. The disclosure wording is a defensible default, not an approved text — a deployer serving a given market should have counsel read what it ships.

It does not apply the machine-readable marking that 50(2) requires. That is a technical measure — a watermark, a signed provenance manifest — and the package says so where the duty arises rather than pretending to discharge it.

Install and use

npm install @governancer-foundation/art50-disclosure-sdk

Requires Node 20 or later. The package is ESM-only and ships types. It has one runtime dependency, @governancer-foundation/conformance-attestation, which owns the shape of the attestation record — depending on it rather than copying the types is what makes the claim that two axes share one format checkable instead of asserted.

import {
  resolveObligations,
  planDisclosures,
  firstInteractionNotice,
  chatPrefix,
  buildMarkingClaim,
  buildManifest,
  serialiseManifest,
} from "@governancer-foundation/art50-disclosure-sdk";

// The one line to show before a conversation starts, or undefined.
firstInteractionNotice({ interactsWithPersons: true });
// "You are interacting with an AI system."

// A short label where a banner will not fit.
chatPrefix("fr"); // "[IA]"

// File the assessment as evidence.
const manifest = buildManifest(
  { systemName: "clip-generator", producesDeepfakes: true, artisticWork: true },
  { generatedAt: new Date().toISOString(), sdkVersion: "0.1.0" },
);
serialiseManifest(manifest); // indented JSON, trailing newline, ready to commit

A worked example

examples/end-to-end.mjs takes one product description all the way through — obligations, notices, marking values, and a record validated by the package that owns its shape — and prints each step. It runs in continuous integration, so it cannot drift into describing an interface that no longer exists.

node examples/end-to-end.mjs

Tests

npm test          # vitest, one pass
npm run typecheck # source and specs

The suite covers each paragraph on both sides of every exemption line, the notice set each profile produces, all six locales, and the determinism of the record.

Status

v0.2 — the API surface above is what the package commits to; additions are expected, breaking changes are not, before v1.0. See ROADMAP.md.

License

Apache-2.0 (see LICENSE and NOTICE).


Maintained by Alexander Brichkin (Agonist Development AB) under the governancer-foundation open-source commons.