@certrev/cert-block 2.0.1 → 2.1.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +9 -4
  3. package/dist/builder/cert-review-card.d.ts +2 -0
  4. package/dist/builder/cert-review-card.d.ts.map +1 -1
  5. package/dist/builder/cert-review-card.js +95 -10
  6. package/dist/builder/cert-review-card.js.map +1 -1
  7. package/dist/builder/delivery-runtime.d.ts +25 -1
  8. package/dist/builder/delivery-runtime.d.ts.map +1 -1
  9. package/dist/builder/delivery-runtime.js +26 -1
  10. package/dist/builder/delivery-runtime.js.map +1 -1
  11. package/dist/builder/envelope-face.d.ts +2 -0
  12. package/dist/builder/envelope-face.d.ts.map +1 -1
  13. package/dist/builder/envelope-face.js +9 -1
  14. package/dist/builder/envelope-face.js.map +1 -1
  15. package/dist/builder/version.d.ts +1 -1
  16. package/dist/builder/version.js +1 -1
  17. package/dist/components/CertBadge.d.ts.map +1 -1
  18. package/dist/components/CertBadge.js +4 -2
  19. package/dist/components/CertBadge.js.map +1 -1
  20. package/dist/components/render-cert-block.d.ts +9 -1
  21. package/dist/components/render-cert-block.d.ts.map +1 -1
  22. package/dist/components/render-cert-block.js +4 -4
  23. package/dist/components/render-cert-block.js.map +1 -1
  24. package/dist/components/render-def.d.ts +18 -0
  25. package/dist/components/render-def.d.ts.map +1 -1
  26. package/dist/components/render-def.js +15 -0
  27. package/dist/components/render-def.js.map +1 -1
  28. package/dist/modal/cert-modal-view.d.ts +3 -0
  29. package/dist/modal/cert-modal-view.d.ts.map +1 -1
  30. package/dist/modal/cert-modal-view.js +4 -3
  31. package/dist/modal/cert-modal-view.js.map +1 -1
  32. package/dist/modal/certrev-cert.js +4 -4
  33. package/dist/modal/display-strings.d.ts +9 -0
  34. package/dist/modal/display-strings.d.ts.map +1 -1
  35. package/dist/modal/display-strings.js +12 -1
  36. package/dist/modal/display-strings.js.map +1 -1
  37. package/dist/modal/ftc-disclosure.d.ts +6 -0
  38. package/dist/modal/ftc-disclosure.d.ts.map +1 -1
  39. package/dist/modal/ftc-disclosure.js +6 -0
  40. package/dist/modal/ftc-disclosure.js.map +1 -1
  41. package/dist/reader/render.d.ts.map +1 -1
  42. package/dist/reader/render.js +5 -10
  43. package/dist/reader/render.js.map +1 -1
  44. package/dist/verify/cache.d.ts +24 -0
  45. package/dist/verify/cache.d.ts.map +1 -1
  46. package/dist/verify/cache.js +78 -6
  47. package/dist/verify/cache.js.map +1 -1
  48. package/dist/verify/get-verified-delivery.d.ts +14 -0
  49. package/dist/verify/get-verified-delivery.d.ts.map +1 -1
  50. package/dist/verify/get-verified-delivery.js +21 -0
  51. package/dist/verify/get-verified-delivery.js.map +1 -1
  52. package/dist/webcomponent/render-badge-html.d.ts.map +1 -1
  53. package/dist/webcomponent/render-badge-html.js +6 -3
  54. package/dist/webcomponent/render-badge-html.js.map +1 -1
  55. package/package.json +1 -1
  56. package/src/builder/cert-review-card.tsx +108 -8
  57. package/src/builder/delivery-runtime.ts +28 -1
  58. package/src/builder/envelope-face.ts +16 -1
  59. package/src/builder/version.ts +1 -1
  60. package/src/components/CertBadge.tsx +6 -3
  61. package/src/components/render-cert-block.ts +13 -4
  62. package/src/components/render-def.ts +24 -0
  63. package/src/modal/cert-modal-view.ts +7 -3
  64. package/src/modal/display-strings.ts +14 -1
  65. package/src/modal/ftc-disclosure.ts +8 -0
  66. package/src/reader/render.ts +12 -11
  67. package/src/verify/cache.ts +78 -6
  68. package/src/verify/get-verified-delivery.ts +27 -0
  69. package/src/webcomponent/render-badge-html.ts +6 -3
@@ -1,5 +1,5 @@
1
1
  /* biome-ignore-all format: generated cert-badge bundle, see @certrev/cert-block src/modal/ */ /* biome-ignore-all lint: generated cert-badge bundle, see @certrev/cert-block src/modal/ */
