@certrev/cert-block 0.5.5 → 1.0.1

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.
Files changed (190) hide show
  1. package/CHANGELOG.md +189 -25
  2. package/LICENSE +21 -0
  3. package/README.md +415 -54
  4. package/dist/builder/cert-chrome-data.d.ts +26 -8
  5. package/dist/builder/cert-chrome-data.d.ts.map +1 -1
  6. package/dist/builder/cert-chrome-data.js +5 -5
  7. package/dist/builder/cert-chrome-data.js.map +1 -1
  8. package/dist/builder/cert-review-card.d.ts +35 -5
  9. package/dist/builder/cert-review-card.d.ts.map +1 -1
  10. package/dist/builder/cert-review-card.js +117 -34
  11. package/dist/builder/cert-review-card.js.map +1 -1
  12. package/dist/builder/index.d.ts +33 -16
  13. package/dist/builder/index.d.ts.map +1 -1
  14. package/dist/builder/index.js +33 -16
  15. package/dist/builder/index.js.map +1 -1
  16. package/dist/components/CertBadge.d.ts +2 -2
  17. package/dist/components/CertBadge.d.ts.map +1 -1
  18. package/dist/components/CertBadge.js +11 -5
  19. package/dist/components/CertBadge.js.map +1 -1
  20. package/dist/components/CertJsonLd.d.ts.map +1 -1
  21. package/dist/components/CertJsonLd.js.map +1 -1
  22. package/dist/components/CertRevBacklink.d.ts.map +1 -1
  23. package/dist/components/CertRevBacklink.js +3 -2
  24. package/dist/components/CertRevBacklink.js.map +1 -1
  25. package/dist/components/CertReview.d.ts +1 -1
  26. package/dist/components/ExpertBio.d.ts.map +1 -1
  27. package/dist/components/ExpertBio.js +12 -4
  28. package/dist/components/ExpertBio.js.map +1 -1
  29. package/dist/components/escape.d.ts +28 -1
  30. package/dist/components/escape.d.ts.map +1 -1
  31. package/dist/components/escape.js +37 -8
  32. package/dist/components/escape.js.map +1 -1
  33. package/dist/components/format.d.ts +51 -2
  34. package/dist/components/format.d.ts.map +1 -1
  35. package/dist/components/format.js +103 -6
  36. package/dist/components/format.js.map +1 -1
  37. package/dist/components/preview-block.d.ts +1 -1
  38. package/dist/components/preview-block.js +3 -3
  39. package/dist/components/preview-block.js.map +1 -1
  40. package/dist/components/rel.d.ts +24 -0
  41. package/dist/components/rel.d.ts.map +1 -0
  42. package/dist/components/rel.js +24 -0
  43. package/dist/components/rel.js.map +1 -0
  44. package/dist/components/render-cert-block.d.ts +50 -22
  45. package/dist/components/render-cert-block.d.ts.map +1 -1
  46. package/dist/components/render-cert-block.js +146 -80
  47. package/dist/components/render-cert-block.js.map +1 -1
  48. package/dist/components/render-def.d.ts +13 -14
  49. package/dist/components/render-def.d.ts.map +1 -1
  50. package/dist/components/render-def.js +14 -15
  51. package/dist/components/render-def.js.map +1 -1
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +4 -2
  55. package/dist/index.js.map +1 -1
  56. package/dist/jsonld/project.d.ts +46 -13
  57. package/dist/jsonld/project.d.ts.map +1 -1
  58. package/dist/jsonld/project.js +139 -56
  59. package/dist/jsonld/project.js.map +1 -1
  60. package/dist/modal/avatar-resize.d.ts +10 -10
  61. package/dist/modal/avatar-resize.js +14 -14
  62. package/dist/modal/avatar-resize.js.map +1 -1
  63. package/dist/modal/cert-modal-view.d.ts +27 -7
  64. package/dist/modal/cert-modal-view.d.ts.map +1 -1
  65. package/dist/modal/cert-modal-view.js +49 -25
  66. package/dist/modal/cert-modal-view.js.map +1 -1
  67. package/dist/modal/certrev-cert-modal.d.ts +5 -5
  68. package/dist/modal/certrev-cert-modal.js +9 -9
  69. package/dist/modal/certrev-cert-modal.js.map +1 -1
  70. package/dist/modal/certrev-cert-modal.styles.d.ts +6 -6
  71. package/dist/modal/certrev-cert-modal.styles.d.ts.map +1 -1
  72. package/dist/modal/certrev-cert-modal.styles.js +8 -8
  73. package/dist/modal/certrev-cert-modal.styles.js.map +1 -1
  74. package/dist/modal/certrev-cert.entry.d.ts +8 -6
  75. package/dist/modal/certrev-cert.entry.d.ts.map +1 -1
  76. package/dist/modal/certrev-cert.entry.js +9 -7
  77. package/dist/modal/certrev-cert.entry.js.map +1 -1
  78. package/dist/modal/certrev-cert.js +6 -6
  79. package/dist/modal/display-strings.d.ts +25 -5
  80. package/dist/modal/display-strings.d.ts.map +1 -1
  81. package/dist/modal/display-strings.js +27 -5
  82. package/dist/modal/display-strings.js.map +1 -1
  83. package/dist/modal/escape.d.ts +26 -3
  84. package/dist/modal/escape.d.ts.map +1 -1
  85. package/dist/modal/escape.js +32 -3
  86. package/dist/modal/escape.js.map +1 -1
  87. package/dist/modal/font-face.d.ts.map +1 -1
  88. package/dist/modal/font-face.js +8 -11
  89. package/dist/modal/font-face.js.map +1 -1
  90. package/dist/modal/ftc-disclosure.d.ts +2 -2
  91. package/dist/modal/ftc-disclosure.js +2 -2
  92. package/dist/modal/ftc-guard.d.ts +44 -9
  93. package/dist/modal/ftc-guard.d.ts.map +1 -1
  94. package/dist/modal/ftc-guard.js +50 -17
  95. package/dist/modal/ftc-guard.js.map +1 -1
  96. package/dist/modal/index.d.ts +1 -1
  97. package/dist/modal/index.js +1 -1
  98. package/dist/modal/interactions.d.ts +2 -2
  99. package/dist/modal/interactions.js +2 -2
  100. package/dist/modal/logo-paths.js +2 -2
  101. package/dist/modal/logo-paths.js.map +1 -1
  102. package/dist/modal/placement.d.ts +4 -3
  103. package/dist/modal/placement.d.ts.map +1 -1
  104. package/dist/modal/placement.js +7 -6
  105. package/dist/modal/placement.js.map +1 -1
  106. package/dist/modal/revalidate.d.ts +2 -3
  107. package/dist/modal/revalidate.d.ts.map +1 -1
  108. package/dist/modal/revalidate.js +2 -3
  109. package/dist/modal/revalidate.js.map +1 -1
  110. package/dist/modal/verify-client.d.ts +2 -2
  111. package/dist/modal/verify-client.js +2 -2
  112. package/dist/verify/cache.d.ts +21 -6
  113. package/dist/verify/cache.d.ts.map +1 -1
  114. package/dist/verify/cache.js +29 -8
  115. package/dist/verify/cache.js.map +1 -1
  116. package/dist/verify/fetch-with-deadline.d.ts +35 -0
  117. package/dist/verify/fetch-with-deadline.d.ts.map +1 -0
  118. package/dist/verify/fetch-with-deadline.js +55 -0
  119. package/dist/verify/fetch-with-deadline.js.map +1 -0
  120. package/dist/verify/get-verified-envelope.d.ts +23 -9
  121. package/dist/verify/get-verified-envelope.d.ts.map +1 -1
  122. package/dist/verify/get-verified-envelope.js +89 -40
  123. package/dist/verify/get-verified-envelope.js.map +1 -1
  124. package/dist/verify/resolve-kid.d.ts +3 -0
  125. package/dist/verify/resolve-kid.d.ts.map +1 -1
  126. package/dist/verify/resolve-kid.js +17 -8
  127. package/dist/verify/resolve-kid.js.map +1 -1
  128. package/dist/webcomponent/certrev-badge.d.ts.map +1 -1
  129. package/dist/webcomponent/certrev-badge.js +24 -2
  130. package/dist/webcomponent/certrev-badge.js.map +1 -1
  131. package/dist/webcomponent/render-badge-html.d.ts +1 -1
  132. package/dist/webcomponent/render-badge-html.d.ts.map +1 -1
  133. package/dist/webcomponent/render-badge-html.js +36 -17
  134. package/dist/webcomponent/render-badge-html.js.map +1 -1
  135. package/package.json +5 -2
  136. package/src/builder/cert-chrome-data.ts +26 -8
  137. package/src/builder/cert-review-card.tsx +149 -38
  138. package/src/builder/index.tsx +34 -17
  139. package/src/components/CertBadge.tsx +14 -9
  140. package/src/components/CertJsonLd.tsx +1 -1
  141. package/src/components/CertRevBacklink.tsx +10 -3
  142. package/src/components/CertReview.tsx +1 -1
  143. package/src/components/ExpertBio.tsx +15 -8
  144. package/src/components/escape.ts +37 -7
  145. package/src/components/format.ts +102 -6
  146. package/src/components/preview-block.ts +3 -3
  147. package/src/components/rel.ts +23 -0
  148. package/src/components/render-cert-block.ts +192 -109
  149. package/src/components/render-def.ts +14 -15
  150. package/src/index.ts +4 -2
  151. package/src/jsonld/project.ts +155 -59
  152. package/src/modal/avatar-resize.ts +14 -14
  153. package/src/modal/cert-modal-view.ts +52 -27
  154. package/src/modal/certrev-cert-modal.styles.ts +8 -8
  155. package/src/modal/certrev-cert-modal.ts +9 -9
  156. package/src/modal/certrev-cert.entry.ts +9 -7
  157. package/src/modal/display-strings.ts +26 -5
  158. package/src/modal/escape.ts +32 -4
  159. package/src/modal/font-face.ts +8 -11
  160. package/src/modal/ftc-disclosure.ts +2 -2
  161. package/src/modal/ftc-guard.ts +73 -18
  162. package/src/modal/index.ts +1 -1
  163. package/src/modal/interactions.ts +2 -2
  164. package/src/modal/logo-paths.ts +2 -2
  165. package/src/modal/placement.ts +7 -6
  166. package/src/modal/revalidate.ts +2 -3
  167. package/src/modal/verify-client.ts +2 -2
  168. package/src/verify/cache.ts +34 -8
  169. package/src/verify/fetch-with-deadline.ts +60 -0
  170. package/src/verify/get-verified-envelope.ts +131 -48
  171. package/src/verify/resolve-kid.ts +22 -6
  172. package/src/webcomponent/certrev-badge.ts +24 -2
  173. package/src/webcomponent/render-badge-html.ts +66 -19
  174. package/src/__tests__/__snapshots__/render-cert-block.test.ts.snap +0 -17
  175. package/src/__tests__/components.test.tsx +0 -206
  176. package/src/__tests__/preview-block.test.ts +0 -84
  177. package/src/__tests__/project.test.ts +0 -128
  178. package/src/__tests__/readme-version.test.ts +0 -51
  179. package/src/__tests__/render-cert-block.test.ts +0 -657
  180. package/src/__tests__/render-def.test.tsx +0 -295
  181. package/src/__tests__/verify.test.ts +0 -239
  182. package/src/__tests__/webcomponent.test.tsx +0 -116
  183. package/src/builder/__tests__/builder.test.tsx +0 -158
  184. package/src/modal/cert-modal-view.test.ts +0 -175
  185. package/src/modal/certrev-cert-modal.test.ts +0 -125
  186. package/src/modal/ftc-guard.test.ts +0 -153
  187. package/src/modal/interactions.test.ts +0 -250
  188. package/src/modal/placement.test.ts +0 -398
  189. package/src/modal/revalidate.test.ts +0 -111
  190. package/src/modal/verify-client.test.ts +0 -164
