@certrev/cert-block 0.3.0 → 0.5.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 (129) hide show
  1. package/README.md +48 -1
  2. package/dist/builder/cert-chrome-data.d.ts +129 -0
  3. package/dist/builder/cert-chrome-data.d.ts.map +1 -0
  4. package/dist/builder/cert-chrome-data.js +59 -0
  5. package/dist/builder/cert-chrome-data.js.map +1 -0
  6. package/dist/builder/cert-review-card.d.ts +68 -0
  7. package/dist/builder/cert-review-card.d.ts.map +1 -0
  8. package/dist/builder/cert-review-card.js +129 -0
  9. package/dist/builder/cert-review-card.js.map +1 -0
  10. package/dist/builder/index.d.ts +2 -0
  11. package/dist/builder/index.d.ts.map +1 -1
  12. package/dist/builder/index.js +3 -0
  13. package/dist/builder/index.js.map +1 -1
  14. package/dist/components/preview-block.d.ts +43 -0
  15. package/dist/components/preview-block.d.ts.map +1 -0
  16. package/dist/components/preview-block.js +53 -0
  17. package/dist/components/preview-block.js.map +1 -0
  18. package/dist/components/render-cert-block.d.ts +50 -7
  19. package/dist/components/render-cert-block.d.ts.map +1 -1
  20. package/dist/components/render-cert-block.js +304 -80
  21. package/dist/components/render-cert-block.js.map +1 -1
  22. package/dist/components/render-def.d.ts +27 -0
  23. package/dist/components/render-def.d.ts.map +1 -1
  24. package/dist/components/render-def.js +38 -0
  25. package/dist/components/render-def.js.map +1 -1
  26. package/dist/index.d.ts +3 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +3 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/modal/avatar-resize.d.ts +60 -0
  31. package/dist/modal/avatar-resize.d.ts.map +1 -0
  32. package/dist/modal/avatar-resize.js +91 -0
  33. package/dist/modal/avatar-resize.js.map +1 -0
  34. package/dist/modal/cert-modal-view.d.ts +74 -0
  35. package/dist/modal/cert-modal-view.d.ts.map +1 -0
  36. package/dist/modal/cert-modal-view.js +160 -0
  37. package/dist/modal/cert-modal-view.js.map +1 -0
  38. package/dist/modal/certrev-cert-modal.d.ts +72 -0
  39. package/dist/modal/certrev-cert-modal.d.ts.map +1 -0
  40. package/dist/modal/certrev-cert-modal.js +270 -0
  41. package/dist/modal/certrev-cert-modal.js.map +1 -0
  42. package/dist/modal/certrev-cert-modal.styles.d.ts +35 -0
  43. package/dist/modal/certrev-cert-modal.styles.d.ts.map +1 -0
  44. package/dist/modal/certrev-cert-modal.styles.js +488 -0
  45. package/dist/modal/certrev-cert-modal.styles.js.map +1 -0
  46. package/dist/modal/certrev-cert.entry.d.ts +19 -0
  47. package/dist/modal/certrev-cert.entry.d.ts.map +1 -0
  48. package/dist/modal/certrev-cert.entry.js +39 -0
  49. package/dist/modal/certrev-cert.entry.js.map +1 -0
  50. package/dist/modal/certrev-cert.js +557 -0
  51. package/dist/modal/display-strings.d.ts +22 -0
  52. package/dist/modal/display-strings.d.ts.map +1 -0
  53. package/dist/modal/display-strings.js +35 -0
  54. package/dist/modal/display-strings.js.map +1 -0
  55. package/dist/modal/escape.d.ts +13 -0
  56. package/dist/modal/escape.d.ts.map +1 -0
  57. package/dist/modal/escape.js +20 -0
  58. package/dist/modal/escape.js.map +1 -0
  59. package/dist/modal/font-face.d.ts +4 -0
  60. package/dist/modal/font-face.d.ts.map +1 -0
  61. package/dist/modal/font-face.js +137 -0
  62. package/dist/modal/font-face.js.map +1 -0
  63. package/dist/modal/ftc-disclosure.d.ts +12 -0
  64. package/dist/modal/ftc-disclosure.d.ts.map +1 -0
  65. package/dist/modal/ftc-disclosure.js +12 -0
  66. package/dist/modal/ftc-disclosure.js.map +1 -0
  67. package/dist/modal/ftc-guard.d.ts +50 -0
  68. package/dist/modal/ftc-guard.d.ts.map +1 -0
  69. package/dist/modal/ftc-guard.js +117 -0
  70. package/dist/modal/ftc-guard.js.map +1 -0
  71. package/dist/modal/index.d.ts +20 -0
  72. package/dist/modal/index.d.ts.map +1 -0
  73. package/dist/modal/index.js +25 -0
  74. package/dist/modal/index.js.map +1 -0
  75. package/dist/modal/interactions.d.ts +53 -0
  76. package/dist/modal/interactions.d.ts.map +1 -0
  77. package/dist/modal/interactions.js +147 -0
  78. package/dist/modal/interactions.js.map +1 -0
  79. package/dist/modal/logo-paths.d.ts +15 -0
  80. package/dist/modal/logo-paths.d.ts.map +1 -0
  81. package/dist/modal/logo-paths.js +24 -0
  82. package/dist/modal/logo-paths.js.map +1 -0
  83. package/dist/modal/placement.d.ts +95 -0
  84. package/dist/modal/placement.d.ts.map +1 -0
  85. package/dist/modal/placement.js +302 -0
  86. package/dist/modal/placement.js.map +1 -0
  87. package/dist/modal/revalidate.d.ts +48 -0
  88. package/dist/modal/revalidate.d.ts.map +1 -0
  89. package/dist/modal/revalidate.js +65 -0
  90. package/dist/modal/revalidate.js.map +1 -0
  91. package/dist/modal/verify-client.d.ts +24 -0
  92. package/dist/modal/verify-client.d.ts.map +1 -0
  93. package/dist/modal/verify-client.js +38 -0
  94. package/dist/modal/verify-client.js.map +1 -0
  95. package/package.json +10 -4
  96. package/src/__tests__/__snapshots__/render-cert-block.test.ts.snap +10 -6
  97. package/src/__tests__/preview-block.test.ts +84 -0
  98. package/src/__tests__/render-cert-block.test.ts +380 -5
  99. package/src/builder/__tests__/builder.test.tsx +71 -0
  100. package/src/builder/cert-chrome-data.ts +159 -0
  101. package/src/builder/cert-review-card.tsx +177 -0
  102. package/src/builder/index.tsx +18 -0
  103. package/src/components/preview-block.ts +74 -0
  104. package/src/components/render-cert-block.ts +387 -102
  105. package/src/components/render-def.ts +55 -0
  106. package/src/index.ts +9 -0
  107. package/src/modal/avatar-resize.ts +99 -0
  108. package/src/modal/cert-modal-view.test.ts +175 -0
  109. package/src/modal/cert-modal-view.ts +210 -0
  110. package/src/modal/certrev-cert-modal.styles.ts +494 -0
  111. package/src/modal/certrev-cert-modal.test.ts +125 -0
  112. package/src/modal/certrev-cert-modal.ts +273 -0
  113. package/src/modal/certrev-cert.entry.ts +44 -0
  114. package/src/modal/display-strings.ts +38 -0
  115. package/src/modal/escape.ts +20 -0
  116. package/src/modal/font-face.ts +138 -0
  117. package/src/modal/ftc-disclosure.ts +13 -0
  118. package/src/modal/ftc-guard.test.ts +153 -0
  119. package/src/modal/ftc-guard.ts +119 -0
  120. package/src/modal/index.ts +34 -0
  121. package/src/modal/interactions.test.ts +250 -0
  122. package/src/modal/interactions.ts +166 -0
  123. package/src/modal/logo-paths.ts +23 -0
  124. package/src/modal/placement.test.ts +398 -0
  125. package/src/modal/placement.ts +331 -0
  126. package/src/modal/revalidate.test.ts +111 -0
  127. package/src/modal/revalidate.ts +81 -0
  128. package/src/modal/verify-client.test.ts +164 -0
  129. package/src/modal/verify-client.ts +42 -0