2
- "use strict";(()=>{var H="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",Be=(()=>{let e=new Int8Array(128).fill(-1);for(let t=0;t<H.length;t++)e[H.charCodeAt(t)]=t;return e[45]=62,e[95]=63,e})();function g(e){let t=[];for(let i=0;i<e.length;i++){let c=e.charCodeAt(i),d=c<128?Be[c]:-1;d>=0&&t.push(d)}let r=Math.floor(t.length*6/8),n=new Uint8Array(r),o=0,a=0,s=0;for(let i=0;i<t.length;i++)o=o<<6|t[i],a+=6,a>=8&&(a-=8,n[s++]=o>>a&255);return n}function C(e){return g(e)}function p(e,t=new Set){if(typeof e=="number"&&isNaN(e))throw new Error("NaN is not allowed");if(typeof e=="number"&&!isFinite(e))throw new Error("Infinity is not allowed");if(e===null||typeof e!="object")return JSON.stringify(e);if(typeof e.toJSON=="function"){if(t.has(e))throw new Error("Circular reference detected");t.add(e);let n=p(e.toJSON(),t);return t.delete(e),n}if(t.has(e))throw new Error("Circular reference detected");t.add(e);let r;if(Array.isArray(e))r=`[${e.map(o=>p(o===void 0||typeof o=="symbol"?null:o,t)).join(",")}]`;else{let n=[];for(let o of Object.keys(e).sort())e[o]===void 0||typeof e[o]=="symbol"||n.push(`${p(o)}:${p(e[o],t)}`);r=`{${n.join(",")}}`}return t.delete(e),r}var Ie=typeof p=="function"?p:p.default;function K(e){let t=Ie(e);if(typeof t!="string")throw new Error("canonicalize: value is not JSON-serializable");return t}function F(e){return new TextEncoder().encode(K(e))}function b(e,t="$"){if(typeof e=="number"){if(!Number.isInteger(e)||!Number.isSafeInteger(e))throw new Error(`canonicalPayloadBytes: number at ${t} (${e}) is not a safe integer. Signed-payload numbers must be safe integers so PHP/Go/Java verifiers reproduce identical canonical bytes`);return}if(Array.isArray(e)){e.forEach((r,n)=>b(r,`${t}[${n}]`));return}if(e&&typeof e=="object")for(let[r,n]of Object.entries(e))b(n,`${t}.${r}`)}function T(e){return b(e),F(e)}function R(e){return b(e),F(e)}var U="ed25519";var m={name:"Ed25519"};function Oe(e){return e.replace(/-----BEGIN [^-]+-----/g,"").replace(/-----END [^-]+-----/g,"").replace(/\s+/g,"")}async function q(e){switch(e.format){case"pem":return crypto.subtle.importKey("spki",g(Oe(e.pem)),m,!1,["verify"]);case"spki-base64":return crypto.subtle.importKey("spki",g(e.base64),m,!1,["verify"]);case"spki-der":return crypto.subtle.importKey("spki",e.bytes,m,!1,["verify"]);case"raw":{if(e.bytes.length!==32)throw new Error(`ed25519 raw public key must be 32 bytes, got ${e.bytes.length}`);return crypto.subtle.importKey("raw",e.bytes,m,!1,["verify"])}}}function Ne(e){if("format"in e)return!1;let t=e;return typeof t.type=="string"&&typeof t.algorithm=="object"&&Array.isArray(t.usages)}async function j(e){return Ne(e)?e:q(e)}async function G(e,t,r){let n=T(e),o=C(t);try{return await crypto.subtle.verify(m,r,o,n)}catch{return!1}}async function Pe(e,t){let{payload:r,signature:n}=e??{};if(!r||!n||r.contractVersion!==1)return{ok:!1,reason:"unsupported_contract_version"};if(n.alg!==U)return{ok:!1,reason:"unsupported_alg"};let o=await t(n.kid);if(!o)return{ok:!1,reason:"unknown_key"};let a;try{a=await j(o)}catch{return{ok:!1,reason:"unknown_key"}}return await G(r,n.sig,a)?{ok:!0,key:a}:{ok:!1,reason:"invalid_signature"}}function J(e,t){let r=t.now??new Date;if(e.subject.platform!==t.platform)return{decision:"suppress",reason:"platform_mismatch"};if(e.subject.externalId!==t.externalId)return{decision:"suppress",reason:"subject_mismatch"};if(e.lifecycle.revokedAt!==null)return{decision:"suppress",reason:"revoked"};if(r.getTime()>=Date.parse(e.lifecycle.expiresAt))return{decision:"suppress",reason:"expired"};let n=e.subject.contentDigest,o=t.liveContentHash;return n!==null&&o!=null&&n!==o?{decision:"suppress",reason:"content_drift"}:{decision:"render",payload:e}}async function Z(e,t,r){let n;try{n=await Pe(e,t)}catch{return{decision:"suppress",reason:"unknown_key"}}return n.ok?J(e.payload,r):{decision:"suppress",reason:n.reason}}function v(e){return e?.kind==="tombstone"}async function ze(e,t){let{signature:r}=e??{};if(!e?.subject||!r||e.contractVersion!==1)return{ok:!1,reason:"unsupported_contract_version"};if(r.alg!==U)return{ok:!1,reason:"unsupported_alg"};let n=await t(r.kid);if(!n)return{ok:!1,reason:"unknown_key"};let o;try{o=await j(n)}catch{return{ok:!1,reason:"unknown_key"}}let{signature:a,...s}=e,i=C(r.sig),c=!1;try{c=await crypto.subtle.verify(m,o,i,R(s))}catch{c=!1}return c?{ok:!0,key:o}:{ok:!1,reason:"invalid_signature"}}async function W(e,t,r){let n;try{n=await ze(e,t)}catch{return{decision:"suppress",reason:"unknown_key"}}return n.ok?e.subject.platform!==r.platform?{decision:"suppress",reason:"platform_mismatch"}:e.subject.externalId!==r.externalId?{decision:"suppress",reason:"subject_mismatch"}:{decision:"suppress",reason:"revoked"}:{decision:"suppress",reason:n.reason}}async function L(e,t,r){return v(e)?W(e,t,r):Z(e,t,r)}var Y=`
2
+ "use strict";(()=>{var H="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",Be=(()=>{let e=new Int8Array(128).fill(-1);for(let t=0;t<H.length;t++)e[H.charCodeAt(t)]=t;return e[45]=62,e[95]=63,e})();function g(e){let t=[];for(let i=0;i<e.length;i++){let c=e.charCodeAt(i),d=c<128?Be[c]:-1;d>=0&&t.push(d)}let r=Math.floor(t.length*6/8),n=new Uint8Array(r),o=0,a=0,s=0;for(let i=0;i<t.length;i++)o=o<<6|t[i],a+=6,a>=8&&(a-=8,n[s++]=o>>a&255);return n}function C(e){return g(e)}function p(e,t=new Set){if(typeof e=="number"&&isNaN(e))throw new Error("NaN is not allowed");if(typeof e=="number"&&!isFinite(e))throw new Error("Infinity is not allowed");if(e===null||typeof e!="object")return JSON.stringify(e);if(typeof e.toJSON=="function"){if(t.has(e))throw new Error("Circular reference detected");t.add(e);let n=p(e.toJSON(),t);return t.delete(e),n}if(t.has(e))throw new Error("Circular reference detected");t.add(e);let r;if(Array.isArray(e))r=`[${e.map(o=>p(o===void 0||typeof o=="symbol"?null:o,t)).join(",")}]`;else{let n=[];for(let o of Object.keys(e).sort())e[o]===void 0||typeof e[o]=="symbol"||n.push(`${p(o)}:${p(e[o],t)}`);r=`{${n.join(",")}}`}return t.delete(e),r}var $e=typeof p=="function"?p:p.default;function K(e){let t=$e(e);if(typeof t!="string")throw new Error("canonicalize: value is not JSON-serializable");return t}function T(e){return new TextEncoder().encode(K(e))}function b(e,t="$"){if(typeof e=="number"){if(!Number.isInteger(e)||!Number.isSafeInteger(e))throw new Error(`canonicalPayloadBytes: number at ${t} (${e}) is not a safe integer. Signed-payload numbers must be safe integers so PHP/Go/Java verifiers reproduce identical canonical bytes`);return}if(Array.isArray(e)){e.forEach((r,n)=>b(r,`${t}[${n}]`));return}if(e&&typeof e=="object")for(let[r,n]of Object.entries(e))b(n,`${t}.${r}`)}function F(e){return b(e),T(e)}function R(e){return b(e),T(e)}var E="ed25519";var m={name:"Ed25519"};function Ne(e){return e.replace(/-----BEGIN [^-]+-----/g,"").replace(/-----END [^-]+-----/g,"").replace(/\s+/g,"")}async function q(e){switch(e.format){case"pem":return crypto.subtle.importKey("spki",g(Ne(e.pem)),m,!1,["verify"]);case"spki-base64":return crypto.subtle.importKey("spki",g(e.base64),m,!1,["verify"]);case"spki-der":return crypto.subtle.importKey("spki",e.bytes,m,!1,["verify"]);case"raw":{if(e.bytes.length!==32)throw new Error(`ed25519 raw public key must be 32 bytes, got ${e.bytes.length}`);return crypto.subtle.importKey("raw",e.bytes,m,!1,["verify"])}}}function Pe(e){if("format"in e)return!1;let t=e;return typeof t.type=="string"&&typeof t.algorithm=="object"&&Array.isArray(t.usages)}async function j(e){return Pe(e)?e:q(e)}async function G(e,t,r){let n=F(e),o=C(t);try{return await crypto.subtle.verify(m,r,o,n)}catch{return!1}}async function ze(e,t){let{payload:r,signature:n}=e??{};if(!r||!n||r.contractVersion!==1)return{ok:!1,reason:"unsupported_contract_version"};if(n.alg!==E)return{ok:!1,reason:"unsupported_alg"};let o=await t(n.kid);if(!o)return{ok:!1,reason:"unknown_key"};let a;try{a=await j(o)}catch{return{ok:!1,reason:"unknown_key"}}return await G(r,n.sig,a)?{ok:!0,key:a}:{ok:!1,reason:"invalid_signature"}}function J(e,t){let r=t.now??new Date;if(e.subject.platform!==t.platform)return{decision:"suppress",reason:"platform_mismatch"};if(e.subject.externalId!==t.externalId)return{decision:"suppress",reason:"subject_mismatch"};if(e.lifecycle.revokedAt!==null)return{decision:"suppress",reason:"revoked"};if(r.getTime()>=Date.parse(e.lifecycle.expiresAt))return{decision:"suppress",reason:"expired"};let n=e.subject.contentDigest,o=t.liveContentHash;return n!==null&&o!=null&&n!==o?{decision:"suppress",reason:"content_drift"}:{decision:"render",payload:e}}async function Z(e,t,r){let n;try{n=await ze(e,t)}catch{return{decision:"suppress",reason:"unknown_key"}}return n.ok?J(e.payload,r):{decision:"suppress",reason:n.reason}}function v(e){return e?.kind==="tombstone"}async function Ve(e,t){let{signature:r}=e??{};if(!e?.subject||!r||e.contractVersion!==1)return{ok:!1,reason:"unsupported_contract_version"};if(r.alg!==E)return{ok:!1,reason:"unsupported_alg"};let n=await t(r.kid);if(!n)return{ok:!1,reason:"unknown_key"};let o;try{o=await j(n)}catch{return{ok:!1,reason:"unknown_key"}}let{signature:a,...s}=e,i=C(r.sig),c=!1;try{c=await crypto.subtle.verify(m,o,i,R(s))}catch{c=!1}return c?{ok:!0,key:o}:{ok:!1,reason:"invalid_signature"}}async function W(e,t,r){let n;try{n=await Ve(e,t)}catch{return{decision:"suppress",reason:"unknown_key"}}return n.ok?e.subject.platform!==r.platform?{decision:"suppress",reason:"platform_mismatch"}:e.subject.externalId!==r.externalId?{decision:"suppress",reason:"subject_mismatch"}:{decision:"suppress",reason:"revoked"}:{decision:"suppress",reason:n.reason}}async function L(e,t,r){return v(e)?W(e,t,r):Z(e,t,r)}var Y=`
3
3
  @font-face {
4
4
  font-family: "DM Sans";
5
5
  font-style: normal;
@@ -119,7 +119,7 @@
119
119
  unicode-range:
120
120
  U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
121
121
  }
122
- `,X="https://assets.certrev.com";function f(e){return typeof e=="string"?e:typeof e=="number"&&Number.isFinite(e)?String(e):""}function l(e){return f(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}var Ve=["assets.certrev.com","staging-assets.certrev.com"];function He(e){return`width=${e},height=${e},fit=cover,format=auto,onerror=redirect`}function Ke(e,t){let r=(e??"").trim();if(!/^https:\/\//i.test(r))return r;let n;try{n=new URL(r)}catch{return r}if(!Ve.includes(n.hostname)||n.pathname.startsWith("/cdn-cgi/image/"))return r;let o=n.pathname.replace(/^\//,"");return`${n.origin}/cdn-cgi/image/${He(t)}/${o}`}function Q(e,t){return Ke(e,t)}var ee="Independent editorial review of this article\u2019s text and sources. Not a product endorsement, nor medical advice.";var te=ee;function M(e){if(!e||typeof e!="string"&&!(e instanceof Date))return null;let t=e instanceof Date?e:new Date(e);return Number.isNaN(t.getTime())?null:t.toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric",timeZone:"UTC"})}var B=["M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z","M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z","M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z","M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"];function re(e,t){let r=B.map(n=>`<path fill="${t}" d="${n}"/>`).join("");return`<svg width="${e}" height="${e}" viewBox="0 0 375 375" aria-hidden="true" style="display:block;flex-shrink:0">${r}</svg>`}function ne(e=8){return`<svg width="${e}" height="${e}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>`}function oe(e="crm"){let t=`crm-stamp-arc-${e}`,r=B.map(n=>`<path fill="#0a1b3f" d="${n}"/>`).join("");return`<span class="crm-stamp"><svg viewBox="0 0 128 128" width="74" height="74" role="img" aria-label="CertREV verified stamp" style="display:block"><defs><path id="${t}" d="M64 18 A46 46 0 1 1 64 110 A46 46 0 1 1 64 18"/></defs><circle cx="64" cy="64" r="58" fill="none" stroke="#0a1b3f" stroke-width="1.3"/><circle cx="64" cy="64" r="51.5" fill="none" stroke="#0a1b3f" stroke-width="0.7" stroke-opacity="0.4"/><text font-family="'JetBrains Mono',ui-monospace,monospace" font-size="7.8" font-weight="600" letter-spacing="1.3" fill="#0a1b3f"><textPath href="#${t}" startOffset="1%">CERTREV VERIFIED \xB7 CERTIFIED \xB7 </textPath></text><svg x="49" y="50" width="30" height="28" viewBox="0 0 375 375" preserveAspectRatio="xMidYMid meet">${r}</svg></svg></span>`}var I=`
122
+ `,X="https://assets.certrev.com";function f(e){return typeof e=="string"?e:typeof e=="number"&&Number.isFinite(e)?String(e):""}function l(e){return f(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}var He=["assets.certrev.com","staging-assets.certrev.com"];function Ke(e){return`width=${e},height=${e},fit=cover,format=auto,onerror=redirect`}function qe(e,t){let r=(e??"").trim();if(!/^https:\/\//i.test(r))return r;let n;try{n=new URL(r)}catch{return r}if(!He.includes(n.hostname)||n.pathname.startsWith("/cdn-cgi/image/"))return r;let o=n.pathname.replace(/^\//,"");return`${n.origin}/cdn-cgi/image/${Ke(t)}/${o}`}function Q(e,t){return qe(e,t)}var ee="Independent editorial review of this article\u2019s text and sources. Not a product endorsement, nor medical advice.",te="Independent editorial review of this article\u2019s text. Not a product endorsement, nor medical advice.";var je=ee,Ge=te;function re(e){return e==="text"?Ge:je}function I(e){if(!e||typeof e!="string"&&!(e instanceof Date))return null;let t=e instanceof Date?e:new Date(e);return Number.isNaN(t.getTime())?null:t.toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric",timeZone:"UTC"})}var M=["M67.59 221.77L138.77 292.95C145.8 299.98 145.8 311.44 138.77 318.47L123.02 334.22C116 341.25 104.54 341.25 97.5 334.22L26.32 263.04C19.29 256.01 19.29 244.55 26.32 237.52L42.07 221.77C49.1 214.74 60.56 214.74 67.59 221.77Z","M96.79 335.08L81.12 319.42C73.8 312.1 73.8 300.23 81.12 292.92L315.88 58.16C323.2 50.85 335.06 50.85 342.38 58.16L358.04 73.83C365.36 81.14 365.36 93.01 358.04 100.33L123.29 335.08C115.97 342.4 104.1 342.4 96.79 335.08Z","M203.5 335.14L187.83 319.48C180.52 312.16 180.52 300.29 187.83 292.98L315.88 164.93C323.2 157.62 335.06 157.62 342.38 164.93L358.04 180.6C365.36 187.92 365.36 199.78 358.04 207.1L230 335.14C222.68 342.46 210.82 342.46 203.5 335.14Z","M310.21 335.2L294.54 319.54C287.23 312.22 287.23 300.36 294.54 293.04L315.88 271.71C323.2 264.39 335.06 264.39 342.38 271.71L358.04 287.37C365.36 294.69 365.36 306.55 358.04 313.87L336.71 335.2C329.39 342.52 317.53 342.52 310.21 335.2Z"];function ne(e,t){let r=M.map(n=>`<path fill="${t}" d="${n}"/>`).join("");return`<svg width="${e}" height="${e}" viewBox="0 0 375 375" aria-hidden="true" style="display:block;flex-shrink:0">${r}</svg>`}function oe(e=8){return`<svg width="${e}" height="${e}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>`}function ae(e="crm"){let t=`crm-stamp-arc-${e}`,r=M.map(n=>`<path fill="#0a1b3f" d="${n}"/>`).join("");return`<span class="crm-stamp"><svg viewBox="0 0 128 128" width="74" height="74" role="img" aria-label="CertREV verified stamp" style="display:block"><defs><path id="${t}" d="M64 18 A46 46 0 1 1 64 110 A46 46 0 1 1 64 18"/></defs><circle cx="64" cy="64" r="58" fill="none" stroke="#0a1b3f" stroke-width="1.3"/><circle cx="64" cy="64" r="51.5" fill="none" stroke="#0a1b3f" stroke-width="0.7" stroke-opacity="0.4"/><text font-family="'JetBrains Mono',ui-monospace,monospace" font-size="7.8" font-weight="600" letter-spacing="1.3" fill="#0a1b3f"><textPath href="#${t}" startOffset="1%">CERTREV VERIFIED \xB7 CERTIFIED \xB7 </textPath></text><svg x="49" y="50" width="30" height="28" viewBox="0 0 375 375" preserveAspectRatio="xMidYMid meet">${r}</svg></svg></span>`}var B=`
123
123
  :host {
124
124
  --cr-navy: #0a1b3f;
125
125
  --cr-lime: #d4e157;
@@ -552,6 +552,6 @@
552
552
  padding: 18px 18px 20px;
553
553
  }
554
554
  }
555
- `;var ae="nofollow sponsored noopener noreferrer",qe=/^(dr|prof|professor|mr|mrs|ms|mx|rev|sir|dame)\.?\s+/i;function ie(e){let t=f(e).replace(qe,"").trim(),r=t.indexOf(",");return(r===-1?t:t.slice(0,r)).trim()}function je(e){let t=ie(e).split(/\s+/).filter(Boolean);return t.length===0?"":t.length===1?t[0].slice(0,2).toUpperCase():(t[0][0]+t[t.length-1][0]).toUpperCase()}function Ge(e){return ie(e)}function Je(e){return f(e).replace(/^https?:\/\//i,"").replace(/\/$/,"")}function se(e){let t=f(e).trim();return t&&/^https?:\/\//i.test(t)?t:"#"}function Ze(e){return(f(e?.cardLabel)||f(e?.fullName)||f(e?.abbreviation)).trim()}function ce(e){let t=[],r=Array.isArray(e?.credentials)?e.credentials:[];for(let n of r){let o=Ze(n);o&&!t.includes(o)&&t.push(o)}return t}function We(e,t){return t?.showBio===!1?"":(f(e?.background)||f(e?.bio)).trim()}function le(e,t,r,n){let o=f(e?.photoUrl).trim();if(n&&/^https?:\/\//i.test(o)){let a=r.includes("--64")?64:56,s=Q(o,a===64?128:112);return`<img class="crm-avatar ${r}" src="${l(s)}" alt="" width="${a}" height="${a}" decoding="async">`}return`<span class="crm-avatar ${r}">${l(je(t))}</span>`}var fe='<button type="button" class="crm-close" data-certrev-modal-close aria-label="Close">&times;</button>';function de(e){return`<div class="crm-head">${re(16,"#ffffff")}<span class="crm-head__eyebrow">${l(e)}</span><span class="crm-head__wordmark">CertREV</span></div>`}function pe(e){return`<span class="${e}">${ne(8)}Certified</span>`}function ue(e){let t=f(e?.compensationCue).trim();return`<div class="crm-disclosure">${t?`<span class="crm-disclosure__cue">${l(t)}</span> `:""}${l(te)}</div>`}function me(e){let t=e.expert??null,r=f(t?.displayName).trim();if(!r)return null;let n=e.display?.showExpertPhoto!==!1,o=ce(t).join(" \xB7 "),a=M(e.certifiedAt)??"",s=f(e.displayCertId).trim(),i=f(e.articleTitle).trim(),c=f(e.verifyUrl).trim(),d=Ge(r),h=i?`<div class="crm-certifies"><div class="crm-certifies__eyebrow">Certifies the article</div><div class="crm-certifies__title">${l(i)}</div></div>`:"",x=s?`<div class="crm-meta__col"><div class="crm-meta__label">Certificate ID</div><div class="crm-meta__value crm-meta__value--mono">${l(s)}</div></div>`:"",Me=c?`<div class="crm-sig__url">${l(Je(c))}</div>`:"";return`${fe}${de("Certificate of Expert Review")}<div class="crm-body--cert"><div class="crm-expert-row">${le(t,r,"crm-avatar--56",n)}<div class="crm-expert-row__info"><div class="crm-expert-row__eyebrow">Reviewing Expert</div><div class="crm-expert-row__name">${l(r)}</div>${o?`<div class="crm-expert-row__creds">${l(o)}</div>`:""}</div></div>${h}<div class="crm-meta"><div class="crm-meta__col"><div class="crm-meta__label">Issued</div><div class="crm-meta__value">${l(a)}</div></div>${x}<div class="crm-meta__col"><div class="crm-meta__label">Status</div><div class="crm-meta__status">${pe("crm-chip")}</div></div></div><div class="crm-sig"><div><div class="crm-sig__name">${l(d)}</div><div class="crm-sig__rule"></div>${Me}</div>${oe("cert")}</div>${ue(t)}<div class="crm-actions"><a class="crm-cta" href="${l(se(c))}" target="_blank" rel="${ae}">View full certificate</a><button type="button" class="crm-ghost" data-certrev-modal-close>Close</button></div></div>`}function ye(e){let t=e.expert??null,r=f(t?.displayName).trim();if(!r)return null;let n=e.display?.showExpertPhoto!==!1,o=ce(t),a=We(t,e.display),s=M(e.certifiedAt),i=o.length?`<div class="crm-chips">${o.map(h=>`<span class="crm-chips__chip">${l(h)}</span>`).join("")}</div>`:"",c=a?`<p class="crm-bio">${l(a)}</p>`:"",d=s?`Independently reviewed \xB7 Certified ${l(s)}`:"Independently reviewed";return`${fe}${de("Verified reviewer")}<div class="crm-body--expert"><div class="crm-id">${le(t,r,"crm-avatar--64",n)}<div class="crm-id__info"><div class="crm-id__name">${l(r)}</div></div></div>${i}${c}<div class="crm-trust">${pe("crm-trust__chip")}<span class="crm-trust__text">${d}</span></div>${ue(t)}<div class="crm-actions"><a class="crm-cta" href="${l(se(t?.profileUrl))}" target="_blank" rel="${ae}">View full profile on CertREV</a><button type="button" class="crm-ghost" data-certrev-modal-close>Close</button></div></div>`}var w="certrev-cert-modal",ge="[data-certrev-cert]";function O(e){let t=e.closest(ge);for(let r=e;r;r=r.parentElement){let n=Array.from(r.querySelectorAll(w)).filter(o=>o.closest(ge)===t);if(n.length===1)return{modal:n[0],reason:null};if(n.length>1)return{modal:null,reason:"ambiguous",count:n.length};if(r===t)break}return{modal:null,reason:"none",count:0}}var E=null;function Ye(){return typeof CSSStyleSheet<"u"&&"replaceSync"in CSSStyleSheet.prototype&&"adoptedStyleSheets"in Document.prototype}function Xe(){return Ye()?(E||(E=new CSSStyleSheet,E.replaceSync(I)),E):null}var ve=!1;function Qe(e){if(ve||(ve=!0,e.querySelector("style[data-certrev-modal-fonts]")))return;if(!e.querySelector("link[data-certrev-modal-preconnect]")){let r=e.createElement("link");r.rel="preconnect",r.href=X,r.crossOrigin="",r.setAttribute("data-certrev-modal-preconnect",""),e.head.appendChild(r)}let t=e.createElement("style");t.textContent=Y,t.setAttribute("data-certrev-modal-fonts",""),e.head.appendChild(t)}var $=class extends HTMLElement{constructor(){super();this.rendered=!1;this.content=null;this.fetchInFlight=null;this.root=this.attachShadow({mode:"open"});let r=Xe();if(r)this.root.adoptedStyleSheets=[r];else{let n=document.createElement("style");n.textContent=I,this.root.appendChild(n)}this.root.addEventListener("click",n=>this.onShadowClick(n))}open(r){return this.getAttribute("data-fonts")!=="host"&&Qe(document),this.ensureRendered()?(this.show(r),!0):this.hasFetchSource()?(this.fetchThenShow(r),!0):!1}ensureRendered(){if(this.rendered)return this.content!=null;let r=this.readSyncContent();return r?(this.content=r,this.renderDialogs(r),this.rendered=!0,!0):!1}readSyncContent(){let r=this.getAttribute("data-envelope");if(r)return he(r);let n=this.querySelector("script[data-certrev-envelope]");return n?.textContent?he(n.textContent):null}hasFetchSource(){return!!(this.getAttribute("data-delivery-api")&&this.getAttribute("data-platform")&&this.getAttribute("data-external-id"))}async fetchThenShow(r){if(!this.fetchInFlight){let n=(this.getAttribute("data-delivery-api")||"").replace(/\/$/,""),o=this.getAttribute("data-platform")||"",a=this.getAttribute("data-external-id")||"";this.fetchInFlight=(async()=>{try{let s=await fetch(`${n}/api/cert/v1/delivery/${encodeURIComponent(o)}/${encodeURIComponent(a)}`,{cache:"no-store",credentials:"omit"});if(!s.ok)return;let i=await s.json();if(et(i)){this.markSuppressed();return}let c=v(i)?void 0:i.payload?.content;c&&(this.content=c,this.renderDialogs(c),this.rendered=!0)}catch{}})()}await this.fetchInFlight,this.rendered&&this.show(r)}renderDialogs(r){let n=me(r),o=ye(r),a=document.createElement("div");a.innerHTML=`${n?`<dialog id="cert" class="crm-dialog crm-dialog--cert" aria-label="CertREV certificate">${n}</dialog>`:""}${o?`<dialog id="expert" class="crm-dialog crm-dialog--expert" aria-label="Verified reviewer profile">${o}</dialog>`:""}`;for(let s of Array.from(a.childNodes))this.root.appendChild(s)}show(r){let n=this.root.getElementById(r);n&&typeof n.showModal=="function"&&!n.open&&n.showModal()}markSuppressed(){this.setAttribute("data-certrev-suppressed","");for(let r of Array.from(this.ownerDocument.querySelectorAll("[data-certrev-modal-open]")))O(r).modal===this&&(r.setAttribute("hidden",""),r.setAttribute("aria-hidden","true"))}onShadowClick(r){let n=r.target;if(!n)return;if(n instanceof HTMLDialogElement&&n.classList.contains("crm-dialog")){n.close();return}let o=n.closest("[data-certrev-modal-close]");o&&(r.preventDefault(),o.closest("dialog")?.close())}};function he(e){try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function et(e){if(!e)return!1;if(v(e))return!0;let t=e.payload?.lifecycle;return t?!!(t.revokedAt!=null||t.expiresAt&&Date.now()>=new Date(t.expiresAt).getTime()):!1}function tt(){typeof customElements>"u"||customElements.get(w)||customElements.define(w,$)}tt();var xe="data-certrev-acc",A="data-certrev-modal-open",N="data-certrev-initials";var rt="data-certrev-modal-unresolved",nt="certrev:modal-unresolved",ot=["avatar","certrev-memo__avatar"],Ce=new WeakSet;function be(e){let t=e.classList.toggle("open");e.setAttribute("aria-expanded",t?"true":"false")}function Ue(e){return e==="expert"?"expert":"cert"}function Ee(e,t){let r=O(e);if(r.modal){let n=r.modal;return typeof n.open=="function"?n.open(t):!1}return r.reason==="ambiguous"&&(e.setAttribute(rt,r.reason),e.dispatchEvent(new CustomEvent(nt,{bubbles:!0,detail:{reason:r.reason,modals:r.count}}))),!1}function we(e){return e&&e.closest?e:null}function Ae(e){let t=e.getAttribute(N);if(t==null)return;let r=ot.find(o=>e.classList.contains(o));if(!r)return;let n=e.ownerDocument.createElement("span");n.className=`${r} ${r}--initials`,n.setAttribute("aria-hidden","true"),n.textContent=t,e.replaceWith(n)}function at(e){for(let t of Array.from(e.querySelectorAll(`img[${N}]`)))t.complete&&t.naturalWidth===0&&Ae(t)}function it(e){Ce.has(e)||(Ce.add(e),e.addEventListener("click",t=>{let r=we(t.target);if(!r)return;let n=r.closest(`[${A}]`);if(n){Ee(n,Ue(n.getAttribute(A)))&&t.preventDefault();return}let o=r.closest(`[${xe}]`);o&&!r.closest("a, button")&&be(o)}),e.addEventListener("error",t=>{let r=t.target;r&&r.tagName==="IMG"&&r.hasAttribute(N)&&Ae(r)},!0),at(e),e.addEventListener("keydown",t=>{if(t.key!=="Enter"&&t.key!==" "&&t.key!=="Spacebar")return;let r=we(t.target);if(!r||r.closest("a, button"))return;let n=r.closest(`[${A}]`);if(n&&Ee(n,Ue(n.getAttribute(A)))){t.preventDefault();return}let o=r.closest(`[${xe}]`);o&&(t.preventDefault(),be(o))}))}function _e(e){let t=()=>it(e);e.readyState==="loading"?e.addEventListener("DOMContentLoaded",t,{once:!0}):t()}var st=[{selector:"main article",tier:"article"},{selector:"article",tier:"article"},{selector:"main",tier:"main"},{selector:".article-template__content",tier:"theme-class"},{selector:'[id^="ArticleContent"]',tier:"theme-class"},{selector:".rte",tier:"theme-class"}],y=[{selector:".article-template__content",tier:"theme-class"},{selector:'[id^="ArticleContent"]',tier:"theme-class"},{selector:".rte",tier:"theme-class"},{selector:"main article",tier:"article"},{selector:"article",tier:"article"},{selector:"main",tier:"main"}],P=y.map(e=>e.selector).join(", "),ct='header, [role="banner"], [class*="announcement"], footer, [role="contentinfo"], nav, [role="navigation"], cart-drawer, .cart-drawer, .drawer, .mini-cart, .modal, [role="dialog"]',u="data-certrev-placement",De="data-certrev-anchor",lt='script[type="application/ld+json"][data-certrev-graph]',ft=".certrev-card-wrap",Fe=".certrev-memo-wrap",dt=".certrev-pill-wrap",Te=384,pt=24,_="#references";function S(e){for(let t=e;t;t=t.parentElement){if(t.hasAttribute("hidden")||t.getAttribute("aria-hidden")==="true")return!1;let r=getComputedStyle(t);if(r.display==="none"||r.visibility==="hidden")return!1}return!0}function z(e){return e.closest(ct)!==null}function Se(e,t){for(let{selector:r,tier:n}of t)if(e.matches(r))return n;return"article"}function D(e,t,r){for(let{selector:n,tier:o}of r)for(let a of Array.from(e.querySelectorAll(n)))if(a!==t&&!a.contains(t)&&!t.contains(a)&&S(a)&&!z(a))return{el:a,tier:o};return null}function V(e,t){let r=t.getAttribute(u);if(r)return{anchored:r!=="body-fallback",tier:r};let n=t.getAttribute(De);if(n==="rail"){let i=e.querySelector(_)?.closest(P)??D(e,t,y)?.el??null,c=e.defaultView;if(i&&c&&S(i)&&!z(i)){let d=i.getBoundingClientRect();if(c.innerWidth-d.right>=Te)return t.style.setProperty("--certrev-rail-left",`${Math.round(d.right+pt)}px`),t.setAttribute(u,"rail"),{anchored:!0,tier:"rail"};i.insertAdjacentElement("afterbegin",t);let x=Se(i,y);return t.setAttribute(u,x),{anchored:!0,tier:x}}return t.setAttribute(u,"body-fallback"),{anchored:!1,tier:"body-fallback"}}let o=n==="bottom"?"bottom":"top",a="body-fallback";if(o==="top"){let i=e.querySelector(_)?.closest(P)??null;if(i&&i!==t&&!i.contains(t)&&!t.contains(i)&&S(i)&&!z(i))i.insertAdjacentElement("afterbegin",t),a=Se(i,y);else{let c=D(e,t,y);c&&(c.el.insertAdjacentElement("afterbegin",t),a=c.tier)}}else{let s=e.querySelector(_);if(s&&s!==t&&!t.contains(s)&&!s.contains(t)&&S(s))s.insertAdjacentElement("beforebegin",t),a="references";else{let i=D(e,t,st);i&&(i.el.insertAdjacentElement("afterend",t),a=i.tier)}}return t.setAttribute(u,a),{anchored:a!=="body-fallback",tier:a}}function ut(e){let t=e.querySelector(lt),r=!1;t&&t.parentNode!==e.head&&(e.head.appendChild(t),r=!0);let n=e.querySelector(ft),o=e.querySelector(Fe);return e.querySelector(dt)?.setAttribute(u,"pill-fixed"),{graph:r,card:n?V(e,n):null,memo:o?V(e,o):null}}function mt(e){let t=e.defaultView;if(!t)return;let r=e.querySelector(`${Fe}[${De}="rail"]`);if(!r||r.getAttribute(u)!=="rail")return;let n,o=()=>{n&&clearTimeout(n),n=setTimeout(()=>{if(r.getAttribute(u)!=="rail"){t.removeEventListener("resize",o);return}let s=e.querySelector(_)?.closest(P)??D(e,r,y)?.el??null;(s?t.innerWidth-s.getBoundingClientRect().right:0)<Te&&(r.style.removeProperty("--certrev-rail-left"),r.removeAttribute(u),V(e,r),t.removeEventListener("resize",o))},150)};t.addEventListener("resize",o)}function Re(e){let t=()=>{ut(e),mt(e)};e.readyState==="loading"?e.addEventListener("DOMContentLoaded",t,{once:!0}):t()}async function yt(e,t){let r=e.querySelector(".certrev-badge");if(!r)return;let n=e.getAttribute("data-delivery-api"),o=e.getAttribute("data-external-id"),a=e.getAttribute("data-platform")??"shopify";if(!n||!o)return;let s;try{s=await t.verify({baseUrl:n,platform:a,externalId:o})}catch{return}s.decision!=="render"&&(r.setAttribute("hidden",""),r.setAttribute("data-certrev-suppressed",s.reason))}function ke(e,t){let r=()=>{for(let n of Array.from(e.querySelectorAll("certrev-badge[revalidate]")))yt(n,t)};e.readyState==="loading"?e.addEventListener("DOMContentLoaded",r,{once:!0}):r()}function Le(e,t=fetch){return async r=>{let o=`${r.baseUrl.replace(/\/+$/,"")}/api/cert/v1/delivery/${encodeURIComponent(r.platform)}/${encodeURIComponent(r.externalId)}`,a=await t(o,{headers:{accept:"application/json"}});if(!a.ok)throw new Error(`cert delivery ${a.status}`);let s=await a.json();return L(s,e,{platform:r.platform,externalId:r.externalId,liveContentHash:null,now:new Date})}}var gt="cert-issuer-1",vt=`-----BEGIN PUBLIC KEY-----
555
+ `;var ie="nofollow sponsored noopener noreferrer",Je=/^(dr|prof|professor|mr|mrs|ms|mx|rev|sir|dame)\.?\s+/i;function se(e){let t=f(e).replace(Je,"").trim(),r=t.indexOf(",");return(r===-1?t:t.slice(0,r)).trim()}function Ze(e){let t=se(e).split(/\s+/).filter(Boolean);return t.length===0?"":t.length===1?t[0].slice(0,2).toUpperCase():(t[0][0]+t[t.length-1][0]).toUpperCase()}function We(e){return se(e)}function Ye(e){return f(e).replace(/^https?:\/\//i,"").replace(/\/$/,"")}function ce(e){let t=f(e).trim();return t&&/^https?:\/\//i.test(t)?t:"#"}function Xe(e){return(f(e?.cardLabel)||f(e?.fullName)||f(e?.abbreviation)).trim()}function le(e){let t=[],r=Array.isArray(e?.credentials)?e.credentials:[];for(let n of r){let o=Xe(n);o&&!t.includes(o)&&t.push(o)}return t}function Qe(e,t){return t?.showBio===!1?"":(f(e?.background)||f(e?.bio)).trim()}function fe(e,t,r,n){let o=f(e?.photoUrl).trim();if(n&&/^https?:\/\//i.test(o)){let a=r.includes("--64")?64:56,s=Q(o,a===64?128:112);return`<img class="crm-avatar ${r}" src="${l(s)}" alt="" width="${a}" height="${a}" decoding="async">`}return`<span class="crm-avatar ${r}">${l(Ze(t))}</span>`}var de='<button type="button" class="crm-close" data-certrev-modal-close aria-label="Close">&times;</button>';function pe(e){return`<div class="crm-head">${ne(16,"#ffffff")}<span class="crm-head__eyebrow">${l(e)}</span><span class="crm-head__wordmark">CertREV</span></div>`}function ue(e){return`<span class="${e}">${oe(8)}Certified</span>`}function me(e){let t=f(e?.compensationCue).trim();return`<div class="crm-disclosure">${t?`<span class="crm-disclosure__cue">${l(t)}</span> `:""}${l(re(e?.reviewScope))}</div>`}function ye(e){let t=e.expert??null,r=f(t?.displayName).trim();if(!r)return null;let n=e.display?.showExpertPhoto!==!1,o=le(t).join(" \xB7 "),a=I(e.certifiedAt)??"",s=f(e.displayCertId).trim(),i=f(e.articleTitle).trim(),c=f(e.verifyUrl).trim(),d=We(r),h=i?`<div class="crm-certifies"><div class="crm-certifies__eyebrow">Certifies the article</div><div class="crm-certifies__title">${l(i)}</div></div>`:"",x=s?`<div class="crm-meta__col"><div class="crm-meta__label">Certificate ID</div><div class="crm-meta__value crm-meta__value--mono">${l(s)}</div></div>`:"",Me=c?`<div class="crm-sig__url">${l(Ye(c))}</div>`:"";return`${de}${pe("Certificate of Expert Review")}<div class="crm-body--cert"><div class="crm-expert-row">${fe(t,r,"crm-avatar--56",n)}<div class="crm-expert-row__info"><div class="crm-expert-row__eyebrow">Reviewing Expert</div><div class="crm-expert-row__name">${l(r)}</div>${o?`<div class="crm-expert-row__creds">${l(o)}</div>`:""}</div></div>${h}<div class="crm-meta"><div class="crm-meta__col"><div class="crm-meta__label">Issued</div><div class="crm-meta__value">${l(a)}</div></div>${x}<div class="crm-meta__col"><div class="crm-meta__label">Status</div><div class="crm-meta__status">${ue("crm-chip")}</div></div></div><div class="crm-sig"><div><div class="crm-sig__name">${l(d)}</div><div class="crm-sig__rule"></div>${Me}</div>${ae("cert")}</div>${me(t)}<div class="crm-actions"><a class="crm-cta" href="${l(ce(c))}" target="_blank" rel="${ie}">View full certificate</a><button type="button" class="crm-ghost" data-certrev-modal-close>Close</button></div></div>`}function ge(e){let t=e.expert??null,r=f(t?.displayName).trim();if(!r)return null;let n=e.display?.showExpertPhoto!==!1,o=le(t),a=Qe(t,e.display),s=I(e.certifiedAt),i=o.length?`<div class="crm-chips">${o.map(h=>`<span class="crm-chips__chip">${l(h)}</span>`).join("")}</div>`:"",c=a?`<p class="crm-bio">${l(a)}</p>`:"",d=s?`Independently reviewed \xB7 Certified ${l(s)}`:"Independently reviewed";return`${de}${pe("Verified reviewer")}<div class="crm-body--expert"><div class="crm-id">${fe(t,r,"crm-avatar--64",n)}<div class="crm-id__info"><div class="crm-id__name">${l(r)}</div></div></div>${i}${c}<div class="crm-trust">${ue("crm-trust__chip")}<span class="crm-trust__text">${d}</span></div>${me(t)}<div class="crm-actions"><a class="crm-cta" href="${l(ce(t?.profileUrl))}" target="_blank" rel="${ie}">View full profile on CertREV</a><button type="button" class="crm-ghost" data-certrev-modal-close>Close</button></div></div>`}var w="certrev-cert-modal",ve="[data-certrev-cert]";function O(e){let t=e.closest(ve);for(let r=e;r;r=r.parentElement){let n=Array.from(r.querySelectorAll(w)).filter(o=>o.closest(ve)===t);if(n.length===1)return{modal:n[0],reason:null};if(n.length>1)return{modal:null,reason:"ambiguous",count:n.length};if(r===t)break}return{modal:null,reason:"none",count:0}}var U=null;function et(){return typeof CSSStyleSheet<"u"&&"replaceSync"in CSSStyleSheet.prototype&&"adoptedStyleSheets"in Document.prototype}function tt(){return et()?(U||(U=new CSSStyleSheet,U.replaceSync(B)),U):null}var he=!1;function rt(e){if(he||(he=!0,e.querySelector("style[data-certrev-modal-fonts]")))return;if(!e.querySelector("link[data-certrev-modal-preconnect]")){let r=e.createElement("link");r.rel="preconnect",r.href=X,r.crossOrigin="",r.setAttribute("data-certrev-modal-preconnect",""),e.head.appendChild(r)}let t=e.createElement("style");t.textContent=Y,t.setAttribute("data-certrev-modal-fonts",""),e.head.appendChild(t)}var $=class extends HTMLElement{constructor(){super();this.rendered=!1;this.content=null;this.fetchInFlight=null;this.root=this.attachShadow({mode:"open"});let r=tt();if(r)this.root.adoptedStyleSheets=[r];else{let n=document.createElement("style");n.textContent=B,this.root.appendChild(n)}this.root.addEventListener("click",n=>this.onShadowClick(n))}open(r){return this.getAttribute("data-fonts")!=="host"&&rt(document),this.ensureRendered()?(this.show(r),!0):this.hasFetchSource()?(this.fetchThenShow(r),!0):!1}ensureRendered(){if(this.rendered)return this.content!=null;let r=this.readSyncContent();return r?(this.content=r,this.renderDialogs(r),this.rendered=!0,!0):!1}readSyncContent(){let r=this.getAttribute("data-envelope");if(r)return xe(r);let n=this.querySelector("script[data-certrev-envelope]");return n?.textContent?xe(n.textContent):null}hasFetchSource(){return!!(this.getAttribute("data-delivery-api")&&this.getAttribute("data-platform")&&this.getAttribute("data-external-id"))}async fetchThenShow(r){if(!this.fetchInFlight){let n=(this.getAttribute("data-delivery-api")||"").replace(/\/$/,""),o=this.getAttribute("data-platform")||"",a=this.getAttribute("data-external-id")||"";this.fetchInFlight=(async()=>{try{let s=await fetch(`${n}/api/cert/v1/delivery/${encodeURIComponent(o)}/${encodeURIComponent(a)}`,{cache:"no-store",credentials:"omit"});if(!s.ok)return;let i=await s.json();if(nt(i)){this.markSuppressed();return}let c=v(i)?void 0:i.payload?.content;c&&(this.content=c,this.renderDialogs(c),this.rendered=!0)}catch{}})()}await this.fetchInFlight,this.rendered&&this.show(r)}renderDialogs(r){let n=ye(r),o=ge(r),a=document.createElement("div");a.innerHTML=`${n?`<dialog id="cert" class="crm-dialog crm-dialog--cert" aria-label="CertREV certificate">${n}</dialog>`:""}${o?`<dialog id="expert" class="crm-dialog crm-dialog--expert" aria-label="Verified reviewer profile">${o}</dialog>`:""}`;for(let s of Array.from(a.childNodes))this.root.appendChild(s)}show(r){let n=this.root.getElementById(r);n&&typeof n.showModal=="function"&&!n.open&&n.showModal()}markSuppressed(){this.setAttribute("data-certrev-suppressed","");for(let r of Array.from(this.ownerDocument.querySelectorAll("[data-certrev-modal-open]")))O(r).modal===this&&(r.setAttribute("hidden",""),r.setAttribute("aria-hidden","true"))}onShadowClick(r){let n=r.target;if(!n)return;if(n instanceof HTMLDialogElement&&n.classList.contains("crm-dialog")){n.close();return}let o=n.closest("[data-certrev-modal-close]");o&&(r.preventDefault(),o.closest("dialog")?.close())}};function xe(e){try{let t=JSON.parse(e);return t&&typeof t=="object"?t:null}catch{return null}}function nt(e){if(!e)return!1;if(v(e))return!0;let t=e.payload?.lifecycle;return t?!!(t.revokedAt!=null||t.expiresAt&&Date.now()>=new Date(t.expiresAt).getTime()):!1}function ot(){typeof customElements>"u"||customElements.get(w)||customElements.define(w,$)}ot();var Ce="data-certrev-acc",A="data-certrev-modal-open",N="data-certrev-initials";var at="data-certrev-modal-unresolved",it="certrev:modal-unresolved",st=["avatar","certrev-memo__avatar"],be=new WeakSet;function Ee(e){let t=e.classList.toggle("open");e.setAttribute("aria-expanded",t?"true":"false")}function Ue(e){return e==="expert"?"expert":"cert"}function we(e,t){let r=O(e);if(r.modal){let n=r.modal;return typeof n.open=="function"?n.open(t):!1}return r.reason==="ambiguous"&&(e.setAttribute(at,r.reason),e.dispatchEvent(new CustomEvent(it,{bubbles:!0,detail:{reason:r.reason,modals:r.count}}))),!1}function Ae(e){return e&&e.closest?e:null}function _e(e){let t=e.getAttribute(N);if(t==null)return;let r=st.find(o=>e.classList.contains(o));if(!r)return;let n=e.ownerDocument.createElement("span");n.className=`${r} ${r}--initials`,n.setAttribute("aria-hidden","true"),n.textContent=t,e.replaceWith(n)}function ct(e){for(let t of Array.from(e.querySelectorAll(`img[${N}]`)))t.complete&&t.naturalWidth===0&&_e(t)}function lt(e){be.has(e)||(be.add(e),e.addEventListener("click",t=>{let r=Ae(t.target);if(!r)return;let n=r.closest(`[${A}]`);if(n){we(n,Ue(n.getAttribute(A)))&&t.preventDefault();return}let o=r.closest(`[${Ce}]`);o&&!r.closest("a, button")&&Ee(o)}),e.addEventListener("error",t=>{let r=t.target;r&&r.tagName==="IMG"&&r.hasAttribute(N)&&_e(r)},!0),ct(e),e.addEventListener("keydown",t=>{if(t.key!=="Enter"&&t.key!==" "&&t.key!=="Spacebar")return;let r=Ae(t.target);if(!r||r.closest("a, button"))return;let n=r.closest(`[${A}]`);if(n&&we(n,Ue(n.getAttribute(A)))){t.preventDefault();return}let o=r.closest(`[${Ce}]`);o&&(t.preventDefault(),Ee(o))}))}function Se(e){let t=()=>lt(e);e.readyState==="loading"?e.addEventListener("DOMContentLoaded",t,{once:!0}):t()}var ft=[{selector:"main article",tier:"article"},{selector:"article",tier:"article"},{selector:"main",tier:"main"},{selector:".article-template__content",tier:"theme-class"},{selector:'[id^="ArticleContent"]',tier:"theme-class"},{selector:".rte",tier:"theme-class"}],y=[{selector:".article-template__content",tier:"theme-class"},{selector:'[id^="ArticleContent"]',tier:"theme-class"},{selector:".rte",tier:"theme-class"},{selector:"main article",tier:"article"},{selector:"article",tier:"article"},{selector:"main",tier:"main"}],P=y.map(e=>e.selector).join(", "),dt='header, [role="banner"], [class*="announcement"], footer, [role="contentinfo"], nav, [role="navigation"], cart-drawer, .cart-drawer, .drawer, .mini-cart, .modal, [role="dialog"]',u="data-certrev-placement",Te="data-certrev-anchor",pt='script[type="application/ld+json"][data-certrev-graph]',ut=".certrev-card-wrap",Fe=".certrev-memo-wrap",mt=".certrev-pill-wrap",Re=384,yt=24,_="#references";function S(e){for(let t=e;t;t=t.parentElement){if(t.hasAttribute("hidden")||t.getAttribute("aria-hidden")==="true")return!1;let r=getComputedStyle(t);if(r.display==="none"||r.visibility==="hidden")return!1}return!0}function z(e){return e.closest(dt)!==null}function De(e,t){for(let{selector:r,tier:n}of t)if(e.matches(r))return n;return"article"}function D(e,t,r){for(let{selector:n,tier:o}of r)for(let a of Array.from(e.querySelectorAll(n)))if(a!==t&&!a.contains(t)&&!t.contains(a)&&S(a)&&!z(a))return{el:a,tier:o};return null}function V(e,t){let r=t.getAttribute(u);if(r)return{anchored:r!=="body-fallback",tier:r};let n=t.getAttribute(Te);if(n==="rail"){let i=e.querySelector(_)?.closest(P)??D(e,t,y)?.el??null,c=e.defaultView;if(i&&c&&S(i)&&!z(i)){let d=i.getBoundingClientRect();if(c.innerWidth-d.right>=Re)return t.style.setProperty("--certrev-rail-left",`${Math.round(d.right+yt)}px`),t.setAttribute(u,"rail"),{anchored:!0,tier:"rail"};i.insertAdjacentElement("afterbegin",t);let x=De(i,y);return t.setAttribute(u,x),{anchored:!0,tier:x}}return t.setAttribute(u,"body-fallback"),{anchored:!1,tier:"body-fallback"}}let o=n==="bottom"?"bottom":"top",a="body-fallback";if(o==="top"){let i=e.querySelector(_)?.closest(P)??null;if(i&&i!==t&&!i.contains(t)&&!t.contains(i)&&S(i)&&!z(i))i.insertAdjacentElement("afterbegin",t),a=De(i,y);else{let c=D(e,t,y);c&&(c.el.insertAdjacentElement("afterbegin",t),a=c.tier)}}else{let s=e.querySelector(_);if(s&&s!==t&&!t.contains(s)&&!s.contains(t)&&S(s))s.insertAdjacentElement("beforebegin",t),a="references";else{let i=D(e,t,ft);i&&(i.el.insertAdjacentElement("afterend",t),a=i.tier)}}return t.setAttribute(u,a),{anchored:a!=="body-fallback",tier:a}}function gt(e){let t=e.querySelector(pt),r=!1;t&&t.parentNode!==e.head&&(e.head.appendChild(t),r=!0);let n=e.querySelector(ut),o=e.querySelector(Fe);return e.querySelector(mt)?.setAttribute(u,"pill-fixed"),{graph:r,card:n?V(e,n):null,memo:o?V(e,o):null}}function vt(e){let t=e.defaultView;if(!t)return;let r=e.querySelector(`${Fe}[${Te}="rail"]`);if(!r||r.getAttribute(u)!=="rail")return;let n,o=()=>{n&&clearTimeout(n),n=setTimeout(()=>{if(r.getAttribute(u)!=="rail"){t.removeEventListener("resize",o);return}let s=e.querySelector(_)?.closest(P)??D(e,r,y)?.el??null;(s?t.innerWidth-s.getBoundingClientRect().right:0)<Re&&(r.style.removeProperty("--certrev-rail-left"),r.removeAttribute(u),V(e,r),t.removeEventListener("resize",o))},150)};t.addEventListener("resize",o)}function ke(e){let t=()=>{gt(e),vt(e)};e.readyState==="loading"?e.addEventListener("DOMContentLoaded",t,{once:!0}):t()}async function ht(e,t){let r=e.querySelector(".certrev-badge");if(!r)return;let n=e.getAttribute("data-delivery-api"),o=e.getAttribute("data-external-id"),a=e.getAttribute("data-platform")??"shopify";if(!n||!o)return;let s;try{s=await t.verify({baseUrl:n,platform:a,externalId:o})}catch{return}s.decision!=="render"&&(r.setAttribute("hidden",""),r.setAttribute("data-certrev-suppressed",s.reason))}function Le(e,t){let r=()=>{for(let n of Array.from(e.querySelectorAll("certrev-badge[revalidate]")))ht(n,t)};e.readyState==="loading"?e.addEventListener("DOMContentLoaded",r,{once:!0}):r()}function Ie(e,t=fetch){return async r=>{let o=`${r.baseUrl.replace(/\/+$/,"")}/api/cert/v1/delivery/${encodeURIComponent(r.platform)}/${encodeURIComponent(r.externalId)}`,a=await t(o,{headers:{accept:"application/json"}});if(!a.ok)throw new Error(`cert delivery ${a.status}`);let s=await a.json();return L(s,e,{platform:r.platform,externalId:r.externalId,liveContentHash:null,now:new Date})}}var xt="cert-issuer-1",Ct=`-----BEGIN PUBLIC KEY-----
556
556
  MCowBQYDK2VwAyEAMWN956IOPjpAq900dL428VzA28TO/pVXnq3brwqUmwM=
557
- -----END PUBLIC KEY-----`,ht=e=>e===gt?{format:"pem",pem:vt}:null;typeof document<"u"&&(Re(document),_e(document),ke(document,{verify:Le(ht)}));})();
557
+ -----END PUBLIC KEY-----`,bt=e=>e===xt?{format:"pem",pem:Ct}:null;typeof document<"u"&&(ke(document),Se(document),Le(document,{verify:Ie(bt)}));})();
@@ -17,6 +17,15 @@
17
17
  export declare const COMPENSATED_EXPERT_CUE = "Compensated expert";