package/CHANGELOG.md CHANGED
@@ -1,44 +1,208 @@
1
- # Changelog — @certrev/cert-block
1
+ # Changelog: @certrev/cert-block
2
2
 
3
3
  The cert card is a **design-locked** component. Semver contract: **patch and minor releases never
4
4
  change the rendered cert output and never break a compiling integration** (registration surface,
5
- exports, types). Anything that would alter what a visitor sees — or require integration changes —
5
+ exports, types). Anything that would alter what a visitor sees, or require integration changes,
6
6
  is announced loudly here first.
7
7
 
8
- ## 0.5.5 — 2026-07-31
8
+ ## 1.0.1 · 2026-08-18
9
9
 
10
- - **New:** `repository`, `homepage`, and `bugs` in `package.json` — the npm page now links to the
10
+ Patch: copy only. No API change, no type change, no behaviour change beyond the five characters
11
+ named below.
12
+
13
+ - **Five em dashes were rendering to readers in 1.0.0.** Two of them on the customer's own article:
14
+ the expert credential list set one between each abbreviation and its expansion (`MD`, then
15
+ `Doctor of Medicine`). That is labelled data, so it now uses a middle dot, matching the preview
16
+ caption and the modal. The other three sat in the
17
+ Builder editor's helper text, where an editor reads them: one list qualifier takes a full stop
18
+ (the middle dots already separate the three values, so a fourth would read as a fourth option),
19
+ one pair of independent clauses takes a comma before `and`, and one consequence clause takes a
20
+ colon.
21
+ - **Why 1.0.0 shipped with them.** Every guard in place checked PROSE or SOURCE. The prose guard
22
+ covers the README and this changelog; a source grep cannot tell a string literal that renders
23
+ from a comment that does not, and this package has ~795 em dashes in comments that are
24
+ deliberately in scope for neither. So the one thing nobody checked was the output. They were
25
+ found by rendering the package and grepping what came out, during the mirror leak sweep, after
26
+ 1.0.0 was already immutable on npm.
27
+ - **`rendered-voice.test.tsx` closes it as a gate**, not as something to remember: it renders all
28
+ 33 surfaces (every `mode` × `part`, both badge styles, the pro-bono and empty-memo shapes, the
29
+ preview, the JSON-LD, both modal dialogs, all five React components, and the Builder
30
+ registration) and asserts zero em dashes, plus an en dash only between digits. It carries a
31
+ coverage floor, because an empty render is indistinguishable from a clean one. Confirmed to fail
32
+ on the 1.0.0 strings, naming each surface and quoting the sentence.
33
+
34
+ ## 1.0.0 · 2026-08-17
35
+
36
+ **A major, and the semver contract at the top of this file is why.** It says patch and minor
37
+ releases never change the rendered cert output and never break a compiling integration. This
38
+ release does both, deliberately. 0.5.4's entry records what happens when that rule is applied
39
+ loosely; this one applies it strictly.
40
+
41
+ ### Breaking: sidebar is the default placement
42
+
43
+ Any previously-exported entry that omits `mode` rendered as a **banner** and now renders as a
44
+ **sidebar**, on every brand, not just the one that asked for it. That is the intended outcome. No
45
+ compatibility flag, no backfill, no per-brand switch: one default, everywhere.
46
+
47
+ The mechanism matters as much as the value. `renderCertBlock`'s `switch (mode)` had no `default:`,
48
+ so an unmatched mode returned `undefined` from a function declared `: string`. On the Builder path
49
+ that lands in `dangerouslySetInnerHTML` and emits a 39-byte empty div: HTTP 200, no console error,
50
+ no throw, card silently gone. `case 'sidebar':` now falls into `default:`, so the declared default
51
+ and the runtime fallback are the same physical line and cannot drift. `RenderCertBlockInput.mode`
52
+ is optional, and the `?? 'banner'` in the Builder card is deleted rather than flipped, because two
53
+ layers naming a default is the bug class. Every arm passes a string literal to the root wrapper, so
54
+ an untyped `mode` can no longer reach the root class name or `data-certrev-mode`. `part` is
55
+ normalised by an explicit rule instead of a catch-all ternary arm. The Builder `mode` and `part`
56
+ inputs now carry a default and an enum, which constrains new editor input; the runtime fallback is
57
+ what covers already-stored content and anything written through Builder's Write API.
58
+
59
+ ### Breaking: compliance strings are constants, not caller input
60
+
61
+ - **Removed from `CertBlockFacts`:** `scopeLine` and `credentialLine`. The FTC scope line's curly
62
+ apostrophe is documented in `render-def.ts` as pinned to MSA §3, and `locked(supplied, constant)`
63
+ returned the caller's value whenever it was a non-blank string, so that copy was rewritable from
64
+ a Builder "Advanced" text box. `locked()` is deleted; the package renders its constants.
65
+ - **`compensationCue` is now `string | null`,** and only `null` is meaningful: it OMITS the cue,
66
+ which is the pro-bono reviewer. Any other value renders the locked constant. Previously a null
67
+ cue caused the key to be dropped and the constant to substitute, so a volunteer's card asserted
68
+ "Compensated expert" while the modal in this same package got the same null right.
69
+
70
+ ### Breaking: the escape helpers accept what actually arrives
71
+
72
+ `escapeHtml` / `escapeAttribute` widen from `string` to `string | null | undefined` and coerce a
73
+ wrong TYPE rather than throwing. `formatDate` returns null for a non-string instead of fabricating
74
+ a date from a number. `expertNameWithCredentials` returns `''` when the display name is missing.
75
+ Well-formed output is byte-identical; only off-contract input behaves differently.
76
+
77
+ ### Rendered output changes
78
+
79
+ - **Every anchor is qualified.** All 14 emission sites across the React components, the string
80
+ renderer, the Web Component and the modal now carry `rel="nofollow sponsored noopener"` from one
81
+ exported constant, `CERTREV_LINK_REL`. Google's link-spam policy names an unqualified
82
+ vendor-required link on a customer's page directly, and `CertBadgeProps` had no `rel` prop, so
83
+ the customer could not qualify them.
84
+ - **An empty memo no longer renders an "Expert memo" heading over an empty `<p>`,** or an empty
85
+ accent-bordered blockquote on the sidebar and custom faces. `bio` already did this correctly
86
+ three times in the same file; only `memo` skipped the check.
87
+ - **An unparseable or blank date no longer asserts a date.** "Credential verified by CertREV on
88
+ not-a-date" and a dangling "on " are gone; so is a bare "Certified" with nothing after it.
89
+ - **A credential carried in the display name is no longer printed twice.** "Dr. Erik Schraga, MD,
90
+ MD, EM" renders one "MD". A token is dropped only when it equals a WHOLE comma-separated segment
91
+ of the name, so "MD" survives "Dr. MDonald", "Jane Amdahl" and "Md. Rahman". This is a render
92
+ boundary declining to print a duplicate; the stored data is still wrong and the repair is
93
+ portal-side.
94
+ - **The expert avatar is marked decorative (`alt=""`) on all four faces.** Three of them emitted
95
+ `alt="Photo of {name}"` beside the same name in text. In `<ExpertBio>` that made a screen reader
96
+ announce it three times running: the aside's `aria-label`, then "Photo of Jane Doe, image", then
97
+ the heading. The modal avatar already had `alt=""`, which is the tell that one decision was made
98
+ four times by hand and landed differently. A source sweep now holds all four in lockstep.
99
+ - **The bio accordion's toggle attribute changed** from `data-certrev-bio-toggle`, which had zero
100
+ consumers anywhere, to `data-certrev-acc`, which is what `modal/interactions.ts` binds. The
101
+ focusable `role="button"` was emitted even with no bio, so a screen reader announced "Read more
102
+ about Dr. X, button, collapsed" over nothing: WCAG 2.1 4.1.2 and 2.1.1, in a vendor string
103
+ renderer the consumer cannot patch. With no bio the row is now inert markup.
104
+
105
+ ### JSON-LD
106
+
107
+ - `reviewNode` dropped the caller's `opts`, so any `pageUrl` differing from `canonicalUrls[0]` left
108
+ the Review's `itemReviewed` pointing at an `@id` no node in the graph carried. Fixed, and a graph
109
+ integrity test now walks every `@id` reference and asserts it resolves.
110
+ - `reviewBody`, `Article.author` and `Person.image` were emitted regardless of the display flags
111
+ the card gates them on. All three now resolve visibility through the same `resolveDisplay` the
112
+ card uses, which folds in the render-def's subtractive hide-set. Google: don't mark up content
113
+ that is not visible to readers.
114
+ - **New:** a `WebPage` node with `lastReviewed`, and `recognizedBy` on every credential.
115
+ - **Changed `@id`:** the Organization node is now the constant
116
+ `https://certrev.com/#certrev-organization` instead of being derived from the per-payload
117
+ `verifyUrl` origin, which is what made "one stable CertREV organization node across all pages"
118
+ false. Portal-side alignment is a separate job.
119
+ - `ProjectJsonLdOptions` gains an optional `renderDef`.
120
+
121
+ ### Verify layer
122
+
123
+ - **Every fetch now has a deadline.** A hung origin was confirmed still pending at 45 seconds
124
+ inside a server render, with no `AbortSignal` anywhere. An abort lands on the same fail-closed
125
+ suppress path as any other failure.
126
+ - **`ttlMs` is wired through.** It was declared in the shipped `.d.ts` with a documented default
127
+ and never read.
128
+ - **Truthful suppress reasons.** A network failure, a 404 and malformed JSON all collapsed to
129
+ `unsupported_contract_version`.
130
+ - The `delivery_api` cache key omitted `baseUrl` and the whole `RenderContext`, while the
131
+ `metafield` branch two lines below keyed on both.
132
+
133
+ ### FTC guard
134
+
135
+ `enforceFtcDisclosure` returns `'intact' | 'tampered' | 'unguarded'` instead of a boolean. Nothing
136
+ in this package emits `.certrev-memo` (that markup is portal's Liquid), so on every React / Web
137
+ Component / `renderCertBlock` surface the guard installed a whole-body, subtree, attributes and
138
+ characterData observer that could never match, then reported `true` for "intact" on a page it had
139
+ not checked. It now declines to observe a document with no guarded surface, and says so. Which
140
+ surfaces the kill switch *should* cover is an open design question, documented not guessed.
141
+
142
+ ### Packaging and docs
143
+
144
+ - **`LICENSE` now exists.** Both packages declared MIT and shipped no license text; there was no
145
+ LICENSE file anywhere in the repo. Holder: CertREV LLC.
146
+ - **The tarball no longer ships its own test suite:** 227 files / 315.8 kB → 210 / 269.7 kB, with
147
+ every production source still shipping, `.tsx` included.
148
+ - **The README's central trust claim was false about the path it recommends.** "The package never
149
+ renders an unverified credential" is now scoped to the verify layer, where it holds, and a new
150
+ "PUSH trust model" section states what the Builder path actually guarantees and what revocation
151
+ does and does not do.
152
+ - **The route example exists.** "(See the route example.)" had shipped in `dist/builder/index.d.ts`
153
+ for releases, pointing at a file that never existed.
154
+ - The Hydrogen example wired the kid `certrev-2026-1`, which appears nowhere else in the repo; the
155
+ live JWKS serves `cert-issuer-1`, and a wrong kid suppresses silently with nothing logged.
156
+ - CSP docs gain `font-src` for the 12 `@font-face` rules the modal injects, and `data-fonts` is
157
+ documented.
158
+ - **Biome now lints and formats `.tsx`.** `files.includes` had never listed the extension, so all
159
+ 11 React components in the repo were unchecked by the linter that gates every other file. Turning
160
+ it on surfaced the avatar `alt` defect above, three computed keys that were plain string literals,
161
+ a suppression comment for a rule that was never firing, and six files with unsorted imports.
162
+ - **Internal notes stripped from published source** (this package publishes `src/`), and
163
+ `scripts/check-publish-hygiene.mjs` now fails CI on a new one, covering `@certrev/cert-contract`
164
+ on the same rules.
165
+ - **Copy:** the preview block's caption is `Preview · Not a verified certification`; its HTML
166
+ comment banner uses a colon; the Builder registration description uses a semicolon. The npm
167
+ `description` is rewritten to 236 characters, because npm caps the packument description at 255
168
+ and was serving this one cut off mid-word at "…and a".
169
+
170
+ 541 tests, up from 249.
171
+
172
+ ## 0.5.5 · 2026-07-31
173
+
174
+ - **New:** `repository`, `homepage`, and `bugs` in `package.json`: the npm page now links to the
11
175
  public source mirror (`github.com/CertREV/cert-kit`, `packages/cert-block`) and to the issue
12
176
  tracker, so the registry listing is no longer a dead end. Provenance metadata only: no code, no
13
177
  exports, no dependency change.
14
- - **Docs:** README gains a source-repo link and states the peer requirement explicitly — **React
178
+ - **Docs:** README gains a source-repo link and states the peer requirement explicitly: **React
15
179
  `>=18`**. `peerDependencies.react` has enforced `>=18.0.0` since before 0.5.0 (and
16
180
  `peerDependenciesMeta` marks it non-optional), but the README never said so; a consumer had to
17
181
  read `package.json` to find the floor.
18
- - Rendered output: **byte-identical to 0.5.4** (metadata and prose only — no file under `dist/`
182
+ - Rendered output: **byte-identical to 0.5.4** (metadata and prose only: no file under `dist/`
19
183
  changes).
20
184
 
21
- ## 0.5.4 — 2026-07-23
185
+ ## 0.5.4 · 2026-07-23
22
186
 
23
- - **Backfilled — this release shipped with no entry.** 0.5.4 published 2026-07-23 and is the first
187
+ - **Backfilled: this release shipped with no entry.** 0.5.4 published 2026-07-23 and is the first
24
188
  release after this file was written; every other version from 0.3.0 on has a section, including
25
189
  0.5.2 (a no-op republish). It changed the public type surface without the notice the contract
26
190
  above requires. The omission is recorded here rather than quietly closed.
27
- - **Changed:** `FONT_SLOTS` / `FONT_STACKS` (`render-def`) widened 3 → 5 — `grotesk` (Plus Jakarta
191
+ - **Changed:** `FONT_SLOTS` / `FONT_STACKS` (`render-def`) widened 3 → 5: `grotesk` (Plus Jakarta
28
192
  Sans) and `mono` (JetBrains Mono) added at the shared guide values, byte-identical to this
29
193
  package's `RENDER_BLOCK_FONT_STACKS`, the portal `FONT_SLOT_STACKS`, and the Liquid twin's
30
194
  branches. Purely additive: `sans` / `serif` / `system` are untouched, so the card == modal
31
195
  invariant holds. Shipped lockstep with the portal's Liquid + WordPress grotesk/mono wiring
32
- (POR-10775 / POR-10721) — Phase-3 enablement of a vocabulary that was dormant on both engines,
33
- not a repair of a live intra-page mismatch: before this release the Liquid card dropped
196
+ This was Phase-3 enablement of a vocabulary that was dormant on both engines, not a repair of a
197
+ live intra-page mismatch: before this release the Liquid card dropped
34
198
  `grotesk`/`mono` too, and fell back exactly as the modal did.
35
- - **Breaking (types) — belonged in a minor, with notice:** `FONT_SLOTS`, `FONT_STACKS`, `FontSlot`
199
+ - **Breaking (types). This belonged in a minor, with notice:** `FONT_SLOTS`, `FONT_STACKS`, `FontSlot`
36
200
  and `isFontSlot` are public exports. Widening the `FontSlot` union 3 → 5 breaks any consumer
37
- holding an exhaustive `Record<FontSlot, string>` or an exhaustive `switch` over the slots — a
201
+ holding an exhaustive `Record<FontSlot, string>` or an exhaustive `switch` over the slots: a
38
202
  break of a compiling integration (exports, types) under the semver contract at the top of this
39
203
  file, shipped in a patch.
40
204
  - Rendered output: the design-locked cert card and the modal bundle are **byte-identical to
41
- 0.5.3** — across the two published tarballs `dist/components/render-cert-block.js` (sha1
205
+ 0.5.3**: across the two published tarballs `dist/components/render-cert-block.js` (sha1
42
206
  `22267d5d…`) and all 65 files under `dist/modal/` (`certrev-cert.js` sha1 `2013ebbe…`) are
43
207
  unchanged, and neither resolves the shared `FONT_STACKS` (the card carries its own
44
208
  `RENDER_BLOCK_FONT_STACKS`, which already listed all five slots; the modal consults no font map
@@ -47,23 +211,23 @@ is announced loudly here first.
47
211
  legacy `<CertBadge>` / `renderBadgeHtml`, where that slot now resolves to a `--certrev-font`
48
212
  stack instead of being dropped as invalid. No brand could author those slots at release time (the
49
213
  portal editor did not offer them; every known `render_def` writer emits `sans`), so no visitor's
50
- render is known to have changed — that last point is inference from the call graph and the
214
+ render is known to have changed; that last point is inference from the call graph and the
51
215
  authoring surface, not a production data check.
52
216
 
53
- ## 0.5.3 — 2026-07-22
217
+ ## 0.5.3 · 2026-07-22
54
218
 
55
- - **New:** `certRevCertComponent` (`./builder`) — the drop-in gen2 registration entry, with the
219
+ - **New:** `certRevCertComponent` (`./builder`): the drop-in gen2 registration entry, with the
56
220
  mutable `inputs[]` the SDK's `RegisteredComponent` type expects:
57
221
  `customComponents={[...yourComponents, certRevCertComponent]}`. One import, no re-wrapping, no
58
222
  readonly spread. `BUILDER_REGISTRATION` (the readonly canonical view) is unchanged.
59
- - **New:** the 19 exporter-populated wire inputs are marked `advanced` — the Builder editor's
223
+ - **New:** the 19 exporter-populated wire inputs are marked `advanced`: the Builder editor's
60
224
  Options tab now leads with the two placement inputs (`mode`, `part`) and tucks the
61
225
  system-populated fields under "Advanced". Editor-cosmetic only.
62
226
  - **Changed:** `@certrev/cert-contract` moved from a peer dependency (`>=0.5.0`, unbounded) to a
63
- regular dependency (bounded `^0.5.0`) — a plain `npm i @certrev/cert-block` is a complete
227
+ regular dependency (bounded `^0.5.0`): a plain `npm i @certrev/cert-block` is a complete
64
228
  install regardless of the consumer's peer-install settings, and a future contract 0.6 can no
65
229
  longer float in unreviewed.
66
- - **Docs:** README rewritten for the gen2 SDK (`customComponents` array) — the previous README
230
+ - **Docs:** README rewritten for the gen2 SDK (`customComponents` array): the previous README
67
231
  showed the gen1 `Builder.registerComponent` API and pre-publish notes that no longer applied
68
232
  (the contract package and the modal bundle both ship for real since 0.5.x). Added in-package
69
233
  modal instructions (`?url` import + external script + literal CSP allowances), a known-issues
@@ -72,21 +236,21 @@ is announced loudly here first.
72
236
  - Rendered output: **byte-identical to 0.5.2** (changes outside the registration surface are
73
237
  comment-only).
74
238
 
75
- ## 0.5.2 — 2026-07-21
239
+ ## 0.5.2 · 2026-07-21
76
240
 
77
241
  - Republish of 0.5.1 (the 0.5.1 GitHub-Packages tarball was unfetchable). No code changes.
78
242
 
79
- ## 0.5.1 — 2026-07
243
+ ## 0.5.1 · 2026-07
80
244
 
81
245
  - `./modal/placement` subpath exposed (the side-effect-free placement engine).
82
246
 
83
- ## 0.5.0 — 2026-07
247
+ ## 0.5.0 · 2026-07
84
248
 
85
- - The certificate-modal Web Component moved **into** the package (POR-10721 W2): prebuilt
249
+ - The certificate-modal Web Component moved **into** the package: prebuilt
86
250
  dependency-free IIFE at `./modal/certrev-cert.js` (byte-parity with the deployed theme-extension
87
251
  asset) + the `./modal` subpath. Banner memo placement (`part`), font hook, static preview block.
88
252
 
89
- ## 0.4.0 — 2026-07
253
+ ## 0.4.0 · 2026-07
90
254
 
91
255
  - Render strictly from `placedFields` + `renderCustomFace`; v2 brand-ink theming
92
256
  (`barInk` / `inkColor`).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CertREV LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.