@@ -0,0 +1,13 @@
1
+ /**
2
+ * HTML escaping for the cert MODAL string builder — a BYTE-FAITHFUL relocation of
3
+ * portal `src/lib/utils/html.ts` `escapeHtml` (the exact `.replace` chain the deployed
4
+ * `certrev-cert.js` was bundled from — POR-10721 W2).
5
+ *
6
+ * ⚠ Deliberately SEPARATE from `../components/escape.ts`: that SSR helper encodes the
7
+ * apostrophe as `'`, THIS one as `'`. They render identically in a browser, but
8
+ * this module is a byte-frozen relocation of the live Shopify asset, so it must reproduce
9
+ * portal's exact `'` bytes — the two escapes are NOT interchangeable here. (Unifying
10
+ * them is a deliberate post-publish follow-up, tracked with the unification program.)
11
+ */
12
+ export declare function escapeHtml(text: string): string;
13
+ //# sourceMappingURL=escape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../../src/modal/escape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * HTML escaping for the cert MODAL string builder — a BYTE-FAITHFUL relocation of
3
+ * portal `src/lib/utils/html.ts` `escapeHtml` (the exact `.replace` chain the deployed
4
+ * `certrev-cert.js` was bundled from — POR-10721 W2).
5
+ *
6
+ * ⚠ Deliberately SEPARATE from `../components/escape.ts`: that SSR helper encodes the
7
+ * apostrophe as `'`, THIS one as `'`. They render identically in a browser, but
8
+ * this module is a byte-frozen relocation of the live Shopify asset, so it must reproduce
9
+ * portal's exact `'` bytes — the two escapes are NOT interchangeable here. (Unifying
10
+ * them is a deliberate post-publish follow-up, tracked with the unification program.)
11
+ */
12
+ export function escapeHtml(text) {
13
+ return text
14
+ .replace(/&/g, "&")
15
+ .replace(/</g, "&lt;")
16
+ .replace(/>/g, "&gt;")
17
+ .replace(/"/g, "&quot;")
18
+ .replace(/'/g, "&#039;");
19
+ }
20
+ //# sourceMappingURL=escape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape.js","sourceRoot":"","sources":["../../src/modal/escape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,UAAU,UAAU,CAAC,IAAY;IACtC,OAAO,IAAI;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const CERT_FONT_FACE_CSS = "\n@font-face {\n\tfont-family: \"DM Sans\";\n\tfont-style: normal;\n\tfont-weight: 400 700;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-dm-sans-latin-ext.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n\tfont-family: \"DM Sans\";\n\tfont-style: normal;\n\tfont-weight: 400 700;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-dm-sans-latin.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+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;\n}\n\n@font-face {\n\tfont-family: \"Playfair Display\";\n\tfont-style: italic;\n\tfont-weight: 400 600;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-playfair-italic-latin-ext.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n\tfont-family: \"Playfair Display\";\n\tfont-style: italic;\n\tfont-weight: 400 600;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-playfair-italic-latin.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+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;\n}\n\n@font-face {\n\tfont-family: \"Playfair Display\";\n\tfont-style: normal;\n\tfont-weight: 600 700;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-playfair-latin-ext.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n\tfont-family: \"Playfair Display\";\n\tfont-style: normal;\n\tfont-weight: 600 700;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-playfair-latin.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+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;\n}\n\n@font-face {\n\tfont-family: \"JetBrains Mono\";\n\tfont-style: normal;\n\tfont-weight: 400 700;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-jetbrains-mono-latin-ext.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n\tfont-family: \"JetBrains Mono\";\n\tfont-style: normal;\n\tfont-weight: 400 700;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-jetbrains-mono-latin.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+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;\n}\n\n@font-face {\n\tfont-family: \"Plus Jakarta Sans\";\n\tfont-style: normal;\n\tfont-weight: 700 800;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-jakarta-latin-ext.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n\tfont-family: \"Plus Jakarta Sans\";\n\tfont-style: normal;\n\tfont-weight: 700 800;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-jakarta-latin.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+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;\n}\n\n@font-face {\n\tfont-family: \"Allura\";\n\tfont-style: normal;\n\tfont-weight: 400;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-allura-latin-ext.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n\n@font-face {\n\tfont-family: \"Allura\";\n\tfont-style: normal;\n\tfont-weight: 400;\n\tfont-display: swap;\n\tsrc: url(\"https://assets.certrev.com/fonts/cert-allura-latin.woff2\") format(\"woff2\");\n\tunicode-range:\n\t\tU+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;\n}\n";
2
+ /** Preconnect origin for the self-hosted cert fonts (crossorigin — @font-face is always CORS). */
3
+ export declare const CERT_FONTS_ORIGIN = "https://assets.certrev.com";
4
+ //# sourceMappingURL=font-face.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-face.d.ts","sourceRoot":"","sources":["../../src/modal/font-face.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,kBAAkB,uiKAwH9B,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,+BAA+B,CAAC"}
@@ -0,0 +1,137 @@
1
+ // ⚠ VENDORED, BYTE-FAITHFUL copy of portal `src/lib/cert-delivery/fonts/font-face.generated.ts`
2
+ // (POR-10721 W2) — the exact @font-face block the deployed `certrev-cert.js` was bundled from.
3
+ // Regenerated upstream in portal; do not hand-edit the CSS here (a drift would break byte-parity).
4
+ //
5
+ // GENERATED by scripts/build-cert-fonts.mjs — DO NOT EDIT BY HAND.
6
+ //
7
+ // The CertREV self-hosted cert @font-face block (absolute R2 URLs on assets.certrev.com),
8
+ // mirrored from the block spliced into
9
+ // shopify/extensions/certrev-schema/assets/certrev-cert.css so the surfaces that CAN'T @import a
10
+ // .css asset share ONE canonical declaration: the standalone /embed renderers and the
11
+ // <certrev-cert-modal> web component (POR-10657). Regenerate with
12
+ // `node scripts/build-cert-fonts.mjs` (or `--emit-ts-only` to re-derive from the CSS without
13
+ // re-downloading). Inline this inside a <style> to load the fonts non-blocking from R2.
14
+ export const CERT_FONT_FACE_CSS = `
15
+ @font-face {
16
+ font-family: "DM Sans";
17
+ font-style: normal;
18
+ font-weight: 400 700;
19
+ font-display: swap;
20
+ src: url("https://assets.certrev.com/fonts/cert-dm-sans-latin-ext.woff2") format("woff2");
21
+ unicode-range:
22
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
23
+ }
24
+
25
+ @font-face {
26
+ font-family: "DM Sans";
27
+ font-style: normal;
28
+ font-weight: 400 700;
29
+ font-display: swap;
30
+ src: url("https://assets.certrev.com/fonts/cert-dm-sans-latin.woff2") format("woff2");
31
+ unicode-range:
32
+ 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;
33
+ }
34
+
35
+ @font-face {
36
+ font-family: "Playfair Display";
37
+ font-style: italic;
38
+ font-weight: 400 600;
39
+ font-display: swap;
40
+ src: url("https://assets.certrev.com/fonts/cert-playfair-italic-latin-ext.woff2") format("woff2");
41
+ unicode-range:
42
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
43
+ }
44
+
45
+ @font-face {
46
+ font-family: "Playfair Display";
47
+ font-style: italic;
48
+ font-weight: 400 600;
49
+ font-display: swap;
50
+ src: url("https://assets.certrev.com/fonts/cert-playfair-italic-latin.woff2") format("woff2");
51
+ unicode-range:
52
+ 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;
53
+ }
54
+
55
+ @font-face {
56
+ font-family: "Playfair Display";
57
+ font-style: normal;
58
+ font-weight: 600 700;
59
+ font-display: swap;
60
+ src: url("https://assets.certrev.com/fonts/cert-playfair-latin-ext.woff2") format("woff2");
61
+ unicode-range:
62
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
63
+ }
64
+
65
+ @font-face {
66
+ font-family: "Playfair Display";
67
+ font-style: normal;
68
+ font-weight: 600 700;
69
+ font-display: swap;
70
+ src: url("https://assets.certrev.com/fonts/cert-playfair-latin.woff2") format("woff2");
71
+ unicode-range:
72
+ 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;
73
+ }
74
+
75
+ @font-face {
76
+ font-family: "JetBrains Mono";
77
+ font-style: normal;
78
+ font-weight: 400 700;
79
+ font-display: swap;
80
+ src: url("https://assets.certrev.com/fonts/cert-jetbrains-mono-latin-ext.woff2") format("woff2");
81
+ unicode-range:
82
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
83
+ }
84
+
85
+ @font-face {
86
+ font-family: "JetBrains Mono";
87
+ font-style: normal;
88
+ font-weight: 400 700;
89
+ font-display: swap;
90
+ src: url("https://assets.certrev.com/fonts/cert-jetbrains-mono-latin.woff2") format("woff2");
91
+ unicode-range:
92
+ 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;
93
+ }
94
+
95
+ @font-face {
96
+ font-family: "Plus Jakarta Sans";
97
+ font-style: normal;
98
+ font-weight: 700 800;
99
+ font-display: swap;
100
+ src: url("https://assets.certrev.com/fonts/cert-jakarta-latin-ext.woff2") format("woff2");
101
+ unicode-range:
102
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
103
+ }
104
+
105
+ @font-face {
106
+ font-family: "Plus Jakarta Sans";
107
+ font-style: normal;
108
+ font-weight: 700 800;
109
+ font-display: swap;
110
+ src: url("https://assets.certrev.com/fonts/cert-jakarta-latin.woff2") format("woff2");
111
+ unicode-range:
112
+ 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;
113
+ }
114
+
115
+ @font-face {
116
+ font-family: "Allura";
117
+ font-style: normal;
118
+ font-weight: 400;
119
+ font-display: swap;
120
+ src: url("https://assets.certrev.com/fonts/cert-allura-latin-ext.woff2") format("woff2");
121
+ unicode-range:
122
+ U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
123
+ }
124
+
125
+ @font-face {
126
+ font-family: "Allura";
127
+ font-style: normal;
128
+ font-weight: 400;
129
+ font-display: swap;
130
+ src: url("https://assets.certrev.com/fonts/cert-allura-latin.woff2") format("woff2");
131
+ unicode-range:
132
+ 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;
133
+ }
134
+ `;
135
+ /** Preconnect origin for the self-hosted cert fonts (crossorigin — @font-face is always CORS). */
136
+ export const CERT_FONTS_ORIGIN = "https://assets.certrev.com";
137
+ //# sourceMappingURL=font-face.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-face.js","sourceRoot":"","sources":["../../src/modal/font-face.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,+FAA+F;AAC/F,mGAAmG;AACnG,EAAE;AACF,mEAAmE;AACnE,EAAE;AACF,0FAA0F;AAC1F,uCAAuC;AACvC,iGAAiG;AACjG,sFAAsF;AACtF,kEAAkE;AAClE,6FAA6F;AAC7F,wFAAwF;AAExF,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwHjC,CAAC;AAEF,kGAAkG;AAClG,MAAM,CAAC,MAAM,iBAAiB,GAAG,4BAA4B,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The verbatim FTC material-connection + scope disclosure line — a BYTE-FAITHFUL relocation of
3
+ * the (tree-shaken) `FTC_DISCLOSURE_LINE` from portal `src/lib/embed/ftc-disclosure.ts`
4
+ * (POR-9317 / POR-10721 W2). Legally load-bearing: the curly apostrophe (U+2019) in "article’s"
5
+ * is byte-exact; a reword is a contract divergence.
6
+ *
7
+ * Kept as its OWN module (imported by both ftc-guard + display-strings, exactly as in portal) so
8
+ * the browser bundle emits the same `var` structure as the deployed certrev-cert.js — do not merge
9
+ * it into display-strings.ts (that consolidation drops one `var` and breaks byte-parity).
10
+ */
11
+ export declare const FTC_DISCLOSURE_LINE: "Independent editorial review of this article\u2019s text and sources. Not a product endorsement, nor medical advice.";
12
+ //# sourceMappingURL=ftc-disclosure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ftc-disclosure.d.ts","sourceRoot":"","sources":["../../src/modal/ftc-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,mBAAmB,EAC/B,sHAA0H,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The verbatim FTC material-connection + scope disclosure line — a BYTE-FAITHFUL relocation of
3
+ * the (tree-shaken) `FTC_DISCLOSURE_LINE` from portal `src/lib/embed/ftc-disclosure.ts`
4
+ * (POR-9317 / POR-10721 W2). Legally load-bearing: the curly apostrophe (U+2019) in "article’s"
5
+ * is byte-exact; a reword is a contract divergence.
6
+ *
7
+ * Kept as its OWN module (imported by both ftc-guard + display-strings, exactly as in portal) so
8
+ * the browser bundle emits the same `var` structure as the deployed certrev-cert.js — do not merge
9
+ * it into display-strings.ts (that consolidation drops one `var` and breaks byte-parity).
10
+ */
11
+ export const FTC_DISCLOSURE_LINE = "Independent editorial review of this article’s text and sources. Not a product endorsement, nor medical advice.";
12
+ //# sourceMappingURL=ftc-disclosure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ftc-disclosure.js","sourceRoot":"","sources":["../../src/modal/ftc-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAC/B,iHAA0H,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * FTC disclosure tamper guard for the NATIVE Shopify cert render (iframe→native parity).
3
+ *
4
+ * In the cross-origin iframe model the expert-memo embed inlined `ftcTamperGuardScript()`
5
+ * (src/lib/embed/ftc-disclosure.ts): a kill switch that blanks the memo if the verbatim FTC
6
+ * material-connection disclosure is stripped, hidden, or altered — making the MSA §3
7
+ * anti-stripping covenant TECHNICALLY enforced, not just contractual. The native memo renders
8
+ * in the host theme's DOM (no sandbox), so without this it would lose that runtime enforcement.
9
+ * This module restores it: on load + on later DOM mutation it verifies the in-DOM
10
+ * `[data-ftc-line]` is present, carries the EXACT verbatim text, and is actually visible; if not,
11
+ * it neutralizes the memo with a neutral notice so the memo NEVER renders without its disclosure.
12
+ *
13
+ * Native-specific semantics (differ from the iframe, which only existed when a memo did):
14
+ * - Enforcement is keyed on the MEMO element (`.certrev-memo`). A certified article with NO
15
+ * memo legitimately has no `.certrev-memo` and no disclosure — the guard does NOT fire
16
+ * (no false positive on the no-memo path).
17
+ * - On tamper it neutralizes ONLY the memo (never `document.body` — we're in the host page).
18
+ * - The contributors card is governed by the badge re-verify (`revalidate.ts`), not this guard;
19
+ * the card carries only the one-word "Compensated" cue, never the guarded disclosure.
20
+ *
21
+ * Pure DOM, no crypto, no network. The expected text is the single source of truth
22
+ * `FTC_DISCLOSURE_LINE` (imported, not copied — so a reword can never desync this guard).
23
+ */
24
+ export declare const FTC_LINE_SELECTOR = "[data-ftc-line]";
25
+ export declare const MEMO_SELECTOR = ".certrev-memo";
26
+ export declare const MEMO_WRAP_SELECTOR = ".certrev-memo-wrap";
27
+ /** Marker on the neutral notice node that replaces a tampered memo (testable / idempotent). */
28
+ export declare const FTC_NEUTRALIZED_ATTR = "data-certrev-ftc-neutralized";
29
+ /** True when a memo's disclosure line is present, exactly verbatim, and visible. */
30
+ export declare function isDisclosureIntact(memo: Element): boolean;
31
+ /**
32
+ * Replace a tampered memo with a neutral, self-contained notice — no reviewer attribution, no
33
+ * seal — so the surface can never read as an endorsement without its required disclosure.
34
+ */
35
+ export declare function neutralizeMemo(memo: Element): void;
36
+ /**
37
+ * Enforce the disclosure across every memo in the doc: neutralize any whose disclosure isn't
38
+ * intact. A doc with no `.certrev-memo` (no-memo article) is a no-op. Returns true if all memos
39
+ * present were intact (or none existed).
40
+ */
41
+ export declare function enforceFtcDisclosure(doc: Document): boolean;
42
+ /**
43
+ * Install the guard once per document: enforce now (on DOM ready) and re-enforce on later DOM
44
+ * mutations within the memo wrap(s) — so a host script that strips / hides / edits the disclosure
45
+ * after load still trips the kill switch. Scoping the observer to the small `.certrev-memo-wrap`
46
+ * subtree(s) keeps it cheap on a busy storefront page (cf. the iframe, which observed its whole
47
+ * — tiny — body). Idempotent.
48
+ */
49
+ export declare function installFtcGuard(doc: Document): void;
50
+ //# sourceMappingURL=ftc-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ftc-guard.d.ts","sourceRoot":"","sources":["../../src/modal/ftc-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,eAAO,MAAM,iBAAiB,oBAAoB,CAAA;AAClD,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAC5C,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AACtD,+FAA+F;AAC/F,eAAO,MAAM,oBAAoB,iCAAiC,CAAA;AAiBlE,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAKzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAS3D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAwBnD"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * FTC disclosure tamper guard for the NATIVE Shopify cert render (iframe→native parity).
3
+ *
4
+ * In the cross-origin iframe model the expert-memo embed inlined `ftcTamperGuardScript()`
5
+ * (src/lib/embed/ftc-disclosure.ts): a kill switch that blanks the memo if the verbatim FTC
6
+ * material-connection disclosure is stripped, hidden, or altered — making the MSA §3
7
+ * anti-stripping covenant TECHNICALLY enforced, not just contractual. The native memo renders
8
+ * in the host theme's DOM (no sandbox), so without this it would lose that runtime enforcement.
9
+ * This module restores it: on load + on later DOM mutation it verifies the in-DOM
10
+ * `[data-ftc-line]` is present, carries the EXACT verbatim text, and is actually visible; if not,
11
+ * it neutralizes the memo with a neutral notice so the memo NEVER renders without its disclosure.
12
+ *
13
+ * Native-specific semantics (differ from the iframe, which only existed when a memo did):
14
+ * - Enforcement is keyed on the MEMO element (`.certrev-memo`). A certified article with NO
15
+ * memo legitimately has no `.certrev-memo` and no disclosure — the guard does NOT fire
16
+ * (no false positive on the no-memo path).
17
+ * - On tamper it neutralizes ONLY the memo (never `document.body` — we're in the host page).
18
+ * - The contributors card is governed by the badge re-verify (`revalidate.ts`), not this guard;
19
+ * the card carries only the one-word "Compensated" cue, never the guarded disclosure.
20
+ *
21
+ * Pure DOM, no crypto, no network. The expected text is the single source of truth
22
+ * `FTC_DISCLOSURE_LINE` (imported, not copied — so a reword can never desync this guard).
23
+ */
24
+ import { FTC_DISCLOSURE_LINE } from './ftc-disclosure.js';
25
+ export const FTC_LINE_SELECTOR = '[data-ftc-line]';
26
+ export const MEMO_SELECTOR = '.certrev-memo';
27
+ export const MEMO_WRAP_SELECTOR = '.certrev-memo-wrap';
28
+ /** Marker on the neutral notice node that replaces a tampered memo (testable / idempotent). */
29
+ export const FTC_NEUTRALIZED_ATTR = 'data-certrev-ftc-neutralized';
30
+ /** Documents already guarded, so a double script-load can't double-bind. */
31
+ const guardedDocs = new WeakSet();
32
+ /** Visible = not display:none / visibility:hidden / opacity:0 and a non-zero box. */
33
+ function isVisible(el) {
34
+ const win = el.ownerDocument.defaultView;
35
+ // No view (detached / SSR): we can't measure, so don't treat as hidden — the text/presence
36
+ // checks still apply; only the layout-based hide vector is skipped.
37
+ if (!win)
38
+ return true;
39
+ const s = win.getComputedStyle(el);
40
+ if (s.display === 'none' || s.visibility === 'hidden' || Number.parseFloat(s.opacity || '1') === 0)
41
+ return false;
42
+ const r = el.getBoundingClientRect();
43
+ return r.width > 0 && r.height > 0;
44
+ }
45
+ /** True when a memo's disclosure line is present, exactly verbatim, and visible. */
46
+ export function isDisclosureIntact(memo) {
47
+ const line = memo.querySelector(FTC_LINE_SELECTOR);
48
+ if (!line)
49
+ return false;
50
+ if ((line.textContent || '').trim() !== FTC_DISCLOSURE_LINE)
51
+ return false;
52
+ return isVisible(line);
53
+ }
54
+ /**
55
+ * Replace a tampered memo with a neutral, self-contained notice — no reviewer attribution, no
56
+ * seal — so the surface can never read as an endorsement without its required disclosure.
57
+ */
58
+ export function neutralizeMemo(memo) {
59
+ const doc = memo.ownerDocument;
60
+ const notice = doc.createElement('div');
61
+ notice.setAttribute(FTC_NEUTRALIZED_ATTR, '');
62
+ notice.style.cssText =
63
+ 'font-family:system-ui,-apple-system,sans-serif;font-size:12px;color:#555;padding:12px;line-height:1.4';
64
+ notice.innerHTML =
65
+ 'This CertREV verification cannot be displayed because its required disclosure was not shown. ' +
66
+ '<a href="https://certrev.com" style="color:#555" target="_blank" rel="noopener noreferrer">Learn more</a>.';
67
+ memo.replaceWith(notice);
68
+ }
69
+ /**
70
+ * Enforce the disclosure across every memo in the doc: neutralize any whose disclosure isn't
71
+ * intact. A doc with no `.certrev-memo` (no-memo article) is a no-op. Returns true if all memos
72
+ * present were intact (or none existed).
73
+ */
74
+ export function enforceFtcDisclosure(doc) {
75
+ let allIntact = true;
76
+ for (const memo of Array.from(doc.querySelectorAll(MEMO_SELECTOR))) {
77
+ if (!isDisclosureIntact(memo)) {
78
+ allIntact = false;
79
+ neutralizeMemo(memo);
80
+ }
81
+ }
82
+ return allIntact;
83
+ }
84
+ /**
85
+ * Install the guard once per document: enforce now (on DOM ready) and re-enforce on later DOM
86
+ * mutations within the memo wrap(s) — so a host script that strips / hides / edits the disclosure
87
+ * after load still trips the kill switch. Scoping the observer to the small `.certrev-memo-wrap`
88
+ * subtree(s) keeps it cheap on a busy storefront page (cf. the iframe, which observed its whole
89
+ * — tiny — body). Idempotent.
90
+ */
91
+ export function installFtcGuard(doc) {
92
+ if (guardedDocs.has(doc))
93
+ return;
94
+ guardedDocs.add(doc);
95
+ const run = () => {
96
+ enforceFtcDisclosure(doc);
97
+ };
98
+ const start = () => {
99
+ run();
100
+ const MO = doc.defaultView?.MutationObserver;
101
+ if (!MO)
102
+ return;
103
+ // Observe the stable memo wrap(s) — placement.js relocates the wrap as a node, so the
104
+ // observer tracks it wherever it moves. Fall back to <body> only if no wrap exists.
105
+ const wraps = Array.from(doc.querySelectorAll(MEMO_WRAP_SELECTOR));
106
+ const scope = wraps.length ? wraps : doc.body ? [doc.body] : [];
107
+ for (const node of scope) {
108
+ const mo = new MO(run);
109
+ mo.observe(node, { childList: true, subtree: true, characterData: true, attributes: true });
110
+ }
111
+ };
112
+ if (doc.readyState === 'loading')
113
+ doc.addEventListener('DOMContentLoaded', start, { once: true });
114
+ else
115
+ start();
116
+ }
117
+ //# sourceMappingURL=ftc-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ftc-guard.js","sourceRoot":"","sources":["../../src/modal/ftc-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `@certrev/cert-block/modal` — the browser cert MODAL + badge-revalidation Web Component
3
+ * (POR-10721 W2). A BYTE-FAITHFUL relocation of portal `src/lib/cert-delivery/wc/`; the IIFE
4
+ * built from `certrev-cert.entry.ts` (`build:modal-bundle`) is structurally byte-identical to the
5
+ * Shopify-deployed `certrev-cert.js`, so a headless brand can drop the SAME verified modal onto its
6
+ * storefront (`<script src=".../dist/modal/certrev-cert.js">`) instead of vendoring a copy.
7
+ *
8
+ * Importing this module as ESM has the SAME side effect as loading the IIFE: it registers the
9
+ * `<certrev-cert-modal>` element and (in a browser) runs placement + interactions + FTC guard +
10
+ * badge revalidation. Bundler users: `import '@certrev/cert-block/modal'`.
11
+ */
12
+ import "./certrev-cert.entry.js";
13
+ export { CERT_ISSUER_KID, CERT_ISSUER_PUBLIC_KEY_PEM, } from "./certrev-cert.entry.js";
14
+ export { CERT_MODAL_TAG } from "./certrev-cert-modal.js";
15
+ export { installFtcGuard } from "./ftc-guard.js";
16
+ export { initCertInteractionsOnReady } from "./interactions.js";
17
+ export { initCertPlacement } from "./placement.js";
18
+ export { initBadgeRevalidation, type RevalidateDeps, revalidateBadge, } from "./revalidate.js";
19
+ export { createDeliveryVerifier } from "./verify-client.js";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modal/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,yBAAyB,CAAC;AAKjC,OAAO,EACN,eAAe,EACf,0BAA0B,GAC1B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACN,qBAAqB,EACrB,KAAK,cAAc,EACnB,eAAe,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * `@certrev/cert-block/modal` — the browser cert MODAL + badge-revalidation Web Component
3
+ * (POR-10721 W2). A BYTE-FAITHFUL relocation of portal `src/lib/cert-delivery/wc/`; the IIFE
4
+ * built from `certrev-cert.entry.ts` (`build:modal-bundle`) is structurally byte-identical to the
5
+ * Shopify-deployed `certrev-cert.js`, so a headless brand can drop the SAME verified modal onto its
6
+ * storefront (`<script src=".../dist/modal/certrev-cert.js">`) instead of vendoring a copy.
7
+ *
8
+ * Importing this module as ESM has the SAME side effect as loading the IIFE: it registers the
9
+ * `<certrev-cert-modal>` element and (in a browser) runs placement + interactions + FTC guard +
10
+ * badge revalidation. Bundler users: `import '@certrev/cert-block/modal'`.
11
+ */
12
+ // Side-effect: register the element + (in a browser) kick off the DOM passes.
13
+ import "./certrev-cert.entry.js";
14
+ // The published issuer PUBLIC key — re-exported so a portal-side test can assert the package's
15
+ // bundled key matches portal's signer (`CERT_ENVELOPE_*`) after portal re-points at this package
16
+ // (the cross-repo "published key sync" guard that used to live in wc/revalidate.test.ts).
17
+ export { CERT_ISSUER_KID, CERT_ISSUER_PUBLIC_KEY_PEM, } from "./certrev-cert.entry.js";
18
+ // Composable entry points for advanced consumers (the IIFE wires these itself).
19
+ export { CERT_MODAL_TAG } from "./certrev-cert-modal.js";
20
+ export { installFtcGuard } from "./ftc-guard.js";
21
+ export { initCertInteractionsOnReady } from "./interactions.js";
22
+ export { initCertPlacement } from "./placement.js";
23
+ export { initBadgeRevalidation, revalidateBadge, } from "./revalidate.js";
24
+ export { createDeliveryVerifier } from "./verify-client.js";
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/modal/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,8EAA8E;AAC9E,OAAO,yBAAyB,CAAC;AAEjC,+FAA+F;AAC/F,iGAAiG;AACjG,0FAA0F;AAC1F,OAAO,EACN,eAAe,EACf,0BAA0B,GAC1B,MAAM,yBAAyB,CAAC;AAEjC,gFAAgF;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EACN,qBAAqB,EAErB,eAAe,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Cert-card INTERACTIONS for the native Shopify cert experience.
3
+ *
4
+ * Progressive enhancement, delegated from the document (one listener, survives the placement
5
+ * reposition). Two behaviours (POR-9827 chevron model):
6
+ *
7
+ * • Accordion bios — a contributor row carrying `[data-certrev-acc]` toggles its `.open` class
8
+ * (revealing the row's `.acc-bio` in place; the name caret rotates via CSS) and mirrors the
9
+ * state on `aria-expanded`. A click on a link inside the row (e.g. the "Compensated expert"
10
+ * cue) is NOT a toggle. Keyboard: Enter/Space on the role=button row.
11
+ * • In-page modals: a `[data-certrev-modal-open]` control opens the unified
12
+ * `<certrev-cert-modal>` element (POR-10102) via its `.open('cert'|'expert')` method. Bare /
13
+ * `"cert"` opens the certificate dialog; `"expert"` opens the reviewer dialog. With no JS / no
14
+ * element / no envelope a link control falls back to its href (the certificate or the CertREV
15
+ * profile page). The element owns its OWN close plumbing (× / Close / backdrop / Esc) inside its
16
+ * shadow root — a shadow click is retargeted to the host, so a document delegate can't see it.
17
+ *
18
+ * No crypto, no network — pure DOM. Idempotent install (guarded so a double-load can't double-bind).
19
+ */
20
+ export declare const ACC_ATTR = "data-certrev-acc";
21
+ export declare const MODAL_OPEN_ATTR = "data-certrev-modal-open";
22
+ export declare const INITIALS_ATTR = "data-certrev-initials";
23
+ export declare const CARD_SELECTOR = ".certrev-card";
24
+ /** The dialog a `data-certrev-modal-open` control targets. */
25
+ export type ModalKind = 'cert' | 'expert';
26
+ /** Toggle a contributor row's accordion bio open/closed (the `.open` class drives the CSS reveal +
27
+ * caret rotation) and mirror the state on aria-expanded. */
28
+ export declare function toggleAccordion(row: Element): void;
29
+ /** Resolve a `data-certrev-modal-open` value to the dialog it opens. `"expert"` opens the reviewer
30
+ * modal; anything else (the bare attribute, or `"cert"`) opens the certificate modal. */
31
+ export declare function modalTargetKind(value: string | null): ModalKind;
32
+ /** Open a cert dialog via the `<certrev-cert-modal>` element. Returns false (so the caller lets an
33
+ * href fall back) when the element is absent or declines (no envelope + no fetch source). */
34
+ export declare function openModal(doc: Document, kind: ModalKind): boolean;
35
+ /** Open the page's certificate modal (backward-compatible wrapper over openModal). */
36
+ export declare function openCertModal(doc: Document): boolean;
37
+ /**
38
+ * Replace a broken avatar `<img>` with its initials placeholder — the SAME markup the Liquid emits
39
+ * when no photo URL is present. The SSR can't know a present URL will 404 (the canary's expert photo
40
+ * does), so without this a broken-image icon shows instead of the clean initials circle.
41
+ */
42
+ export declare function swapBrokenAvatar(img: HTMLImageElement): void;
43
+ /**
44
+ * Swap every avatar that has ALREADY failed to load. A 404 fires `error` during parse — often
45
+ * before this bundle runs — and `error` doesn't re-fire, so the live `error` listener alone misses
46
+ * pre-init failures (observed on the canary). Safe to call repeatedly; only acts on broken imgs.
47
+ */
48
+ export declare function sweepBrokenAvatars(doc: Document): void;
49
+ /** Install the delegated click + keydown handlers on the document, once. */
50
+ export declare function initCertInteractions(doc: Document): void;
51
+ /** Run interactions setup once the DOM is parsed. */
52
+ export declare function initCertInteractionsOnReady(doc: Document): void;
53
+ //# sourceMappingURL=interactions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactions.d.ts","sourceRoot":"","sources":["../../src/modal/interactions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,eAAO,MAAM,QAAQ,qBAAqB,CAAA;AAC1C,eAAO,MAAM,eAAe,4BAA4B,CAAA;AACxD,eAAO,MAAM,aAAa,0BAA0B,CAAA;AACpD,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAE5C,8DAA8D;AAC9D,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;AAczC;6DAC6D;AAC7D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAGlD;AAED;0FAC0F;AAC1F,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAE/D;AAED;8FAC8F;AAC9F,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAIjE;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAEpD;AAMD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAU5D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAItD;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAyDxD;AAED,qDAAqD;AACrD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAI/D"}