18
18
  /** The FTC scope disclaimer, re-exported from the FTC SoT (portal `CERT_SCOPE_LINE = FTC_DISCLOSURE_LINE`). */
19
19
  export declare const CERT_SCOPE_LINE: "Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.";
20
+ /** 2.1.0: the text-only scope line (portal `FTC_DISCLOSURE_LINE_TEXT_ONLY`), for a review that covered the text only. */
21
+ export declare const CERT_SCOPE_LINE_TEXT_ONLY: "Independent editorial review of this article’s text. Not a product endorsement, nor medical advice.";
22
+ /**
23
+ * 2.1.0: the scope line for the signed `content.expert.reviewScope`. Only an exact `"text"` is the text-only line; absent,
24
+ * null, `"text_and_sources"` or any other value is `CERT_SCOPE_LINE`, as 2.0.2 printed it. The same rule as
25
+ * `certScopeLineFor` in `../components/render-def.ts`, repeated because `src/modal/` imports nothing from `src/components/`
26
+ * (it is bundled standalone into `certrev-cert.js`).
27
+ */
28
+ export declare function scopeLineForReview(reviewScope: unknown): typeof CERT_SCOPE_LINE | typeof CERT_SCOPE_LINE_TEXT_ONLY;
20
29
  /**
21
30
  * Format a timestamp the way every cert byline renders dates ("Jun 14, 2026", en-US short month,
22
31
  * UTC-pinned). Null for an unparseable input — callers treat that as "no date, no byline".
@@ -1 +1 @@
1
- {"version":3,"file":"display-strings.d.ts","sourceRoot":"","sources":["../../src/modal/display-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,iGAAiG;AACjG,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAE3D,+GAA+G;AAC/G,eAAO,MAAM,eAAe,mHAAsB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,GAAG,IAAI,CAWf"}
1
+ {"version":3,"file":"display-strings.d.ts","sourceRoot":"","sources":["../../src/modal/display-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,iGAAiG;AACjG,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAE3D,+GAA+G;AAC/G,eAAO,MAAM,eAAe,mHAAsB,CAAC;AAEnD,yHAAyH;AACzH,eAAO,MAAM,yBAAyB,uGAAgC,CAAC;AAEvE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,eAAe,GAAG,OAAO,yBAAyB,CAElH;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,GACnC,MAAM,GAAG,IAAI,CAWf"}
@@ -13,11 +13,22 @@
13
13
  * every well-formed value renders the exact string portal renders, and a value the wire could
14
14
  * never legitimately carry renders nothing (see `formatCertDisplayDate`).
15
15
  */
