@certrev/cert-block 0.2.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.
- package/README.md +48 -1
- package/dist/builder/cert-chrome-data.d.ts +129 -0
- package/dist/builder/cert-chrome-data.d.ts.map +1 -0
- package/dist/builder/cert-chrome-data.js +59 -0
- package/dist/builder/cert-chrome-data.js.map +1 -0
- package/dist/builder/cert-review-card.d.ts +68 -0
- package/dist/builder/cert-review-card.d.ts.map +1 -0
- package/dist/builder/cert-review-card.js +129 -0
- package/dist/builder/cert-review-card.js.map +1 -0
- package/dist/builder/index.d.ts +2 -0
- package/dist/builder/index.d.ts.map +1 -1
- package/dist/builder/index.js +3 -0
- package/dist/builder/index.js.map +1 -1
- package/dist/components/preview-block.d.ts +43 -0
- package/dist/components/preview-block.d.ts.map +1 -0
- package/dist/components/preview-block.js +53 -0
- package/dist/components/preview-block.js.map +1 -0
- package/dist/components/render-cert-block.d.ts +50 -5
- package/dist/components/render-cert-block.d.ts.map +1 -1
- package/dist/components/render-cert-block.js +341 -93
- package/dist/components/render-cert-block.js.map +1 -1
- package/dist/components/render-def.d.ts +27 -0
- package/dist/components/render-def.d.ts.map +1 -1
- package/dist/components/render-def.js +38 -0
- package/dist/components/render-def.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/modal/avatar-resize.d.ts +60 -0
- package/dist/modal/avatar-resize.d.ts.map +1 -0
- package/dist/modal/avatar-resize.js +91 -0
- package/dist/modal/avatar-resize.js.map +1 -0
- package/dist/modal/cert-modal-view.d.ts +74 -0
- package/dist/modal/cert-modal-view.d.ts.map +1 -0
- package/dist/modal/cert-modal-view.js +160 -0
- package/dist/modal/cert-modal-view.js.map +1 -0
- package/dist/modal/certrev-cert-modal.d.ts +72 -0
- package/dist/modal/certrev-cert-modal.d.ts.map +1 -0
- package/dist/modal/certrev-cert-modal.js +270 -0
- package/dist/modal/certrev-cert-modal.js.map +1 -0
- package/dist/modal/certrev-cert-modal.styles.d.ts +35 -0
- package/dist/modal/certrev-cert-modal.styles.d.ts.map +1 -0
- package/dist/modal/certrev-cert-modal.styles.js +488 -0
- package/dist/modal/certrev-cert-modal.styles.js.map +1 -0
- package/dist/modal/certrev-cert.entry.d.ts +19 -0
- package/dist/modal/certrev-cert.entry.d.ts.map +1 -0
- package/dist/modal/certrev-cert.entry.js +39 -0
- package/dist/modal/certrev-cert.entry.js.map +1 -0
- package/dist/modal/certrev-cert.js +557 -0
- package/dist/modal/display-strings.d.ts +22 -0
- package/dist/modal/display-strings.d.ts.map +1 -0
- package/dist/modal/display-strings.js +35 -0
- package/dist/modal/display-strings.js.map +1 -0
- package/dist/modal/escape.d.ts +13 -0
- package/dist/modal/escape.d.ts.map +1 -0
- package/dist/modal/escape.js +20 -0
- package/dist/modal/escape.js.map +1 -0
- package/dist/modal/font-face.d.ts +4 -0
- package/dist/modal/font-face.d.ts.map +1 -0
- package/dist/modal/font-face.js +137 -0
- package/dist/modal/font-face.js.map +1 -0
- package/dist/modal/ftc-disclosure.d.ts +12 -0
- package/dist/modal/ftc-disclosure.d.ts.map +1 -0
- package/dist/modal/ftc-disclosure.js +12 -0
- package/dist/modal/ftc-disclosure.js.map +1 -0
- package/dist/modal/ftc-guard.d.ts +50 -0
- package/dist/modal/ftc-guard.d.ts.map +1 -0
- package/dist/modal/ftc-guard.js +117 -0
- package/dist/modal/ftc-guard.js.map +1 -0
- package/dist/modal/index.d.ts +20 -0
- package/dist/modal/index.d.ts.map +1 -0
- package/dist/modal/index.js +25 -0
- package/dist/modal/index.js.map +1 -0
- package/dist/modal/interactions.d.ts +53 -0
- package/dist/modal/interactions.d.ts.map +1 -0
- package/dist/modal/interactions.js +147 -0
- package/dist/modal/interactions.js.map +1 -0
- package/dist/modal/logo-paths.d.ts +15 -0
- package/dist/modal/logo-paths.d.ts.map +1 -0
- package/dist/modal/logo-paths.js +24 -0
- package/dist/modal/logo-paths.js.map +1 -0
- package/dist/modal/placement.d.ts +95 -0
- package/dist/modal/placement.d.ts.map +1 -0
- package/dist/modal/placement.js +302 -0
- package/dist/modal/placement.js.map +1 -0
- package/dist/modal/revalidate.d.ts +48 -0
- package/dist/modal/revalidate.d.ts.map +1 -0
- package/dist/modal/revalidate.js +65 -0
- package/dist/modal/revalidate.js.map +1 -0
- package/dist/modal/verify-client.d.ts +24 -0
- package/dist/modal/verify-client.d.ts.map +1 -0
- package/dist/modal/verify-client.js +38 -0
- package/dist/modal/verify-client.js.map +1 -0
- package/package.json +10 -4
- package/src/__tests__/__snapshots__/render-cert-block.test.ts.snap +10 -6
- package/src/__tests__/preview-block.test.ts +84 -0
- package/src/__tests__/render-cert-block.test.ts +404 -6
- package/src/builder/__tests__/builder.test.tsx +71 -0
- package/src/builder/cert-chrome-data.ts +159 -0
- package/src/builder/cert-review-card.tsx +177 -0
- package/src/builder/index.tsx +18 -0
- package/src/components/preview-block.ts +74 -0
- package/src/components/render-cert-block.ts +427 -121
- package/src/components/render-def.ts +55 -0
- package/src/index.ts +9 -0
- package/src/modal/avatar-resize.ts +99 -0
- package/src/modal/cert-modal-view.test.ts +175 -0
- package/src/modal/cert-modal-view.ts +210 -0
- package/src/modal/certrev-cert-modal.styles.ts +494 -0
- package/src/modal/certrev-cert-modal.test.ts +125 -0
- package/src/modal/certrev-cert-modal.ts +273 -0
- package/src/modal/certrev-cert.entry.ts +44 -0
- package/src/modal/display-strings.ts +38 -0
- package/src/modal/escape.ts +20 -0
- package/src/modal/font-face.ts +138 -0
- package/src/modal/ftc-disclosure.ts +13 -0
- package/src/modal/ftc-guard.test.ts +153 -0
- package/src/modal/ftc-guard.ts +119 -0
- package/src/modal/index.ts +34 -0
- package/src/modal/interactions.test.ts +250 -0
- package/src/modal/interactions.ts +166 -0
- package/src/modal/logo-paths.ts +23 -0
- package/src/modal/placement.test.ts +398 -0
- package/src/modal/placement.ts +331 -0
- package/src/modal/revalidate.test.ts +111 -0
- package/src/modal/revalidate.ts +81 -0
- package/src/modal/verify-client.test.ts +164 -0
- package/src/modal/verify-client.ts +42 -0
package/README.md
CHANGED
|
@@ -112,6 +112,53 @@ Preferred mode is **SSR + hydrate** (crawlable): a server-side include emits the
|
|
|
112
112
|
</script>
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
+
## Usage — Builder.io (the cert component)
|
|
116
|
+
|
|
117
|
+
Two ways to place the visible cert on a Builder.io page. **PUSH is the primary story** for
|
|
118
|
+
exporter-driven brands (the cert block arrives with the CertREV-drafted entry); the PULL anchor
|
|
119
|
+
is the editor-placed alternative (W4, POR-10721).
|
|
120
|
+
|
|
121
|
+
### PUSH — the registered cert block (recommended)
|
|
122
|
+
|
|
123
|
+
CertREV's exporter emits a cert block whose options are the `BuilderCertChromeData` projection.
|
|
124
|
+
Register the ready component once, from the `./builder` subpath — no hand-mapped options, no
|
|
125
|
+
hand-maintained inputs array:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { Builder } from '@builder.io/react'
|
|
129
|
+
import { BUILDER_REGISTRATION } from '@certrev/cert-block/builder'
|
|
130
|
+
|
|
131
|
+
Builder.registerComponent(BUILDER_REGISTRATION.component, BUILDER_REGISTRATION)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`CERT_COMPONENT_NAME` is the canonical block name the portal's `certComponent` connection field
|
|
135
|
+
defaults to; `BUILDER_REGISTRATION.inputs` are single-sourced from the `BuilderCertChromeData`
|
|
136
|
+
wire type (drift-locked — the exporter option keys, the registered inputs, and the type can
|
|
137
|
+
never diverge silently). The component enforces the fused-credential rule by construction (a
|
|
138
|
+
credential is unrenderable without its dated verification) and themes to the brand's render-def
|
|
139
|
+
(accent / surface / corners / font + v2 bar-ink / body-ink).
|
|
140
|
+
|
|
141
|
+
### The certificate modal + CSP
|
|
142
|
+
|
|
143
|
+
The "View certificate" affordance opens an envelope-verified modal. Add the modal element +
|
|
144
|
+
its browser bundle. *(Modal-in-package is POR-10721 W2 — until it lands, vendor the IIFE bundle
|
|
145
|
+
from the Shopify theme extension's `certrev-cert.js`, exactly as the canary demo does.)*
|
|
146
|
+
|
|
147
|
+
Two CSP allowances for the headless host:
|
|
148
|
+
- `connect-src` → the CertREV Delivery origin (the modal fetches the signed envelope).
|
|
149
|
+
- `img-src` → `cdn.builder.io` + the CertREV asset origin (headshots).
|
|
150
|
+
|
|
151
|
+
`data-delivery-api` is the **origin only** — the element appends
|
|
152
|
+
`/api/cert/v1/delivery/{platform}/{externalId}`. Preview drafts with `includeUnpublished` on the
|
|
153
|
+
public key.
|
|
154
|
+
|
|
155
|
+
### PULL — the editor-placed anchor (alternative)
|
|
156
|
+
|
|
157
|
+
`CertRevProvider` + the zero-input `CertRevAnchor` (`@certrev/cert-block/builder`) let an editor
|
|
158
|
+
drop the cert wherever they want it (panel-validated). Use this when placement is editorial
|
|
159
|
+
rather than exporter-driven. *(The anchor is preset-default only today — render-def theming on
|
|
160
|
+
the anchor path is a follow-up.)*
|
|
161
|
+
|
|
115
162
|
## Fail-closed, everywhere
|
|
116
163
|
|
|
117
164
|
The package never renders an unverified credential. Every error path — bad signature, unknown kid, wrong post, revoked, expired, content drift, network failure, malformed JSON, a throwing resolver — collapses to a `suppress` verdict (or a `null` render), never an exception that a caller could swallow into a render. `<CertReview>` and `<CertRevBacklink>` also fail closed at the component boundary (suppress / unsafe URL → render nothing). URLs pass through `safeHttpUrl` (drops `javascript:`/`data:`); accent colors through `safeCssColor`; the JSON-LD body neutralizes `<`/`>` so a hostile memo can't break out of the `<script>` tag.
|
|
@@ -151,4 +198,4 @@ Facts are mocked via `makeMockPayload` / `makeSignedEnvelope` (`src/contract/fix
|
|
|
151
198
|
|
|
152
199
|
## Version
|
|
153
200
|
|
|
154
|
-
`0.
|
|
201
|
+
`0.4.0` (this branch, `feat/cert-block-v2-render`) — the locked cert-render faces (`renderCertBlock`, 3 modes + custom), v2 brand-ink theming (`barInk`/`inkColor`), and the Builder.io PUSH kit (`CertReviewCard` + `BUILDER_REGISTRATION` + the single-sourced `BuilderCertChromeData` wire type, POR-10721 W1/W3). npm is at `0.3.0`; `main` trails on `0.1.3` — the version lineage + branch strategy are tracked in the repo `COORDINATION.md`. Publishes **publicly** to npm as `@certrev/cert-block` (`publishConfig.access: public`).
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
* `BuilderCertChromeData` — the CANONICAL headless cert-chrome wire type
|
|
4
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* The brand-render projection of the cert envelope (portal POR-10091) — the OPTIONS
|
|
7
|
+
* of a brand's native cert component (e.g. e.l.f.'s registered `CertReviewCard`) on
|
|
8
|
+
* a headless blocks-mode entry (Builder.io). CertREV serves the data + the ready-made
|
|
9
|
+
* strings; the brand renders it within the design-guide ladder (enforced live by the
|
|
10
|
+
* crawl monitor + the MSA anti-stripping teeth).
|
|
11
|
+
*
|
|
12
|
+
* SINGLE SOURCE (POR-10721 W1): this type is HOMED HERE so the portal exporter
|
|
13
|
+
* (`src/lib/builder/cert-chrome.ts`) and the kit component (`CertReviewCard`) +
|
|
14
|
+
* `BUILDER_REGISTRATION.inputs` all reference ONE definition — killing the drift the
|
|
15
|
+
* hand-rolled Hydrogen-replica component suffered (it carried a stale separate
|
|
16
|
+
* `credential`/`credentialVerifiedAt` shape from before the fused-pair projection).
|
|
17
|
+
* Keep byte-for-byte in sync with the portal interface until the portal migrates to
|
|
18
|
+
* import THIS (that migration is gated on publishing the package that carries it).
|
|
19
|
+
*
|
|
20
|
+
* PURITY: types + a pure key tuple only — no runtime deps, tree-shakeable.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The baked render-def projection (the Shopify `render_def` metafield shape) the
|
|
24
|
+
* exporter delivers so a brand's Builder face themes byte-identically to its Shopify
|
|
25
|
+
* face. The component maps `{ tokens, version }` onto `renderCertBlock`'s theme +
|
|
26
|
+
* `data-certrev-def-version` stamp. Structurally matches the portal's
|
|
27
|
+
* `ShopifyRenderDefMetafield` (single-sourcing that metafield type too is a follow-up).
|
|
28
|
+
*/
|
|
29
|
+
export interface CertChromeRenderDef {
|
|
30
|
+
/** Monotonic per-brand def version → the `data-certrev-def-version` stamp. */
|
|
31
|
+
readonly v: number;
|
|
32
|
+
readonly preset: string;
|
|
33
|
+
readonly rung: string;
|
|
34
|
+
/**
|
|
35
|
+
* The resolved themeable tokens (the baked metafield's `tokens`) — includes the v2
|
|
36
|
+
* `barInk`/`inkColor`, so this is a superset of the input `CertThemeTokens` (which
|
|
37
|
+
* predates brand-ink theming). Inlined structurally to match what the exporter bakes.
|
|
38
|
+
*/
|
|
39
|
+
readonly tokens: {
|
|
40
|
+
readonly accentColor?: string;
|
|
41
|
+
readonly surface?: string;
|
|
42
|
+
readonly cornerRadius?: string;
|
|
43
|
+
readonly fontSlot?: string;
|
|
44
|
+
readonly barInk?: string;
|
|
45
|
+
readonly inkColor?: string;
|
|
46
|
+
};
|
|
47
|
+
/** The auto-contrast bar foreground — present only on a barInk-themed face (v2). */
|
|
48
|
+
readonly barInkFg?: '#141414' | '#ffffff';
|
|
49
|
+
/** The subtractive field-visibility hide-set. */
|
|
50
|
+
readonly hidden: readonly string[];
|
|
51
|
+
/** v2 layout axis. Omitted ⇒ 'banner'. */
|
|
52
|
+
readonly layout?: string;
|
|
53
|
+
/** Custom-face composition — present only when layout === 'custom'. */
|
|
54
|
+
readonly customFace?: {
|
|
55
|
+
readonly placedFields: readonly string[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The OPTIONS a brand's native cert component receives. Delivered per certified
|
|
60
|
+
* article; until the brand registers the component the block renders nothing.
|
|
61
|
+
*/
|
|
62
|
+
export interface BuilderCertChromeData {
|
|
63
|
+
/**
|
|
64
|
+
* The credentialed byline — credential + dated CertREV verification as ONE
|
|
65
|
+
* inseparable string. Null when the R1 gate fails (a displayed credential is
|
|
66
|
+
* unverified / missing `verified_at`); the brand then has only `bylinePlain`.
|
|
67
|
+
*/
|
|
68
|
+
bylineCredentialed: string | null;
|
|
69
|
+
/**
|
|
70
|
+
* The RAW verified credential welded to its dated verification, delivered as ONE
|
|
71
|
+
* INSEPARABLE PAIR (present together) or `null` (omitted together). The WHOLE
|
|
72
|
+
* point: the type hands the brand `credential` and `verifiedAt` only as the two
|
|
73
|
+
* keys of one object, so a bare credential without its dated verification is
|
|
74
|
+
* UNCONSTRUCTIBLE — the fused-verification invariant enforced by construction, not
|
|
75
|
+
* a hopeful side rule. Non-null iff `bylineCredentialed` is. The sidebar/banner
|
|
76
|
+
* faces map this to their `credential` + `credentialVerifiedAt` inputs.
|
|
77
|
+
*/
|
|
78
|
+
credentialVerification: {
|
|
79
|
+
credential: string;
|
|
80
|
+
verifiedAt: string;
|
|
81
|
+
} | null;
|
|
82
|
+
/** The name-only byline (`Reviewed [date] by [Name].`). Always present. */
|
|
83
|
+
bylinePlain: string;
|
|
84
|
+
/** The reviewer's resolved professional name (QA-safe), raw, for a name-only layout. */
|
|
85
|
+
reviewerName: string;
|
|
86
|
+
/** Reviewer's short verified bio, or null (verified-only). */
|
|
87
|
+
bio: string | null;
|
|
88
|
+
/** Reviewer's longer verified background, or null (verified-only). */
|
|
89
|
+
background: string | null;
|
|
90
|
+
/** The QA-SCREENED `verifiedExpertMemo` (never the raw in-flight `expertMemo`), or null. */
|
|
91
|
+
memo: string | null;
|
|
92
|
+
/** The compensation cue (`Compensated expert`). Null for a pro-bono reviewer. */
|
|
93
|
+
compensationCue: string | null;
|
|
94
|
+
/** The verbatim FTC scope disclaimer. Always present. */
|
|
95
|
+
scopeLine: string;
|
|
96
|
+
/** Reviewer photo URL (cert-frozen override ?? live), or null. */
|
|
97
|
+
reviewerPhoto: string | null;
|
|
98
|
+
/** The CertREV expert-profile URL (`certrev.com/expert/{id}`) — never LinkedIn. */
|
|
99
|
+
reviewerProfileUrl: string | null;
|
|
100
|
+
/** The public certificate-verification URL (`/verify/{id}`). */
|
|
101
|
+
verifyUrl: string;
|
|
102
|
+
/** When the article was certified (ISO 8601) — the same date baked into the bylines. */
|
|
103
|
+
certifiedAt: string;
|
|
104
|
+
/** The last real content change after certification (ISO 8601), or null. */
|
|
105
|
+
contentModifiedAt: string | null;
|
|
106
|
+
/** The article's AUTHOR (a different person from the reviewer; carries no verification claim). */
|
|
107
|
+
authorName: string | null;
|
|
108
|
+
authorTitle: string | null;
|
|
109
|
+
/** Brand display prefs the rendering component honors. */
|
|
110
|
+
display: {
|
|
111
|
+
showExpertPhoto: boolean;
|
|
112
|
+
/** When false the component renders `bylinePlain` even if the credentialed form was delivered. */
|
|
113
|
+
showCredentials: boolean;
|
|
114
|
+
};
|
|
115
|
+
/** The brand's ACTIVE resolved render-def projection, or null (⇒ preset default). */
|
|
116
|
+
renderDef: CertChromeRenderDef | null;
|
|
117
|
+
/** Version of the delivered string set (`data-certrev-strings-version` for the crawl monitor). */
|
|
118
|
+
stringsVersion: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The ordered keys of `BuilderCertChromeData` — the SINGLE SOURCE the Builder
|
|
122
|
+
* `inputs` array and the W3 exporter⇄inputs⇄wire-type parity lock derive from, so
|
|
123
|
+
* the three can never silently drift again (POR-10721 W3). Adding a field to the
|
|
124
|
+
* interface without adding it here (or vice-versa) fails the `keyof` exhaustiveness
|
|
125
|
+
* check in `assertChromeKeysExhaustive` below.
|
|
126
|
+
*/
|
|
127
|
+
export declare const BUILDER_CERT_CHROME_KEYS: readonly ["bylineCredentialed", "credentialVerification", "bylinePlain", "reviewerName", "bio", "background", "memo", "compensationCue", "scopeLine", "reviewerPhoto", "reviewerProfileUrl", "verifyUrl", "certifiedAt", "contentModifiedAt", "authorName", "authorTitle", "display", "renderDef", "stringsVersion"];
|
|
128
|
+
export type BuilderCertChromeKey = (typeof BUILDER_CERT_CHROME_KEYS)[number];
|
|
129
|
+
//# sourceMappingURL=cert-chrome-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-chrome-data.d.ts","sourceRoot":"","sources":["../../src/builder/cert-chrome-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE;QAChB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;QAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;QAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;QAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;IACD,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IACzC,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAA;CAClE;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACrC;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC;;;;;;;;OAQG;IACH,sBAAsB,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACzE,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAA;IACnB,wFAAwF;IACxF,YAAY,EAAE,MAAM,CAAA;IACpB,8DAA8D;IAC9D,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,sEAAsE;IACtE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,iFAAiF;IACjF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,mFAAmF;IACnF,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,gEAAgE;IAChE,SAAS,EAAE,MAAM,CAAA;IACjB,wFAAwF;IACxF,WAAW,EAAE,MAAM,CAAA;IACnB,4EAA4E;IAC5E,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IAChC,kGAAkG;IAClG,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,0DAA0D;IAC1D,OAAO,EAAE;QACR,eAAe,EAAE,OAAO,CAAA;QACxB,kGAAkG;QAClG,eAAe,EAAE,OAAO,CAAA;KACxB,CAAA;IACD,qFAAqF;IACrF,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAA;IACrC,kGAAkG;IAClG,cAAc,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,sTAoB3B,CAAA;AAEV,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAA"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
* `BuilderCertChromeData` — the CANONICAL headless cert-chrome wire type
|
|
4
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* The brand-render projection of the cert envelope (portal POR-10091) — the OPTIONS
|
|
7
|
+
* of a brand's native cert component (e.g. e.l.f.'s registered `CertReviewCard`) on
|
|
8
|
+
* a headless blocks-mode entry (Builder.io). CertREV serves the data + the ready-made
|
|
9
|
+
* strings; the brand renders it within the design-guide ladder (enforced live by the
|
|
10
|
+
* crawl monitor + the MSA anti-stripping teeth).
|
|
11
|
+
*
|
|
12
|
+
* SINGLE SOURCE (POR-10721 W1): this type is HOMED HERE so the portal exporter
|
|
13
|
+
* (`src/lib/builder/cert-chrome.ts`) and the kit component (`CertReviewCard`) +
|
|
14
|
+
* `BUILDER_REGISTRATION.inputs` all reference ONE definition — killing the drift the
|
|
15
|
+
* hand-rolled Hydrogen-replica component suffered (it carried a stale separate
|
|
16
|
+
* `credential`/`credentialVerifiedAt` shape from before the fused-pair projection).
|
|
17
|
+
* Keep byte-for-byte in sync with the portal interface until the portal migrates to
|
|
18
|
+
* import THIS (that migration is gated on publishing the package that carries it).
|
|
19
|
+
*
|
|
20
|
+
* PURITY: types + a pure key tuple only — no runtime deps, tree-shakeable.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The ordered keys of `BuilderCertChromeData` — the SINGLE SOURCE the Builder
|
|
24
|
+
* `inputs` array and the W3 exporter⇄inputs⇄wire-type parity lock derive from, so
|
|
25
|
+
* the three can never silently drift again (POR-10721 W3). Adding a field to the
|
|
26
|
+
* interface without adding it here (or vice-versa) fails the `keyof` exhaustiveness
|
|
27
|
+
* check in `assertChromeKeysExhaustive` below.
|
|
28
|
+
*/
|
|
29
|
+
export const BUILDER_CERT_CHROME_KEYS = [
|
|
30
|
+
'bylineCredentialed',
|
|
31
|
+
'credentialVerification',
|
|
32
|
+
'bylinePlain',
|
|
33
|
+
'reviewerName',
|
|
34
|
+
'bio',
|
|
35
|
+
'background',
|
|
36
|
+
'memo',
|
|
37
|
+
'compensationCue',
|
|
38
|
+
'scopeLine',
|
|
39
|
+
'reviewerPhoto',
|
|
40
|
+
'reviewerProfileUrl',
|
|
41
|
+
'verifyUrl',
|
|
42
|
+
'certifiedAt',
|
|
43
|
+
'contentModifiedAt',
|
|
44
|
+
'authorName',
|
|
45
|
+
'authorTitle',
|
|
46
|
+
'display',
|
|
47
|
+
'renderDef',
|
|
48
|
+
'stringsVersion',
|
|
49
|
+
];
|
|
50
|
+
/**
|
|
51
|
+
* Compile-time proof that `BUILDER_CERT_CHROME_KEYS` === `keyof BuilderCertChromeData`
|
|
52
|
+
* exactly (both directions). If a field is added/removed on the interface without the
|
|
53
|
+
* matching key edit, ONE of these two assignments stops type-checking — so the tuple
|
|
54
|
+
* can never drift from the type silently.
|
|
55
|
+
*/
|
|
56
|
+
const _keysCoverType = Object.fromEntries(BUILDER_CERT_CHROME_KEYS.map((k) => [k, true]));
|
|
57
|
+
const _typeCoversKeys = _keysCoverType;
|
|
58
|
+
void _typeCoversKeys;
|
|
59
|
+
//# sourceMappingURL=cert-chrome-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-chrome-data.js","sourceRoot":"","sources":["../../src/builder/cert-chrome-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAiGH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACvC,oBAAoB;IACpB,wBAAwB;IACxB,aAAa;IACb,cAAc;IACd,KAAK;IACL,YAAY;IACZ,MAAM;IACN,iBAAiB;IACjB,WAAW;IACX,eAAe;IACf,oBAAoB;IACpB,WAAW;IACX,aAAa;IACb,mBAAmB;IACnB,YAAY;IACZ,aAAa;IACb,SAAS;IACT,WAAW;IACX,gBAAgB;CACP,CAAA;AAIV;;;;;GAKG;AACH,MAAM,cAAc,GAA8C,MAAM,CAAC,WAAW,CACnF,wBAAwB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CACR,CAAA;AACvC,MAAM,eAAe,GAAuC,cAAc,CAAA;AAC1E,KAAK,eAAe,CAAA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
* `CertReviewCard` — the ready-to-register Builder.io PUSH cert component (W1)
|
|
4
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
*
|
|
6
|
+
* A headless brand (e.l.f.) registers `BUILDER_REGISTRATION` in its Builder
|
|
7
|
+
* `customComponents` and CertREV's exporter emits a block whose options are the
|
|
8
|
+
* `BuilderCertChromeData` projection — so the visible cert chrome renders itself,
|
|
9
|
+
* design-identical to the Shopify Liquid + WordPress PHP faces (same `renderCertBlock`
|
|
10
|
+
* string renderer). This REPLACES the ~200-line hand-rolled component every headless
|
|
11
|
+
* brand copied from the demo (POR-10721 W1).
|
|
12
|
+
*
|
|
13
|
+
* Improvements over the canary demo's hand-rolled version:
|
|
14
|
+
* - consumes the CANONICAL `BuilderCertChromeData` (the fused `credentialVerification`
|
|
15
|
+
* pair — a credential is UNCONSTRUCTIBLE without its dated verification), not the
|
|
16
|
+
* demo's stale separate `credential`/`credentialVerifiedAt` fields;
|
|
17
|
+
* - maps v2 `barInk`/`inkColor` into the theme (the demo predated brand-ink theming);
|
|
18
|
+
* - honors `display.showCredentials`.
|
|
19
|
+
*/
|
|
20
|
+
import { type CertBlockMode } from '../components/render-cert-block.js';
|
|
21
|
+
import type { BuilderCertChromeData } from './cert-chrome-data.js';
|
|
22
|
+
/**
|
|
23
|
+
* The canonical Builder block name. A brand's registration + the portal
|
|
24
|
+
* `certComponent` connection field default to THIS; config exists only for
|
|
25
|
+
* deviation (portal `client-for-brand.ts` gains the default in a follow-up).
|
|
26
|
+
*/
|
|
27
|
+
export declare const CERT_COMPONENT_NAME = "CertREV Cert";
|
|
28
|
+
export interface CertReviewCardProps extends Partial<BuilderCertChromeData> {
|
|
29
|
+
/** Placement face — the ENTRY/editor chooses this, NOT the exporter (not a wire-type field). */
|
|
30
|
+
mode?: CertBlockMode | null;
|
|
31
|
+
/**
|
|
32
|
+
* Banner memo placement (not a wire-type field — the ENTRY/editor chooses it). Passed
|
|
33
|
+
* straight through to `renderCertBlock`'s first-class `part` (POR-10741): `'full'`
|
|
34
|
+
* (default) renders header + memo in one block; `'header'`/`'memo'` render only that
|
|
35
|
+
* card so the memo can be placed as its own block under the article body. The old
|
|
36
|
+
* string-splitting shim is gone — `renderCertBlock` composes each part directly.
|
|
37
|
+
*/
|
|
38
|
+
part?: 'full' | 'header' | 'memo' | null;
|
|
39
|
+
}
|
|
40
|
+
export declare function CertReviewCard(props: CertReviewCardProps): import("react").JSX.Element | null;
|
|
41
|
+
/** The subset of the Builder.io input schema this kit emits. */
|
|
42
|
+
export interface BuilderInput {
|
|
43
|
+
readonly name: string;
|
|
44
|
+
readonly type: 'string' | 'longText' | 'object' | 'boolean' | 'number';
|
|
45
|
+
readonly friendlyName?: string;
|
|
46
|
+
readonly helperText?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The wire-type inputs — DERIVED from `BUILDER_CERT_CHROME_KEYS`, so the 19-field
|
|
50
|
+
* option set can never drift from the type (the W3 lock asserts name-parity). This
|
|
51
|
+
* kills the demo's hand-maintained 17-entry array.
|
|
52
|
+
*/
|
|
53
|
+
export declare const WIRE_INPUTS: readonly BuilderInput[];
|
|
54
|
+
/** Placement inputs — chosen by the entry/editor, NOT emitted by the exporter (not wire-type keys). */
|
|
55
|
+
export declare const PLACEMENT_INPUTS: readonly BuilderInput[];
|
|
56
|
+
/** A Builder.io custom-component registration (the general shape; the anchor uses the same). */
|
|
57
|
+
export interface CertBlockBuilderRegistration {
|
|
58
|
+
readonly name: string;
|
|
59
|
+
readonly component: typeof CertReviewCard;
|
|
60
|
+
readonly inputs: readonly BuilderInput[];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Ready to spread into a brand's Builder `customComponents`:
|
|
64
|
+
* `Builder.registerComponent(BUILDER_REGISTRATION.component, BUILDER_REGISTRATION)`.
|
|
65
|
+
* The exporter-emitted option keys === these `inputs` === the wire type — locked by W3.
|
|
66
|
+
*/
|
|
67
|
+
export declare const BUILDER_REGISTRATION: CertBlockBuilderRegistration;
|
|
68
|
+
//# sourceMappingURL=cert-review-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-review-card.d.ts","sourceRoot":"","sources":["../../src/builder/cert-review-card.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,aAAa,EAAmB,MAAM,oCAAoC,CAAA;AAExF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAGlE;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,iBAAiB,CAAA;AAEjD,MAAM,WAAW,mBAAoB,SAAQ,OAAO,CAAC,qBAAqB,CAAC;IAC1E,gGAAgG;IAChG,IAAI,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;IAC3B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAA;CACxC;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,sCAyDxD;AAMD,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAA;IACtE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC5B;AAyBD;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,YAAY,EAG5C,CAAA;AAEH,uGAAuG;AACvG,eAAO,MAAM,gBAAgB,EAAE,SAAS,YAAY,EAQnD,CAAA;AAED,gGAAgG;AAChG,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,OAAO,cAAc,CAAA;IACzC,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;CACxC;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,4BAIlC,CAAA"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
* `CertReviewCard` — the ready-to-register Builder.io PUSH cert component (W1)
|
|
5
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
*
|
|
7
|
+
* A headless brand (e.l.f.) registers `BUILDER_REGISTRATION` in its Builder
|
|
8
|
+
* `customComponents` and CertREV's exporter emits a block whose options are the
|
|
9
|
+
* `BuilderCertChromeData` projection — so the visible cert chrome renders itself,
|
|
10
|
+
* design-identical to the Shopify Liquid + WordPress PHP faces (same `renderCertBlock`
|
|
11
|
+
* string renderer). This REPLACES the ~200-line hand-rolled component every headless
|
|
12
|
+
* brand copied from the demo (POR-10721 W1).
|
|
13
|
+
*
|
|
14
|
+
* Improvements over the canary demo's hand-rolled version:
|
|
15
|
+
* - consumes the CANONICAL `BuilderCertChromeData` (the fused `credentialVerification`
|
|
16
|
+
* pair — a credential is UNCONSTRUCTIBLE without its dated verification), not the
|
|
17
|
+
* demo's stale separate `credential`/`credentialVerifiedAt` fields;
|
|
18
|
+
* - maps v2 `barInk`/`inkColor` into the theme (the demo predated brand-ink theming);
|
|
19
|
+
* - honors `display.showCredentials`.
|
|
20
|
+
*/
|
|
21
|
+
import { renderCertBlock } from '../components/render-cert-block.js';
|
|
22
|
+
import { BUILDER_CERT_CHROME_KEYS } from './cert-chrome-data.js';
|
|
23
|
+
/**
|
|
24
|
+
* The canonical Builder block name. A brand's registration + the portal
|
|
25
|
+
* `certComponent` connection field default to THIS; config exists only for
|
|
26
|
+
* deviation (portal `client-for-brand.ts` gains the default in a follow-up).
|
|
27
|
+
*/
|
|
28
|
+
export const CERT_COMPONENT_NAME = 'CertREV Cert';
|
|
29
|
+
export function CertReviewCard(props) {
|
|
30
|
+
const { reviewerName, verifyUrl } = props;
|
|
31
|
+
if (!reviewerName || !verifyUrl)
|
|
32
|
+
return null; // no chrome pre-cert
|
|
33
|
+
// The credential + its verification date arrive ONLY as the fused pair, so we can
|
|
34
|
+
// never obtain one without the other (name-only face when the pair is null, or when
|
|
35
|
+
// the brand set showCredentials:false). This IS the R1 gate, enforced by the type.
|
|
36
|
+
const cv = props.credentialVerification ?? null;
|
|
37
|
+
const showCred = props.display?.showCredentials !== false;
|
|
38
|
+
const withCred = cv && showCred ? cv : null;
|
|
39
|
+
const tokens = props.renderDef?.tokens;
|
|
40
|
+
const theme = tokens
|
|
41
|
+
? {
|
|
42
|
+
accentColor: tokens.accentColor,
|
|
43
|
+
surface: tokens.surface,
|
|
44
|
+
cornerRadius: tokens.cornerRadius,
|
|
45
|
+
fontSlot: tokens.fontSlot,
|
|
46
|
+
// v2 brand-ink (post-demo): the bar + free-content ink follow the def.
|
|
47
|
+
barInk: tokens.barInk,
|
|
48
|
+
inkColor: tokens.inkColor,
|
|
49
|
+
}
|
|
50
|
+
: undefined;
|
|
51
|
+
const html = renderCertBlock({
|
|
52
|
+
mode: props.mode ?? 'banner',
|
|
53
|
+
theme,
|
|
54
|
+
// First-class banner memo split (POR-10741) — renderCertBlock composes the requested
|
|
55
|
+
// part directly; no string-splitting. Ignored outside banner mode.
|
|
56
|
+
...(props.part ? { part: props.part } : {}),
|
|
57
|
+
facts: {
|
|
58
|
+
authorName: props.authorName ?? 'Editorial',
|
|
59
|
+
authorTitle: props.authorTitle ?? undefined,
|
|
60
|
+
reviewerName,
|
|
61
|
+
credential: withCred ? withCred.credential : '',
|
|
62
|
+
credentialVerifiedAt: withCred ? withCred.verifiedAt : '',
|
|
63
|
+
certifiedAt: props.certifiedAt ?? '',
|
|
64
|
+
memo: props.memo ?? '',
|
|
65
|
+
bio: props.bio ?? undefined,
|
|
66
|
+
profileUrl: props.reviewerProfileUrl ?? '',
|
|
67
|
+
certificateUrl: verifyUrl,
|
|
68
|
+
// Locked strings default byte-verbatim inside renderCertBlock; pass the
|
|
69
|
+
// delivered cue/scope through so a pro-bono (null-cue) delivery is honored.
|
|
70
|
+
...(props.compensationCue ? { compensationCue: props.compensationCue } : {}),
|
|
71
|
+
...(props.scopeLine ? { scopeLine: props.scopeLine } : {}),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
return (_jsx("div", { "data-certrev-cert-chrome": "", "data-certrev-strings-version": props.stringsVersion ?? undefined, "data-certrev-def-version": props.renderDef?.v ?? undefined,
|
|
75
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: renderCertBlock is the escaping-safe SSR string renderer
|
|
76
|
+
dangerouslySetInnerHTML: { __html: html } }));
|
|
77
|
+
}
|
|
78
|
+
/** Builder input TYPE per wire-type key — the exporter serializes these option values. */
|
|
79
|
+
const WIRE_INPUT_TYPE = {
|
|
80
|
+
bylineCredentialed: 'string',
|
|
81
|
+
credentialVerification: 'object',
|
|
82
|
+
bylinePlain: 'string',
|
|
83
|
+
reviewerName: 'string',
|
|
84
|
+
bio: 'longText',
|
|
85
|
+
background: 'longText',
|
|
86
|
+
memo: 'longText',
|
|
87
|
+
compensationCue: 'string',
|
|
88
|
+
scopeLine: 'string',
|
|
89
|
+
reviewerPhoto: 'string',
|
|
90
|
+
reviewerProfileUrl: 'string',
|
|
91
|
+
verifyUrl: 'string',
|
|
92
|
+
certifiedAt: 'string',
|
|
93
|
+
contentModifiedAt: 'string',
|
|
94
|
+
authorName: 'string',
|
|
95
|
+
authorTitle: 'string',
|
|
96
|
+
display: 'object',
|
|
97
|
+
renderDef: 'object',
|
|
98
|
+
stringsVersion: 'string',
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The wire-type inputs — DERIVED from `BUILDER_CERT_CHROME_KEYS`, so the 19-field
|
|
102
|
+
* option set can never drift from the type (the W3 lock asserts name-parity). This
|
|
103
|
+
* kills the demo's hand-maintained 17-entry array.
|
|
104
|
+
*/
|
|
105
|
+
export const WIRE_INPUTS = BUILDER_CERT_CHROME_KEYS.map((name) => ({
|
|
106
|
+
name,
|
|
107
|
+
type: WIRE_INPUT_TYPE[name],
|
|
108
|
+
}));
|
|
109
|
+
/** Placement inputs — chosen by the entry/editor, NOT emitted by the exporter (not wire-type keys). */
|
|
110
|
+
export const PLACEMENT_INPUTS = [
|
|
111
|
+
{
|
|
112
|
+
name: 'mode',
|
|
113
|
+
type: 'string',
|
|
114
|
+
friendlyName: 'Placement',
|
|
115
|
+
helperText: 'banner (default) · sidebar · floating',
|
|
116
|
+
},
|
|
117
|
+
{ name: 'part', type: 'string', friendlyName: 'Banner part', helperText: 'full (default) · header · memo' },
|
|
118
|
+
];
|
|
119
|
+
/**
|
|
120
|
+
* Ready to spread into a brand's Builder `customComponents`:
|
|
121
|
+
* `Builder.registerComponent(BUILDER_REGISTRATION.component, BUILDER_REGISTRATION)`.
|
|
122
|
+
* The exporter-emitted option keys === these `inputs` === the wire type — locked by W3.
|
|
123
|
+
*/
|
|
124
|
+
export const BUILDER_REGISTRATION = {
|
|
125
|
+
name: CERT_COMPONENT_NAME,
|
|
126
|
+
component: CertReviewCard,
|
|
127
|
+
inputs: [...PLACEMENT_INPUTS, ...WIRE_INPUTS],
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=cert-review-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cert-review-card.js","sourceRoot":"","sources":["../../src/builder/cert-review-card.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAsB,eAAe,EAAE,MAAM,oCAAoC,CAAA;AAGxF,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAEhE;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,cAAc,CAAA;AAejD,MAAM,UAAU,cAAc,CAAC,KAA0B;IACxD,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,KAAK,CAAA;IACzC,IAAI,CAAC,YAAY,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAA,CAAC,qBAAqB;IAElE,kFAAkF;IAClF,oFAAoF;IACpF,mFAAmF;IACnF,MAAM,EAAE,GAAG,KAAK,CAAC,sBAAsB,IAAI,IAAI,CAAA;IAC/C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,EAAE,eAAe,KAAK,KAAK,CAAA;IACzD,MAAM,QAAQ,GAAG,EAAE,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAE3C,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,MAAM,CAAA;IACtC,MAAM,KAAK,GAA4C,MAAM;QAC5D,CAAC,CAAC;YACA,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,QAAQ,EAAE,MAAM,CAAC,QAAsD;YACvE,uEAAuE;YACvE,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SACzB;QACF,CAAC,CAAC,SAAS,CAAA;IAEZ,MAAM,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,EAAG,KAAK,CAAC,IAAsB,IAAI,QAAQ;QAC/C,KAAK;QACL,qFAAqF;QACrF,mEAAmE;QACnE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,KAAK,EAAE;YACN,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,WAAW;YAC3C,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,SAAS;YAC3C,YAAY;YACZ,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;YAC/C,oBAAoB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;YACzD,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,EAAE;YACpC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,SAAS;YAC3B,UAAU,EAAE,KAAK,CAAC,kBAAkB,IAAI,EAAE;YAC1C,cAAc,EAAE,SAAS;YACzB,wEAAwE;YACxE,4EAA4E;YAC5E,GAAG,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1D;KACD,CAAC,CAAA;IAEF,OAAO,CACN,0CAC0B,EAAE,kCACG,KAAK,CAAC,cAAc,IAAI,SAAS,8BACrC,KAAK,CAAC,SAAS,EAAE,CAAC,IAAI,SAAS;QACzD,iHAAiH;QACjH,uBAAuB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GACxC,CACF,CAAA;AACF,CAAC;AAcD,0FAA0F;AAC1F,MAAM,eAAe,GAA4E;IAChG,kBAAkB,EAAE,QAAQ;IAC5B,sBAAsB,EAAE,QAAQ;IAChC,WAAW,EAAE,QAAQ;IACrB,YAAY,EAAE,QAAQ;IACtB,GAAG,EAAE,UAAU;IACf,UAAU,EAAE,UAAU;IACtB,IAAI,EAAE,UAAU;IAChB,eAAe,EAAE,QAAQ;IACzB,SAAS,EAAE,QAAQ;IACnB,aAAa,EAAE,QAAQ;IACvB,kBAAkB,EAAE,QAAQ;IAC5B,SAAS,EAAE,QAAQ;IACnB,WAAW,EAAE,QAAQ;IACrB,iBAAiB,EAAE,QAAQ;IAC3B,UAAU,EAAE,QAAQ;IACpB,WAAW,EAAE,QAAQ;IACrB,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,QAAQ;IACnB,cAAc,EAAE,QAAQ;CACxB,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAA4B,wBAAwB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC3F,IAAI;IACJ,IAAI,EAAE,eAAe,CAAC,IAAI,CAAC;CAC3B,CAAC,CAAC,CAAA;AAEH,uGAAuG;AACvG,MAAM,CAAC,MAAM,gBAAgB,GAA4B;IACxD;QACC,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,QAAQ;QACd,YAAY,EAAE,WAAW;QACzB,UAAU,EAAE,uCAAuC;KACnD;IACD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,gCAAgC,EAAE;CAC3G,CAAA;AASD;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAiC;IACjE,IAAI,EAAE,mBAAmB;IACzB,SAAS,EAAE,cAAc;IACzB,MAAM,EAAE,CAAC,GAAG,gBAAgB,EAAE,GAAG,WAAW,CAAC;CAC7C,CAAA"}
|
package/dist/builder/index.d.ts
CHANGED
|
@@ -72,4 +72,6 @@ export interface CertRevBuilderRegistration {
|
|
|
72
72
|
* (truth). Matched by NAME at render, so Write-API content works without visual-editor setup.
|
|
73
73
|
*/
|
|
74
74
|
export declare const certRevAnchorComponent: CertRevBuilderRegistration;
|
|
75
|
+
export { BUILDER_CERT_CHROME_KEYS, type BuilderCertChromeData, type BuilderCertChromeKey, type CertChromeRenderDef, } from './cert-chrome-data.js';
|
|
76
|
+
export { BUILDER_REGISTRATION, type BuilderInput, CERT_COMPONENT_NAME, type CertBlockBuilderRegistration, CertReviewCard, type CertReviewCardProps, PLACEMENT_INPUTS, WIRE_INPUTS, } from './cert-review-card.js';
|
|
75
77
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builder/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAiB,KAAK,SAAS,EAAc,MAAM,OAAO,CAAA;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,2FAA2F;AAC3F,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,sGAAsG;IACtG,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CACzB;AASD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC/B,OAAO,EACP,SAAiB,EACjB,QAAQ,GACR,EAAE;IACF,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC5B,+BAEA;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,gCAiBvC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,uCAO5B;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C,SAAS,EAAE,OAAO,aAAa,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,KAAK,EAAE,CAAA;CACf;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,0BAIpC,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builder/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAiB,KAAK,SAAS,EAAc,MAAM,OAAO,CAAA;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,2FAA2F;AAC3F,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;IAC7B,sGAAsG;IACtG,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CACzB;AASD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC/B,OAAO,EACP,SAAiB,EACjB,QAAQ,GACR,EAAE;IACF,QAAQ,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAA;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;CAC5B,+BAEA;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,gCAiBvC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,uCAO5B;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IAC1C,SAAS,EAAE,OAAO,aAAa,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,KAAK,EAAE,CAAA;CACf;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,0BAIpC,CAAA;AAGD,OAAO,EACN,wBAAwB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACxB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACN,oBAAoB,EACpB,KAAK,YAAY,EACjB,mBAAmB,EACnB,KAAK,4BAA4B,EACjC,cAAc,EACd,KAAK,mBAAmB,EACxB,gBAAgB,EAChB,WAAW,GACX,MAAM,uBAAuB,CAAA"}
|
package/dist/builder/index.js
CHANGED
|
@@ -77,4 +77,7 @@ export const certRevAnchorComponent = {
|
|
|
77
77
|
name: 'CertREV Review',
|
|
78
78
|
inputs: [],
|
|
79
79
|
};
|
|
80
|
+
// ── POR-10721 W1/W3: the Builder.io PUSH kit (CertReviewCard) + single-sourced wire type ──
|
|
81
|
+
export { BUILDER_CERT_CHROME_KEYS, } from './cert-chrome-data.js';
|
|
82
|
+
export { BUILDER_REGISTRATION, CERT_COMPONENT_NAME, CertReviewCard, PLACEMENT_INPUTS, WIRE_INPUTS, } from './cert-review-card.js';
|
|
80
83
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/builder/index.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,aAAa,EAAkB,UAAU,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAexD,MAAM,cAAc,GAAG,aAAa,CAAsB,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;AAE9F;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,EAC/B,OAAO,EACP,SAAS,GAAG,KAAK,EACjB,QAAQ,GAKR;IACA,OAAO,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,YAAG,QAAQ,GAA2B,CAAA;AACpG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB;IACvC,OAAO,CACN,kDACiC,EAAE,EAClC,KAAK,EAAE;YACN,MAAM,EAAE,oBAAoB;YAC5B,YAAY,EAAE,CAAC;YACf,OAAO,EAAE,WAAW;YACpB,IAAI,EAAE,gBAAgB;YACtB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,SAAS;SACrB,uCAEgB,8CAA0B,oJAEtC,CACN,CAAA;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa;IAC5B,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,cAAc,CAAC,CAAA;IACzD,IAAI,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtD,OAAO,KAAC,UAAU,IAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,SAAG,CAAA;IACrF,CAAC;IACD,IAAI,SAAS;QAAE,OAAO,KAAC,wBAAwB,KAAG,CAAA;IAClD,OAAO,IAAI,CAAA;AACZ,CAAC;AAaD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA+B;IACjE,SAAS,EAAE,aAAa;IACxB,IAAI,EAAE,gBAAgB;IACtB,MAAM,EAAE,EAAE;CACV,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/builder/index.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,aAAa,EAAkB,UAAU,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAexD,MAAM,cAAc,GAAG,aAAa,CAAsB,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;AAE9F;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,EAC/B,OAAO,EACP,SAAS,GAAG,KAAK,EACjB,QAAQ,GAKR;IACA,OAAO,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,YAAG,QAAQ,GAA2B,CAAA;AACpG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB;IACvC,OAAO,CACN,kDACiC,EAAE,EAClC,KAAK,EAAE;YACN,MAAM,EAAE,oBAAoB;YAC5B,YAAY,EAAE,CAAC;YACf,OAAO,EAAE,WAAW;YACpB,IAAI,EAAE,gBAAgB;YACtB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,SAAS;SACrB,uCAEgB,8CAA0B,oJAEtC,CACN,CAAA;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa;IAC5B,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,cAAc,CAAC,CAAA;IACzD,IAAI,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACtD,OAAO,KAAC,UAAU,IAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,UAAU,SAAG,CAAA;IACrF,CAAC;IACD,IAAI,SAAS;QAAE,OAAO,KAAC,wBAAwB,KAAG,CAAA;IAClD,OAAO,IAAI,CAAA;AACZ,CAAC;AAaD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA+B;IACjE,SAAS,EAAE,aAAa;IACxB,IAAI,EAAE,gBAAgB;IACtB,MAAM,EAAE,EAAE;CACV,CAAA;AAED,6FAA6F;AAC7F,OAAO,EACN,wBAAwB,GAIxB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACN,oBAAoB,EAEpB,mBAAmB,EAEnB,cAAc,EAEd,gBAAgB,EAChB,WAAW,GACX,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `renderPreviewBlock` — a STATIC, NON-DELIVERY preview of the cert block for pre-sales
|
|
3
|
+
* look-demos (POR-10743, from the e.l.f. Builder demo).
|
|
4
|
+
*
|
|
5
|
+
* The visual is BYTE-FOR-BYTE `renderCertBlock` (pixel-parity — "see it on your own site
|
|
6
|
+
* today"), wrapped in a `[data-certrev-preview]` container carrying a REQUIRED expiry.
|
|
7
|
+
*
|
|
8
|
+
* Why it is safe by construction — and can NEVER be delivery:
|
|
9
|
+
* - A preview has NO signed envelope and NO modal. CertREV's verify / badge-revalidation /
|
|
10
|
+
* crawl-audit all key off a signed `CertDeliveryEnvelope`; an unsigned block is SUPPRESSED
|
|
11
|
+
* on any live verify, never rendered as a certification. So a preview literally cannot pass
|
|
12
|
+
* as a delivered cert — the "never delivery" property is structural, not a policy.
|
|
13
|
+
* - The container marker (`data-certrev-preview="1"`) + the default-on visible label make it
|
|
14
|
+
* unmistakable to humans AND tooling; the required `data-certrev-preview-expires` bounds its
|
|
15
|
+
* life so a stale snapshot can be refused downstream.
|
|
16
|
+
* - It is NOT revocable — the kill-switch cannot reach a static HTML snapshot — so it must stay
|
|
17
|
+
* demo / draft-only. That is the CALLER's duty; this renderer bakes the markers that let the
|
|
18
|
+
* surrounding systems enforce it.
|
|
19
|
+
*/
|
|
20
|
+
import { type RenderCertBlockInput } from './render-cert-block.js';
|
|
21
|
+
export interface PreviewBlockOptions {
|
|
22
|
+
/**
|
|
23
|
+
* REQUIRED — when this preview expires (ISO 8601). A preview MUST be time-bounded so a stale
|
|
24
|
+
* snapshot can be refused downstream; there is deliberately NO default (an unbounded preview
|
|
25
|
+
* is the drift-into-shadow-delivery risk this option exists to prevent).
|
|
26
|
+
*/
|
|
27
|
+
readonly expiresAt: string;
|
|
28
|
+
/**
|
|
29
|
+
* Show the visible caption. Default `true` — the SAFE default. Opt out (`false`) ONLY for a
|
|
30
|
+
* true pixel-parity look-demo; the machine marker + expiry + non-delivery guarantee remain.
|
|
31
|
+
*/
|
|
32
|
+
readonly showLabel?: boolean;
|
|
33
|
+
/** Override the caption text (default below). */
|
|
34
|
+
readonly labelText?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Extract a preview block's baked expiry (ISO), or null if the HTML isn't a preview block. */
|
|
37
|
+
export declare function previewExpiry(html: string): string | null;
|
|
38
|
+
/**
|
|
39
|
+
* Render a static, clearly-labeled, time-bounded preview of the cert block. See the module doc
|
|
40
|
+
* for the safety model. `expiresAt` is required; throws without it.
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderPreviewBlock(input: RenderCertBlockInput, options: PreviewBlockOptions): string;
|
|
43
|
+
//# sourceMappingURL=preview-block.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-block.d.ts","sourceRoot":"","sources":["../../src/components/preview-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,KAAK,oBAAoB,EAAmB,MAAM,wBAAwB,CAAA;AAEnF,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,iDAAiD;IACjD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAC3B;AAID,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAsBpG"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `renderPreviewBlock` — a STATIC, NON-DELIVERY preview of the cert block for pre-sales
|
|
3
|
+
* look-demos (POR-10743, from the e.l.f. Builder demo).
|
|
4
|
+
*
|
|
5
|
+
* The visual is BYTE-FOR-BYTE `renderCertBlock` (pixel-parity — "see it on your own site
|
|
6
|
+
* today"), wrapped in a `[data-certrev-preview]` container carrying a REQUIRED expiry.
|
|
7
|
+
*
|
|
8
|
+
* Why it is safe by construction — and can NEVER be delivery:
|
|
9
|
+
* - A preview has NO signed envelope and NO modal. CertREV's verify / badge-revalidation /
|
|
10
|
+
* crawl-audit all key off a signed `CertDeliveryEnvelope`; an unsigned block is SUPPRESSED
|
|
11
|
+
* on any live verify, never rendered as a certification. So a preview literally cannot pass
|
|
12
|
+
* as a delivered cert — the "never delivery" property is structural, not a policy.
|
|
13
|
+
* - The container marker (`data-certrev-preview="1"`) + the default-on visible label make it
|
|
14
|
+
* unmistakable to humans AND tooling; the required `data-certrev-preview-expires` bounds its
|
|
15
|
+
* life so a stale snapshot can be refused downstream.
|
|
16
|
+
* - It is NOT revocable — the kill-switch cannot reach a static HTML snapshot — so it must stay
|
|
17
|
+
* demo / draft-only. That is the CALLER's duty; this renderer bakes the markers that let the
|
|
18
|
+
* surrounding systems enforce it.
|
|
19
|
+
*/
|
|
20
|
+
import { escapeAttribute, escapeHtml } from './escape.js';
|
|
21
|
+
import { renderCertBlock } from './render-cert-block.js';
|
|
22
|
+
const DEFAULT_LABEL = 'Preview — not a verified certification';
|
|
23
|
+
/** Extract a preview block's baked expiry (ISO), or null if the HTML isn't a preview block. */
|
|
24
|
+
export function previewExpiry(html) {
|
|
25
|
+
const m = html.match(/data-certrev-preview-expires="([^"]*)"/);
|
|
26
|
+
return m ? m[1] : null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Render a static, clearly-labeled, time-bounded preview of the cert block. See the module doc
|
|
30
|
+
* for the safety model. `expiresAt` is required; throws without it.
|
|
31
|
+
*/
|
|
32
|
+
export function renderPreviewBlock(input, options) {
|
|
33
|
+
const expires = options.expiresAt.trim();
|
|
34
|
+
if (!expires) {
|
|
35
|
+
throw new Error('renderPreviewBlock: `expiresAt` is required — a preview must be time-bounded.');
|
|
36
|
+
}
|
|
37
|
+
// The bound must be REAL — an unparseable expiry is a toothless bound (downstream can't refuse a
|
|
38
|
+
// stale preview it can't date). Reject anything Date can't parse, so `previewExpiry()` consumers
|
|
39
|
+
// always get a usable timestamp.
|
|
40
|
+
if (Number.isNaN(new Date(expires).getTime())) {
|
|
41
|
+
throw new Error(`renderPreviewBlock: \`expiresAt\` must be a parseable date (got "${expires}").`);
|
|
42
|
+
}
|
|
43
|
+
const showLabel = options.showLabel !== false;
|
|
44
|
+
const label = showLabel
|
|
45
|
+
? `<div data-certrev-preview-label style="font:500 11px/1.4 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.08em;text-transform:uppercase;color:#9a9a9a;margin-bottom:8px;">${escapeHtml(options.labelText ?? DEFAULT_LABEL)}</div>`
|
|
46
|
+
: '';
|
|
47
|
+
return (`<!-- CertREV PREVIEW — static, non-revocable, NOT a verified certification. Expires ${escapeHtml(expires)}. Never use as delivery. -->` +
|
|
48
|
+
`<div data-certrev-preview="1" data-certrev-preview-expires="${escapeAttribute(expires)}">` +
|
|
49
|
+
label +
|
|
50
|
+
renderCertBlock(input) +
|
|
51
|
+
`</div>`);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=preview-block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-block.js","sourceRoot":"","sources":["../../src/components/preview-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,EAA6B,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAkBnF,MAAM,aAAa,GAAG,wCAAwC,CAAA;AAE9D,+FAA+F;AAC/F,MAAM,UAAU,aAAa,CAAC,IAAY;IACzC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC9D,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAA2B,EAAE,OAA4B;IAC3F,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAA;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAA;IACjG,CAAC;IACD,iGAAiG;IACjG,iGAAiG;IACjG,iCAAiC;IACjC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,oEAAoE,OAAO,KAAK,CAAC,CAAA;IAClG,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,KAAK,KAAK,CAAA;IAC7C,MAAM,KAAK,GAAG,SAAS;QACtB,CAAC,CAAC,wLAAwL,UAAU,CAAC,OAAO,CAAC,SAAS,IAAI,aAAa,CAAC,QAAQ;QAChP,CAAC,CAAC,EAAE,CAAA;IACL,OAAO,CACN,uFAAuF,UAAU,CAAC,OAAO,CAAC,8BAA8B;QACxI,+DAA+D,eAAe,CAAC,OAAO,CAAC,IAAI;QAC3F,KAAK;QACL,eAAe,CAAC,KAAK,CAAC;QACtB,QAAQ,CACR,CAAA;AACF,CAAC"}
|