{
  "schemaVersion": 1,
  "package": "typeset.us",
  "version": "4.4.0",
  "status": "public-release",
  "mountOwnership": { "scope": "same target, same engine instance", "policy": "first claim owns; waiting controllers take over after release", "diagnostic": "controller.stats.overlappingTargets", "integration": "use disjoint text roots and one engine copy" },
  "inlineNoWrap": { "supported": "ordinary white-space:nowrap inline phrases within wrapping rich text", "preserves": ["protected break boundaries", "styled descendants", "source and author elements"], "overflow": "native:no-candidate with unbreakable-run constraint" },
  "nameGrouping": { "language": "declared English", "scope": "capitalized names followed by street or institution designators", "policy": "bounded soft preference; substantial final location words allowed in titles", "limit": "not a semantic parser or arbitrary brand recognition" },
  "keep": { "option": "keep: string[] (DOM, mount and both React adapters)", "matching": "case-insensitive; NBSP and runs of spaces count as one space; punctuation around the phrase ignored", "body": "never split where the phrase fits the measure; a phrase the browser splits may earn one extra line, except with density: compact; a phrase longer than the measure is split as few times as possible", "titles": "kept within the minimum line count", "retention": "a native layout is retained only if it splits no kept phrase" },
  "defaults": { "lineBreaks": "unicode", "density": "compact with one-line default body allowance for stranded sentence/clause openers; explicit compact/maxLines respected", "spacing": true, "tracking": true, "contour": "finished", "smartQuotes": false, "opticalHanging": false, "copy": true, "coverage": "core", "headings": true, "listStyling": "explicit" },
  "copy": { "option": "copy (data-typeset-copy on the loaders, the copy prop on the React adapters)", "default": true, "on": "a document copy handler puts composed text on the clipboard as its source, without generated line breaks or engine markers, and yields to copy handlers the page registered first", "off": "the browser copies the element itself, with a line break at every composed line end; the handler is installed only when some composed element has copy on" },
  "coverage": { "option": "coverage (data-typeset-coverage on the loaders, the coverage prop on the React adapters)", "default": "core", "extended": ["text declared in any Latin-script language, with neutral line-end preferences", "a descendant declared in another Latin-script language, set with the block's preferences", "time, dfn, kbd and ins", "visually hidden text (the sr-only pattern) and aria-hidden elements with no width, which take no room and never hold a break", "sup, sub and vertical-align: super or sub, measured in place"], "notExtended": ["::after link icons", "a visible aria-hidden icon", "br, img, svg, q and bdi"], "always": "language tags such as en_US and english, and up to three Greek or Cyrillic letters in a row in Latin text (5 μg, α-synuclein), compose under both values", "core": "the default: leaves native everything 4.3.1 left native; extended is opt-in" },
  "headings": { "option": "headings (data-typeset-headings on the loaders)", "default": true, "off": "mount(), typesetAll() and the loaders leave h1 to h6, role=heading and anything inside them untouched, with no outcome written; typeset() composes the element it is given", "why": "a wrapped composed heading has a line break inside it, which iOS VoiceOver may read as two items; not yet checked by ear" },
  "runBudget": { "outcome": "native:run-budget", "limit": "more than 500 code points between two line-break opportunities", "when": "before anything is measured", "why": "WebKit's range geometry costs the length of the line a range is on, so measuring such a run costs its square (about 37 s for 11,000 closing quotes in 4.3)" },
  "contentSecurityPolicy": { "styleSrc": "no 'unsafe-inline' needed: engine styles are written and restored through the CSSOM, never the style attribute", "scriptSrc": "no 'unsafe-eval' and no inline script; allow the origin that serves the bundle", "trustedTypes": "compatible with require-trusted-types-for 'script' and trusted-types 'none'; no HTML sinks", "injectedStyleElements": false, "evidence": "scripts/v4/verify-strict-csp.mjs" },
  "contour": { "basis": "predicted finished widths using the rendering space policy", "beamCompletedPool": 200, "shortParagraphs": "budgeted exhaustive search", "evidence": "result.search", "comparison": "contour: natural" },
  "spacing": { "scope": "composed, left-aligned body text", "level": "full V3 neighbor/median finish", "deltaBounds": "-20 percent to +33 percent of each measured natural space; authored spacing retained", "preserves": ["chosen breaks", "final line", "author elements", "source text"], "fallback": "retain unspaced composition and report native:spacing-verification" },
  "languages": ["en", "fr", "de", "es"],
  "tracking": { "scope": "default Unicode composed left-aligned body text, after verified word spacing", "maxDeltaEm": 0.01, "maxRuns": 256, "preserves": ["chosen breaks", "final line", "author elements", "source text", "authored spacing"], "excluded": ["code/kbd/samp", "joining scripts", "unresolved relative spacing", "legacy plain renderer"], "fallback": "roll back tracking only; report native:tracking-verification", "disable": "tracking: false, or data-typeset-tracking=false; spacing: false disables both finishes" },
  "scheduling": { "discovery": "changed subtrees; no whole-document rescan for unrelated mutations", "priority": "initially near-viewport targets", "batchTargetMs": 8, "hardDeadline": false, "recomposes": ["text", "font", "width", "context"], "limit": "one composition, initial discovery and browser layout may exceed the batch target" },
  "untaggedLanguage": "neutral Latin-script preferences; no language inference",
  "languageTags": "an underscore reads as a hyphen (en_US is en-US) and a language's name as its code (english, Deutsch, francais, español, italiano, nederlands, português); 4.3 left such blocks native:language",
  "otherLatinLanguages": "native:language with coverage: core (the default); neutral preferences with coverage: extended",
  "react": { "peerRange": "^18.2.0 || ^19.0.0", "peers": ["react", "react-dom"], "testedVersion": ["18.2.0", "18.3.1", "19.0.8", "19.1.9", "19.2.8", "19.3.0"], "evidence": "scripts/v4/verify-react-matrix.mjs: install, server render, hydration and composition in Chromium, WebKit and Firefox; strict types against @types/react 18.3, 19.0 and latest", "entry": "typeset.us/react", "formats": ["ESM (dist/react.js)", "CommonJS (dist/react.cjs)"], "as": ["p", "h1", "h2", "h3", "h4", "h5", "h6", "span", "div", "li", "blockquote", "figcaption", "dd", "dt", "td", "th", "caption", "label", "legend", "summary"], "ref": "the host element", "onResult": "each composition's Result, after the commit", "priority": { "auto": "blocks React renders in the browser compose before first paint when on screen (on-screen work beyond about 120 ms in one frame, the one-time setup not counted, continues in the next frame), offscreen blocks in idle time; server-rendered HTML paints natively and composes after hydration", "sync": "compose in the React commit" }, "observers": "one registry per document shared by every adapter", "customComponentChildren": "native:react-component (any component child, such as next/link's Link; a development warning says so)" },
  "node": ">=18.3",
  "nodeScope": "typeset-audit CLI only; the library runs in browsers and the package declares no engines field",
  "browserRequirements": ["Intl.Segmenter", "ResizeObserver", "MutationObserver", "Range geometry", "a layout engine"],
  "browserOptional": ["FontFaceSet"],
  "environment": { "outcome": "native:environment", "when": "jsdom, happy-dom, or an engine without a required API", "behaviour": "every entry imports; text stays as authored; typeset() and both adapters report the outcome; mount() returns an inert controller; nothing throws" },
  "liveRegions": { "outcome": "native:live-region", "regions": ["aria-live other than off (empty counts as absent)", "role status, alert, log, marquee or timer", "output"], "exception": "aria-live=off", "scope": "text inside a live region, and an element that contains one, through open shadow roots (slotted text, a component with a live slot) as they are when the text is composed; a role set through ElementInternals or in a closed shadow root is not seen: use data-no-typeset", "policy": "never measured, composed or rewritten; mount() and the loaders release an owned element whose region turns live, or that moves into or gains a live region, in the same mutation callback when the change is in the light DOM; a shadow tree that becomes live later (a component defined after the text composed, a role set inside its shadow root) is seen at the next resize or font load, which releases the text inside the region once: use data-no-typeset, or hide undefined components with :not(:defined)" },
  "lifecycle": { "recomposes": ["text edits, including framework writes to split Text nodes", "fonts, including stylesheet-requested fonts in WebKit", "width", "text-spacing overrides and browser font-size settings", "CSSOM rule changes", "font, spacing and line-height transitions and animations"], "ancestorRestyles": "recheck a computed layout key; compose only if it changed", "hidden": "compositions are kept while hidden and paint composed when shown", "resize": "native wrapping (data-ts-stale) while a block's composed lines no longer fit; recompose 100 ms after the size holds, or, with mount() and the loaders, once a block more than a viewport height offscreen comes that near (released to native meanwhile)", "print": "native wrapping at the paper width; composition pauses", "translation": "native:translated; breaks removed by moving Text nodes; TypesetRichText freezes", "iframes": "mount() works on same-origin iframe documents and elements", "scheduling": "near-viewport work in the next task, offscreen work in idle time or when near" },
  "cssHooks": { "--ts-break-display": "display of every generated break; none in print, inline on screen", "data-ts-stale": "set on a block showing native wrapping until it is recomposed", "stylesheet": "dist/styles.css; the engine also installs the rules as a constructable stylesheet", "markers": "the declarations every spacing and hanging marker shares are !important in the typeset-markers cascade layer, and tracking wrappers' all: unset is a stylesheet rule that page !important rules still override; each keeps only its own margin-left or letter- and word-spacing inline, and all of them inline where constructable stylesheets are missing" },
  "errors": { "typeset": "TypeError for a target that is not an element", "mount": "TypeError for a root that is not a Document, Element or selector string", "options": "development builds warn once per invalid value, unknown option or non-string selector; values keep their 4.2 behaviour; production bundles omit the checks" },
  "whenSettled": { "entries": ["typeset.us", "typeset.us/react", "window.Typeset"], "signature": "whenSettled(options?: { timeout?: number }): Promise<{ settled: boolean }>", "resolves": "once every mount() controller and React adapter host has its outcome, no composition work is queued or timed, no web font is loading and a loader waiting for hydration has composed, at two checks 50 ms apart", "timeout": "10000 ms by default; { settled: false } if work is still queued then", "environment": "resolves { settled: true } at once under jsdom and happy-dom", "copies": "engine copies on one page (CommonJS and ESM entries, a script-tag loader beside an npm import) report to one shared list" },
  "hydration": { "loaders": ["auto (dist/auto.js, go@<version>.js)", "opt-in (dist/go.js)"], "markers": ["#__next", "#__NEXT_DATA__", "self.__next_f", "#___gatsby", "[data-framer-hydrate-v2]", "astro-island", "[data-server-rendered]", "a React root (__reactContainer$) on the document, the body or a child of the body"], "waitsFor": ["React: a root, and each server-rendered target (or an ancestor below the body) hydrated", "Astro: no astro-island[ssr] left, except client:visible and client:media islands", "Vue 2: no [data-server-rendered] left", "the load event, only under data-typeset-defer=\"hydration\" with no React root yet", "one idle callback (a 50 ms timer without requestIdleCallback)"], "cap": "10 s from the loader's start (DOMContentLoaded), the load event included", "fonts": "mount() then waits for document.fonts.ready, which Chromium and WebKit resolve only at the load event", "force": "data-typeset-defer=\"hydration\" waits without a marker (for React, only when a root exists by the load event)", "off": "data-typeset-defer=\"none\": compose at DOMContentLoaded, as 4.3 did", "unmarked": "compose at DOMContentLoaded, as 4.3 did" },
  "entryPoints": { "cdnDefault": "bare jsDelivr and unpkg package URLs serve dist/auto.js, the automatic loader (4.3 served dist/typeset.global.js, which composes nothing by itself)", "optIn": "typeset.us/opt-in (dist/go.js): composes only [data-typeset] or data-typeset-selector", "deprecated": { "typeset.us/go": "the same file as typeset.us/opt-in; kept as an alias until at least 5.0" } },
  "unsupported": ["automatic hyphenation", "soft hyphens", "a descendant in a different language (native:mixed-language; with coverage: extended, only one in a language written in another script)", "declared languages other than English, French, German and Spanish (native:language; with coverage: extended, only languages written in scripts other than Latin)", "RTL and vertical text", "justified text, and a text-align-last that differs from text-align (native:justify)", "editable text", "inline widgets", "unsupported inline box decoration", "scale, rotation, perspective and nonzero Z transforms"],
  "inlineCode": { "supported": "normal whitespace, overflow-wrap:break-word and nonnegative sliced padding/borders/margins measured in context", "tracking": false },
  "quotes": { "mode": "explicit English", "values": { "en": "declared English and untagged text", "en-declared": "declared English only" }, "straight": ["a double quote with white space or the text's edge on both sides", "a double quote with no open quotation to close (width=\"100\")", "primes after a number (5'10\", 27\")"], "lengthPreserving": true, "dashesAndEllipses": "not changed", "richReactRequires": "lang=en on the adapter", "reactDeclared": "en-declared needs lang on either adapter" },
  "opticalHanging": { "mode": "explicit", "scope": "full measured leading punctuation and raster-measured optical capitals on composed lines or fitting single lines", "capitalMaxEm": 0.08, "clipping": "full glyph must fit available clip/padding/scrollport; partial line coverage reported", "unsupported": ["centered or justified text", "insufficient clip room", "unknown clip paths/masks", "scale/rotation/perspective transforms", "author text indentation", "custom font-feature/variation settings unsupported by canvas, including onum"] },
  "lists": { "entry": "styleProseLists", "stylesheet": "typeset.us/styles.css", "scope": "explicit unordered prose lists", "marker": "native ::marker", "excluded": ["navigation", "ordered lists", "custom markerless lists", "flex and grid lists"] },
  "outcomes": { "reference": "OUTCOMES.md", "runtime": "OUTCOMES", "types": ["Outcome", "FeatureStatus"], "groups": ["composed", "nothing to improve", "unsupported content", "couldn't improve safely", "not processed"], "nativeMeans": "left as the browser set it, with the reason; not an error" },
  "verification": { "cli": "typeset-audit", "api": "auditJSON", "schemaVersion": 1, "passMeans": "nonempty scope, no hard errors, no unprocessed targets", "reviewItems": "never fail the gate; text clipped on purpose (overflow hidden or clip with text-overflow: ellipsis or -webkit-line-clamp) is the review item clipped, not an overflow error", "doesNotMean": "aesthetic perfection, all targets composed, or source preservation without a before capture" },
  "telemetry": "none",
  "websiteLoader": { "selector": "automatic prose and headings; data-typeset-selector overrides", "smartQuotes": "en-declared (data-typeset-smart-quotes=\"en\" also curls untagged text)", "opticalHanging": true, "npmGoSelector": "[data-typeset]", "npmAutoEntry": "typeset.us/auto (dist/auto.js), byte-identical to https://typeset.us/go@<version>.js", "noTargets": "each loader logs one console.info when no element matches", "pinnedPaths": ["go@<version>.js", "typeset@<version>.min.js", "typeset@<version>.esm.js"], "movingAliases": { "go@4.js": "latest 4.x", "go.js": "latest 4.x only; never moves to 5.0" }, "cdnDefault": "bare jsDelivr and unpkg package URLs serve dist/auto.js, the automatic loader (4.3 served dist/typeset.global.js)" },
  "outstandingAcceptance": ["physical iOS and Android", "spoken VoiceOver and NVDA", "non-macOS and native-application rich clipboard", "representative-device performance"],
  "releaseApproval": "owner-approved with documented testing limits"
}