16
- import { FTC_DISCLOSURE_LINE } from "./ftc-disclosure.js";
16
+ import { FTC_DISCLOSURE_LINE, FTC_DISCLOSURE_LINE_TEXT_ONLY } from "./ftc-disclosure.js";
17
17
  /** The compensation cue (guide "line A"), byte-verbatim from portal `COMPENSATED_EXPERT_CUE`. */
18
18
  export const COMPENSATED_EXPERT_CUE = "Compensated expert";
19
19
  /** The FTC scope disclaimer, re-exported from the FTC SoT (portal `CERT_SCOPE_LINE = FTC_DISCLOSURE_LINE`). */
20
20
  export const CERT_SCOPE_LINE = FTC_DISCLOSURE_LINE;
21
+ /** 2.1.0: the text-only scope line (portal `FTC_DISCLOSURE_LINE_TEXT_ONLY`), for a review that covered the text only. */
22
+ export const CERT_SCOPE_LINE_TEXT_ONLY = FTC_DISCLOSURE_LINE_TEXT_ONLY;
23
+ /**
24
+ * 2.1.0: the scope line for the signed `content.expert.reviewScope`. Only an exact `"text"` is the text-only line; absent,
25
+ * null, `"text_and_sources"` or any other value is `CERT_SCOPE_LINE`, as 2.0.2 printed it. The same rule as
26
+ * `certScopeLineFor` in `../components/render-def.ts`, repeated because `src/modal/` imports nothing from `src/components/`
27
+ * (it is bundled standalone into `certrev-cert.js`).
28
+ */
29
+ export function scopeLineForReview(reviewScope) {
30
+ return reviewScope === "text" ? CERT_SCOPE_LINE_TEXT_ONLY : CERT_SCOPE_LINE;
31
+ }
21
32
  /**
22
33
  * Format a timestamp the way every cert byline renders dates ("Jun 14, 2026", en-US short month,
23
34
  * UTC-pinned). Null for an unparseable input — callers treat that as "no date, no byline".
@@ -1 +1 @@
1
- {"version":3,"file":"display-strings.js","sourceRoot":"","sources":["../../src/modal/display-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,iGAAiG;AACjG,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D,+GAA+G;AAC/G,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,qBAAqB,CACpC,GAAqC;IAErC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,YAAY,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnE,MAAM,IAAI,GAAG,GAAG,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE;QACvC,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,KAAK;KACf,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"display-strings.js","sourceRoot":"","sources":["../../src/modal/display-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAEzF,iGAAiG;AACjG,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D,+GAA+G;AAC/G,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAEnD,yHAAyH;AACzH,MAAM,CAAC,MAAM,yBAAyB,GAAG,6BAA6B,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAoB;IACtD,OAAO,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,eAAe,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,qBAAqB,CACpC,GAAqC;IAErC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,GAAG,YAAY,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnE,MAAM,IAAI,GAAG,GAAG,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACvD,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE;QACvC,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,KAAK;KACf,CAAC,CAAC;AACJ,CAAC"}
@@ -13,4 +13,10 @@
13
13
  * its disclosure is settled where the face is configured, not by hiding or replacing it in the page.
14
14
  */
15
15
  export declare const FTC_DISCLOSURE_LINE: "Independent editorial review of this article\u2019s text and sources. Not a product endorsement, nor medical advice.";
16
+ /**
17
+ * 2.1.0: the line for an article whose review covered its TEXT only (no references or sources section): a byte-faithful
18
+ * copy of the portal's `FTC_DISCLOSURE_LINE_TEXT_ONLY` (Owen, Console decision af5b0db5). Same contract status and curly
19
+ * apostrophe as `FTC_DISCLOSURE_LINE`.
20
+ */
21
+ export declare const FTC_DISCLOSURE_LINE_TEXT_ONLY: "Independent editorial review of this article\u2019s text. Not a product endorsement, nor medical advice.";
16
22
  //# sourceMappingURL=ftc-disclosure.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ftc-disclosure.d.ts","sourceRoot":"","sources":["../../src/modal/ftc-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,eAAO,MAAM,mBAAmB,EAC/B,sHAA0H,CAAC"}
1
+ {"version":3,"file":"ftc-disclosure.d.ts","sourceRoot":"","sources":["../../src/modal/ftc-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,eAAO,MAAM,mBAAmB,EAC/B,sHAA0H,CAAC;AAE5H;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,EACzC,0GAA8G,CAAC"}
@@ -13,4 +13,10 @@
13
13
  * its disclosure is settled where the face is configured, not by hiding or replacing it in the page.
14
14
  */
15
15
  export const FTC_DISCLOSURE_LINE = "Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.";
16
+ /**
17
+ * 2.1.0: the line for an article whose review covered its TEXT only (no references or sources section): a byte-faithful
18
+ * copy of the portal's `FTC_DISCLOSURE_LINE_TEXT_ONLY` (Owen, Console decision af5b0db5). Same contract status and curly
19
+ * apostrophe as `FTC_DISCLOSURE_LINE`.
20
+ */
21
+ export const FTC_DISCLOSURE_LINE_TEXT_ONLY = "Independent editorial review of this article’s text. Not a product endorsement, nor medical advice.";
16
22
  //# sourceMappingURL=ftc-disclosure.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ftc-disclosure.js","sourceRoot":"","sources":["../../src/modal/ftc-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAC/B,iHAA0H,CAAC"}
1
+ {"version":3,"file":"ftc-disclosure.js","sourceRoot":"","sources":["../../src/modal/ftc-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAC/B,iHAA0H,CAAC;AAE5H;;;;GAIG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACzC,qGAA8G,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/reader/render.ts"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAmBxD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAA;AAE5D,wHAAwH;AACxH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEnD,MAAM,WAAW,eAAe;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,sGAAsG;IACtG,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,+FAA+F;IAC/F,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAA;IAC1B,2GAA2G;IAC3G,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,8FAA8F;IAC9F,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAC/B;AAoSD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAQ/D"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/reader/render.ts"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAmBxD,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAA;AAE5D,wHAAwH;AACxH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEnD,MAAM,WAAW,eAAe;IAC/B,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,sGAAsG;IACtG,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,+FAA+F;IAC/F,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAA;IAC1B,2GAA2G;IAC3G,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,8FAA8F;IAC9F,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAC/B;AAqSD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAQ/D"}
@@ -49,7 +49,7 @@
49
49
  */
50
50
  import { asText } from '../components/escape.js';
51
51
  import { CERTREV_LINK_REL } from '../components/rel.js';
52
- import { CERT_SCOPE_LINE, CERT_STRINGS_VERSION, COMPENSATED_EXPERT_CUE } from '../components/render-def.js';
52
+ import { CERT_STRINGS_VERSION, COMPENSATED_EXPERT_CUE, certScopeLineFor } from '../components/render-def.js';
53
53
  import { readerFace } from './face.js';
54
54
  import { cleaned, contains, esc, firstName, isBlank, isPresent, isTruthy, longDate, rec, safeUrl, textOr, } from './helpers.js';
55
55
  import { readerLogo } from './logo.js';
@@ -87,6 +87,7 @@ function readFacts(input) {
87
87
  showPhoto,
88
88
  creds: rung === 'named' || minimal ? '' : labels.join(', '),
89
89
  hasCue,
90
+ scope: certScopeLineFor(expert.reviewScope),
90
91
  illus: input.illustrative === true && !hasCue,
91
92
  hasMemo: !isBlank(content.memo) && rung === 'memo',
92
93
  toned: isTonedStyle(style),
@@ -128,12 +129,6 @@ function scopeLead(f) {
128
129
  return '<em>Illustrative example</em> · <!-- -->';
129
130
  return '';
130
131
  }
131
- /**
132
- * The scope sentence is DIRECT text of the scope element (the demo's `<span class="dg-scope">`), which carries the
133
- * `data-ftc-line` marker itself: no inner span, so the element's `.certrev-r-scope em` cue and the sentence are leaves of
134
- * one element, as the demo paints them. The marker is on exactly one element per render, as before.
135
- */
136
- const SCOPE = CERT_SCOPE_LINE;
137
132
  /**
138
133
  * The muted credential line, empty when the reviewer has no displayed credential (so no "verified" claim prints).
139
134
  *
@@ -208,7 +203,7 @@ function bannerCard(f) {
208
203
  foot = `<div class="certrev-r-foot">${when}${cue}</div>`;
209
204
  }
210
205
  // POR-9317: the memo card carries the scope line when there is a memo; with none this card is the sole claim face.
211
- const scope = scopeOn ? `<div class="certrev-r-scope" data-ftc-disclosure data-ftc-line>${SCOPE}</div>` : '';
206
+ const scope = scopeOn ? `<div class="certrev-r-scope" data-ftc-disclosure data-ftc-line>${f.scope}</div>` : '';
212
207
  return (`${sectionOpen(f, true, f.minimal ? 'Expert reviewed' : credentialAria(f))}\n <div class="certrev-r-card">\n` +
213
208
  ` <div class="certrev-r-cap">${readerLogo(f.fg === '#ffffff' ? 'white' : 'mono', 18, 'CertREV')}Expert reviewed${f.minimal ? '' : ' &amp; certified'}</div>\n` +
214
209
  ` <div class="certrev-r-cap-body">\n ${bys}` +
@@ -231,7 +226,7 @@ function bannerMemo(f) {
231
226
  ` <blockquote>${esc(f.content.memo)}</blockquote>${links}</div>\n </div>\n` +
232
227
  ' <div class="certrev-r-rule"></div>\n <div class="certrev-r-vfoot">\n' +
233
228
  ` <span class="certrev-r-verified">${readerLogo('mono', 17, '')}Verified by <b>CertREV</b></span>\n` +
234
- ` <span class="certrev-r-scope" data-ftc-disclosure data-ftc-line>${scopeLead(f)}${SCOPE}</span>\n </div>\n </div>\n</section>`);
229
+ ` <span class="certrev-r-scope" data-ftc-disclosure data-ftc-line>${scopeLead(f)}${f.scope}</span>\n </div>\n </div>\n</section>`);
235
230
  }
236
231
  // ─────────────────────────────────────────────────────────────────────────────
237
232
  // Sidebar and floating pill
@@ -264,7 +259,7 @@ function sidebar(f) {
264
259
  return (`${open}<div class="certrev-r-side-body">\n <div class="certrev-r-by">${avatar}<div>\n` +
265
260
  ` <b>${esc(f.ename)}${f.creds !== '' ? `<!-- -->, <!-- -->${esc(f.creds)}` : ''}</b>${verifiedLine(f, false)}</div>\n </div>` +
266
261
  `${fold}${more}` +
267
- `<div class="certrev-r-scope" data-ftc-disclosure data-ftc-line>${scopeLead(f)}${SCOPE}</div>\n </div>` +
262
+ `<div class="certrev-r-scope" data-ftc-disclosure data-ftc-line>${scopeLead(f)}${f.scope}</div>\n </div>` +
268
263
  `${links}</div>\n</section>`);
269
264
  }
270
265
  function pill(f) {
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/reader/render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/reader/render.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,12 @@
18
18
  * down costs the page nothing it already had. A definitive answer (a revocation, say)
19
19
  * replaces the entry the moment the refresh lands. With the default `staleMs` of 0 an
20
20
  * expired entry is gone, exactly as before 1.2.0.
21
+ * 5. (2.0.2, opt-in through `failureTtlMs`) FAILURE MEMORY: a transient result (`isTransient`: the origin was not
22
+ * reached) is remembered in a slot of its own for `failureTtlMs`, beside a positive entry and never over it. While
23
+ * it is remembered nothing loads for the key: a read with no servable entry gets the failure at once, and a stale
24
+ * entry is served without starting a refresh. A definitive answer clears it. So an ongoing outage costs a caller at
25
+ * most one load per key per failure window. `markFailed` lets a caller that stopped waiting (a render deadline)
26
+ * remember one before the load itself settles. Without `failureTtlMs` the cache behaves exactly as 2.0.1's.
21
27
  *
22
28
  * It is deliberately tiny + dependency-free (a Map + timestamps) so it runs in any server
23
29
  * runtime (Node, edge, workerd). For multi-instance deployments this is per-instance L1 and
@@ -43,21 +49,30 @@ export interface TtlCacheOptions {
43
49
  * it and none would ever refresh again.
44
50
  */
45
51
  readonly inflightMaxMs?: number;
52
+ /**
53
+ * 2.0.2: how long a transient result (`isTransient`) is remembered, in a slot of its own (default: none, and a transient
54
+ * result is cached as a negative entry as before). See the module header, point 5.
55
+ */
56
+ readonly failureTtlMs?: number;
46
57
  /** Injectable clock for deterministic tests. */
47
58
  readonly now?: () => number;
48
59
  }
49
60
  export declare class TtlCache<V> {
50
61
  private readonly store;
51
62
  private readonly inflight;
63
+ private readonly failures;
52
64
  private readonly ttlMs;
53
65
  private readonly negativeTtlMs;
54
66
  private readonly maxEntries;
55
67
  private readonly staleMs;
56
68
  private readonly inflightMaxMs;
69
+ private readonly failureTtlMs;
57
70
  private readonly now;
58
71
  constructor(opts?: TtlCacheOptions);
59
72
  /** The entry while it may still be served (fresh, or positive and inside the stale window); prunes it past that. */
60
73
  private servable;
74
+ /** 2.0.2: the remembered failure while it lasts (only with `failureTtlMs`); prunes it past that. */
75
+ private failure;
61
76
  /** Read a live (non-expired) entry, or undefined. Never serves a stale one; prunes an entry past its stale window. */
62
77
  peek(key: string): V | undefined;
63
78
  /**
@@ -92,6 +107,15 @@ export declare class TtlCache<V> {
92
107
  /** Insert/overwrite an entry. `ttlMsOverride` replaces the TTL this write would otherwise
93
108
  * get (positive or negative); omit it for the cache's configured TTLs. */
94
109
  set(key: string, value: V, negative?: boolean, ttlMsOverride?: number): void;
110
+ /** 2.0.2: whether a load for `key` is running (and still joinable, younger than `inflightMaxMs`). */
111
+ loading(key: string): boolean;
112
+ /**
113
+ * 2.0.2: remember a transient failure for `key` for `failureTtlMs` from now (a caller that stopped waiting for a load, or
114
+ * a load that settled on one), beside the key's entry: it never touches a positive entry. Without `failureTtlMs` it is
115
+ * a negative entry for the negative TTL, as a transient result was before 2.0.2, and like any `set` it replaces the
116
+ * key's entry.
117
+ */
118
+ markFailed(key: string, value: V): void;
95
119
  /** Drop a key (e.g. on a known revocation push). */
96
120
  delete(key: string): void;
97
121
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/verify/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,WAAW,eAAe;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,gDAAgD;IAChD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAC3B;AAaD,qBAAa,QAAQ,CAAC,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;gBAEtB,IAAI,GAAE,eAAoB;IAStC,oHAAoH;IACpH,OAAO,CAAC,QAAQ;IAUhB,sHAAsH;IACtH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAKhC;;;;;OAKG;IACH,aAAa,CACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,EAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,GAC7B,CAAC,GAAG,SAAS;IAShB;;;;;;;;;;;;;;;;;;OAkBG;IACG,SAAS,CACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,EAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,GAC7B,OAAO,CAAC,CAAC,CAAC;IAMb,2FAA2F;IAC3F,OAAO,CAAC,IAAI;IA4BZ;+EAC2E;IAC3E,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,UAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;IAW1E,oDAAoD;IACpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB;;;;;;OAMG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAMlC,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI,MAAM,CAEjB;CACD"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/verify/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,MAAM,WAAW,eAAe;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,gDAAgD;IAChD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAC3B;AAcD,qBAAa,QAAQ,CAAC,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiC;IAC1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmE;IAC5F,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;gBAEtB,IAAI,GAAE,eAAoB;IAUtC,oHAAoH;IACpH,OAAO,CAAC,QAAQ;IAUhB,oGAAoG;IACpG,OAAO,CAAC,OAAO;IAQf,sHAAsH;IACtH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAMhC;;;;;OAKG;IACH,aAAa,CACZ,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,EAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,GAC7B,CAAC,GAAG,SAAS;IAWhB;;;;;;;;;;;;;;;;;;OAkBG;IACG,SAAS,CACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACxB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,EAC9B,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,GAC7B,OAAO,CAAC,CAAC,CAAC;IAMb,2FAA2F;IAC3F,OAAO,CAAC,IAAI;IAuCZ;+EAC2E;IAC3E,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,UAAQ,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;IAW1E,qGAAqG;IACrG,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAK7B;;;;;OAKG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAiBvC,oDAAoD;IACpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB;;;;;;OAMG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IASlC,KAAK,IAAI,IAAI;IAMb,IAAI,IAAI,IAAI,MAAM,CAEjB;CACD"}
@@ -18,6 +18,12 @@
18
18
  * down costs the page nothing it already had. A definitive answer (a revocation, say)
19
19
  * replaces the entry the moment the refresh lands. With the default `staleMs` of 0 an
20
20
  * expired entry is gone, exactly as before 1.2.0.
21
+ * 5. (2.0.2, opt-in through `failureTtlMs`) FAILURE MEMORY: a transient result (`isTransient`: the origin was not
22
+ * reached) is remembered in a slot of its own for `failureTtlMs`, beside a positive entry and never over it. While
23
+ * it is remembered nothing loads for the key: a read with no servable entry gets the failure at once, and a stale
24
+ * entry is served without starting a refresh. A definitive answer clears it. So an ongoing outage costs a caller at
25
+ * most one load per key per failure window. `markFailed` lets a caller that stopped waiting (a render deadline)
26
+ * remember one before the load itself settles. Without `failureTtlMs` the cache behaves exactly as 2.0.1's.
21
27
  *
22
28
  * It is deliberately tiny + dependency-free (a Map + timestamps) so it runs in any server
23
29
  * runtime (Node, edge, workerd). For multi-instance deployments this is per-instance L1 and
@@ -27,11 +33,13 @@
27
33
  export class TtlCache {
28
34
  store = new Map();
29
35
  inflight = new Map();
36
+ failures = new Map();
30
37
  ttlMs;
31
38
  negativeTtlMs;
32
39
  maxEntries;
33
40
  staleMs;
34
41
  inflightMaxMs;
42
+ failureTtlMs;
35
43
  now;
36
44
  constructor(opts = {}) {
37
45
  this.ttlMs = opts.ttlMs ?? 60_000;
@@ -39,6 +47,7 @@ export class TtlCache {
39
47
  this.maxEntries = opts.maxEntries ?? 1000;
40
48
  this.staleMs = opts.staleMs !== undefined && opts.staleMs > 0 ? opts.staleMs : 0;
41
49
  this.inflightMaxMs = opts.inflightMaxMs ?? Number.POSITIVE_INFINITY;
50
+ this.failureTtlMs = opts.failureTtlMs !== undefined && opts.failureTtlMs > 0 ? opts.failureTtlMs : 0;
42
51
  this.now = opts.now ?? Date.now;
43
52
  }
44
53
  /** The entry while it may still be served (fresh, or positive and inside the stale window); prunes it past that. */
@@ -54,10 +63,22 @@ export class TtlCache {
54
63
  this.store.delete(key);
55
64
  return undefined;
56
65
  }
66
+ /** 2.0.2: the remembered failure while it lasts (only with `failureTtlMs`); prunes it past that. */
67
+ failure(key) {
68
+ const f = this.failures.get(key);
69
+ if (!f)
70
+ return undefined;
71
+ if (f.until > this.now())
72
+ return f;
73
+ this.failures.delete(key);
74
+ return undefined;
75
+ }
57
76
  /** Read a live (non-expired) entry, or undefined. Never serves a stale one; prunes an entry past its stale window. */
58
77
  peek(key) {
59
78
  const e = this.servable(key);
60
- return e && e.expiresAt > this.now() ? e.value : undefined;
79
+ if (e && e.expiresAt > this.now())
80
+ return e.value;
81
+ return this.failure(key)?.value;
61
82
  }
62
83
  /**
63
84
  * The synchronous stale-while-revalidate read: a fresh value; or a positive entry past its TTL but inside the stale
@@ -67,9 +88,11 @@ export class TtlCache {
67
88
  */
68
89
  peekOrRefresh(key, loader, isNegative, positiveTtlMs, isTransient) {
69
90
  const e = this.servable(key);
91
+ const failed = this.failure(key);
70
92
  if (!e)
71
- return undefined;
72
- if (e.expiresAt <= this.now()) {
93
+ return failed?.value;
94
+ // 2.0.2: no refresh while a failure is remembered; the stale value is still served.
95
+ if (e.expiresAt <= this.now() && !failed) {
73
96
  this.load(key, loader, isNegative, positiveTtlMs, isTransient).catch(() => undefined);
74
97
  }
75
98
  return e.value;
@@ -104,9 +127,22 @@ export class TtlCache {
104
127
  const existing = this.inflight.get(key);
105
128
  if (existing && this.now() - existing.startedAt < this.inflightMaxMs)
106
129
  return existing.promise;
130
+ const token = {};
107
131
  const promise = (async () => {
108
132
  const value = await loader();
109
- if (isTransient?.(value)) {
133
+ // 2.0.2: a load that was replaced (abandoned past `inflightMaxMs`) never writes: its answer may be older than
134
+ // the replacement's, and a late verified read must never overwrite a newer revocation.
135
+ if (this.inflight.get(key)?.token !== token)
136
+ return value;
137
+ if (this.failureTtlMs > 0) {
138
+ if (isTransient?.(value)) {
139
+ this.markFailed(key, value);
140
+ const kept = this.servable(key);
141
+ return kept && !kept.negative ? kept.value : value;
142
+ }
143
+ this.failures.delete(key);
144
+ }
145
+ else if (isTransient?.(value)) {
110
146
  const kept = this.servable(key);
111
147
  if (kept && !kept.negative)
112
148
  return kept.value;
@@ -116,10 +152,10 @@ export class TtlCache {
116
152
  return value;
117
153
  })().finally(() => {
118
154
  // Only this load's own slot: a newer load that replaced an abandoned one keeps its place.
119
- if (this.inflight.get(key)?.promise === promise)
155
+ if (this.inflight.get(key)?.token === token)
120
156
  this.inflight.delete(key);
121
157
  });
122
- this.inflight.set(key, { promise, startedAt: this.now() });
158
+ this.inflight.set(key, { promise, startedAt: this.now(), token });
123
159
  return promise;
124
160
  }
125
161
  /** Insert/overwrite an entry. `ttlMsOverride` replaces the TTL this write would otherwise
@@ -135,9 +171,40 @@ export class TtlCache {
135
171
  const ttl = ttlMsOverride !== undefined && Number.isFinite(ttlMsOverride) ? ttlMsOverride : configured;
136
172
  this.store.set(key, { value, expiresAt: this.now() + ttl, negative });
137
173
  }
174
+ /** 2.0.2: whether a load for `key` is running (and still joinable, younger than `inflightMaxMs`). */
175
+ loading(key) {
176
+ const existing = this.inflight.get(key);
177
+ return existing !== undefined && this.now() - existing.startedAt < this.inflightMaxMs;
178
+ }
179
+ /**
180
+ * 2.0.2: remember a transient failure for `key` for `failureTtlMs` from now (a caller that stopped waiting for a load, or
181
+ * a load that settled on one), beside the key's entry: it never touches a positive entry. Without `failureTtlMs` it is
182
+ * a negative entry for the negative TTL, as a transient result was before 2.0.2, and like any `set` it replaces the
183
+ * key's entry.
184
+ */
185
+ markFailed(key, value) {
186
+ if (this.failureTtlMs <= 0) {
187
+ this.set(key, value, true);
188
+ return;
189
+ }
190
+ // Bounded like the store (break-it B3): past `maxEntries`, drop the expired failures, then the oldest.
191
+ if (this.failures.size >= this.maxEntries && !this.failures.has(key)) {
192
+ const now = this.now();
193
+ for (const [k, f] of this.failures)
194
+ if (f.until <= now)
195
+ this.failures.delete(k);
196
+ if (this.failures.size >= this.maxEntries) {
197
+ const oldest = this.failures.keys().next().value;
198
+ if (oldest !== undefined)
199
+ this.failures.delete(oldest);
200
+ }
201
+ }
202
+ this.failures.set(key, { value, until: this.now() + this.failureTtlMs });
203
+ }
138
204
  /** Drop a key (e.g. on a known revocation push). */
139
205
  delete(key) {
140
206
  this.store.delete(key);
207
+ this.failures.delete(key);
141
208
  }
142
209
  /**
143
210
  * Drop every key under a prefix. WHY it exists: a cache key identifies everything the
@@ -151,10 +218,15 @@ export class TtlCache {
151
218
  if (key.startsWith(prefix))
152
219
  this.store.delete(key);
153
220
  }
221
+ for (const key of this.failures.keys()) {
222
+ if (key.startsWith(prefix))
223
+ this.failures.delete(key);
224
+ }
154
225
  }
155
226
  clear() {
156
227
  this.store.clear();
157
228
  this.inflight.clear();
229
+ this.failures.clear();
158
230
  }
159
231
  get size() {
160
232
  return this.store.size;