@redsift/products 12.5.7 → 12.5.8-muiv8-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -404,6 +404,37 @@ var EXTRACTOR_STRINGS = {
404
404
  "card.bimi.vmc.issuer_md": "**Issuer: {issuer}**",
405
405
  "card.bimi.vmc.trademarkAuthority_md": "**Trademark Authority: {trademarkAuthority}**",
406
406
  "card.bimi.vmc.valid-for-domain_md": "**Valid for domains:** `{domains}`",
407
+ // BIMI VMC/CMC published-certificate metadata (WEB-1137 / DS-93)
408
+ // Validity
409
+ "card.bimi.vmc.cert-section-validity": "Validity",
410
+ "card.bimi.vmc.cert-valid-from_md": "**Start:** {date}",
411
+ "card.bimi.vmc.cert-expiry_md": "**Expiry:** {date}",
412
+ // Certificate
413
+ "card.bimi.vmc.cert-section-certificate": "Certificate",
414
+ "card.bimi.vmc.cert-issuer-common-name_md": "**Issuer:** {issuerCommonName}",
415
+ "card.bimi.vmc.cert-issuer-organization_md": "**Issuer organization:** {issuerOrganization}",
416
+ "card.bimi.vmc.cert-issuer-country_md": "**Issuer country:** {issuerCountry}",
417
+ "card.bimi.vmc.cert-type_md": "**Certificate type:** {assertionMarkType}",
418
+ "card.bimi.vmc.cert-certified-domains_md": "**Certified domains:** `{certifiedDomains}`",
419
+ // Subject identity
420
+ "card.bimi.vmc.cert-section-subject-identity": "Subject identity",
421
+ "card.bimi.vmc.cert-serial-number_md": "**Serial number:** {serialNumber}",
422
+ "card.bimi.vmc.cert-organization_md": "**Organization:** {organization}",
423
+ "card.bimi.vmc.cert-common-name_md": "**Common name:** {commonName}",
424
+ "card.bimi.vmc.cert-business-category_md": "**Business category:** {businessCategory}",
425
+ "card.bimi.vmc.cert-organization-identifier_md": "**Organization identifier:** {organizationIdentifier}",
426
+ "card.bimi.vmc.cert-legal-entity-identifier_md": "**Legal entity identifier:** {legalEntityIdentifier}",
427
+ "card.bimi.vmc.cert-jurisdiction_md": "**Jurisdiction:** {jurisdiction}",
428
+ "card.bimi.vmc.cert-address_md": "**Address:** {address}",
429
+ // Mark evidence
430
+ "card.bimi.vmc.cert-section-mark-evidence": "Mark evidence",
431
+ "card.bimi.vmc.cert-trademark-registration_md": "**Trademark registration:** {trademarkRegistration}",
432
+ "card.bimi.vmc.cert-trademark-office_md": "**Trademark office:** {trademarkOfficeName}",
433
+ "card.bimi.vmc.cert-mark-type_md": "**Mark type:** {markType}",
434
+ "card.bimi.vmc.cert-trademark-country_md": "**Trademark country or region:** {trademarkCountryOrRegion}",
435
+ // Verification issues
436
+ "card.bimi.vmc.cert-section-verification-issues": "Verification issues",
437
+ "card.bimi.vmc.cert-no-issues-reported_md": "None reported",
407
438
  // BIMI section titles
408
439
  "section-titles.bimi-domain": "DMARC Domains",
409
440
  "section-titles.bimi-policy": "Your BIMI Policy",
@@ -843,6 +874,37 @@ var EXTRACTOR_STRINGS = {
843
874
  "card.bimi.vmc.issuer_md": "**Issuer : {issuer}**",
844
875
  "card.bimi.vmc.trademarkAuthority_md": "**Autorit\xE9 de la marque : {trademarkAuthority}**",
845
876
  "card.bimi.vmc.valid-for-domain_md": "**Valide pour les domaines :** `{domains}`",
877
+ // BIMI VMC/CMC published-certificate metadata (WEB-1137 / DS-93)
878
+ // Validity
879
+ "card.bimi.vmc.cert-section-validity": "Validit\xE9",
880
+ "card.bimi.vmc.cert-valid-from_md": "**D\xE9but :** {date}",
881
+ "card.bimi.vmc.cert-expiry_md": "**Expiration :** {date}",
882
+ // Certificate
883
+ "card.bimi.vmc.cert-section-certificate": "Certificat",
884
+ "card.bimi.vmc.cert-issuer-common-name_md": "**\xC9metteur :** {issuerCommonName}",
885
+ "card.bimi.vmc.cert-issuer-organization_md": "**Organisation de l'\xE9metteur :** {issuerOrganization}",
886
+ "card.bimi.vmc.cert-issuer-country_md": "**Pays de l'\xE9metteur :** {issuerCountry}",
887
+ "card.bimi.vmc.cert-type_md": "**Type de certificat :** {assertionMarkType}",
888
+ "card.bimi.vmc.cert-certified-domains_md": "**Domaines certifi\xE9s :** `{certifiedDomains}`",
889
+ // Subject identity
890
+ "card.bimi.vmc.cert-section-subject-identity": "Identit\xE9 du sujet",
891
+ "card.bimi.vmc.cert-serial-number_md": "**Num\xE9ro de s\xE9rie :** {serialNumber}",
892
+ "card.bimi.vmc.cert-organization_md": "**Organisation :** {organization}",
893
+ "card.bimi.vmc.cert-common-name_md": "**Nom commun :** {commonName}",
894
+ "card.bimi.vmc.cert-business-category_md": "**Cat\xE9gorie d'activit\xE9 :** {businessCategory}",
895
+ "card.bimi.vmc.cert-organization-identifier_md": "**Identifiant de l'organisation :** {organizationIdentifier}",
896
+ "card.bimi.vmc.cert-legal-entity-identifier_md": "**Identifiant d'entit\xE9 juridique :** {legalEntityIdentifier}",
897
+ "card.bimi.vmc.cert-jurisdiction_md": "**Juridiction :** {jurisdiction}",
898
+ "card.bimi.vmc.cert-address_md": "**Adresse :** {address}",
899
+ // Mark evidence
900
+ "card.bimi.vmc.cert-section-mark-evidence": "Preuve de la marque",
901
+ "card.bimi.vmc.cert-trademark-registration_md": "**Enregistrement de la marque :** {trademarkRegistration}",
902
+ "card.bimi.vmc.cert-trademark-office_md": "**Office des marques :** {trademarkOfficeName}",
903
+ "card.bimi.vmc.cert-mark-type_md": "**Type de marque :** {markType}",
904
+ "card.bimi.vmc.cert-trademark-country_md": "**Pays ou r\xE9gion de la marque :** {trademarkCountryOrRegion}",
905
+ // Verification issues
906
+ "card.bimi.vmc.cert-section-verification-issues": "Probl\xE8mes de v\xE9rification",
907
+ "card.bimi.vmc.cert-no-issues-reported_md": "Aucun signal\xE9",
846
908
  // BIMI section titles
847
909
  "section-titles.bimi-domain": "Domaines DMARC",
848
910
  "section-titles.bimi-policy": "Votre politique BIMI",
@@ -7957,6 +8019,277 @@ const uncompressLogo = svgUrl => {
7957
8019
 
7958
8020
  var SVGLogo$1 = SVGLogo;
7959
8021
 
8022
+ /**
8023
+ * A rendered published-certificate section: a titled group of Checklist items.
8024
+ */
8025
+
8026
+ /**
8027
+ * Reference URL for the BIMI certificate-type explainer, used by the VMC/CMC
8028
+ * type badge. Follows the existing external-link convention in the card.
8029
+ */
8030
+ const CERT_TYPE_REFERENCE_URL = 'https://bimigroup.org/verified-mark-certificates-vmc-and-bimi/';
8031
+ const DAY_MS = 24 * 60 * 60 * 1000;
8032
+
8033
+ /**
8034
+ * Parse a YYYY-MM-DD date string to a UTC Date. Returns null when the input is
8035
+ * missing or unparseable so callers can degrade gracefully.
8036
+ */
8037
+ const parseIsoDate = value => {
8038
+ if (!value) return null;
8039
+ const parsed = new Date(`${value}T00:00:00Z`);
8040
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
8041
+ };
8042
+
8043
+ /** Whole-day difference between two dates (b - a), truncated toward zero. */
8044
+ const diffInDays = (a, b) => Math.trunc((b.getTime() - a.getTime()) / DAY_MS);
8045
+
8046
+ /**
8047
+ * Humanize the certificate validity start: "Active for {n} days — Since {date}".
8048
+ * The humanized duration is a render-layer responsibility (the API returns only
8049
+ * the raw validFrom date). Falls back to just the date when duration can't be
8050
+ * computed.
8051
+ */
8052
+ const humanizeValidFrom = (validFrom, now) => {
8053
+ const from = parseIsoDate(validFrom);
8054
+ if (!from) return undefined;
8055
+ const days = diffInDays(from, now);
8056
+ if (days < 0) {
8057
+ // validFrom is in the future — not yet active; show the raw date only.
8058
+ return `Not yet active — Since ${validFrom}`;
8059
+ }
8060
+ const unit = days === 1 ? 'day' : 'days';
8061
+ return `Active for ${days} ${unit} — Since ${validFrom}`;
8062
+ };
8063
+
8064
+ /**
8065
+ * Humanize the certificate expiry: "Expires in {n} days — On {date}", or
8066
+ * "Expired {n} days ago — On {date}" when already past. Falls back to the raw
8067
+ * date when duration can't be computed.
8068
+ */
8069
+ const humanizeExpiry = (expiry, now) => {
8070
+ const to = parseIsoDate(expiry);
8071
+ if (!to) return undefined;
8072
+ const days = diffInDays(now, to);
8073
+ if (days < 0) {
8074
+ const ago = Math.abs(days);
8075
+ const unit = ago === 1 ? 'day' : 'days';
8076
+ return `Expired ${ago} ${unit} ago — On ${expiry}`;
8077
+ }
8078
+ const unit = days === 1 ? 'day' : 'days';
8079
+ return `Expires in ${days} ${unit} — On ${expiry}`;
8080
+ };
8081
+
8082
+ /** Join defined, non-empty parts with a separator; undefined when nothing remains. */
8083
+ const joinParts = function (parts) {
8084
+ let sep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ', ';
8085
+ const filtered = parts.map(p => p === null || p === void 0 ? void 0 : p.trim()).filter(p => !!p);
8086
+ return filtered.length ? filtered.join(sep) : undefined;
8087
+ };
8088
+
8089
+ /**
8090
+ * Build a single info ChecklistItem when its value is present. Returns null so
8091
+ * callers can filter absent fields out and only render populated rows.
8092
+ */
8093
+ const infoRow = (t, key, params, testId, value) => {
8094
+ if (!value) return null;
8095
+ // 'no-icon' renders the label/value with no leading icon — these dense
8096
+ // metadata rows read as a plain key/value list, so an info dot per row is
8097
+ // just noise.
8098
+ return {
8099
+ type: 'no-icon',
8100
+ text: t(key, params),
8101
+ 'data-testid': testId
8102
+ };
8103
+ };
8104
+
8105
+ /** External-link anchor rendered inline inside a Checklist item. */
8106
+ const ExternalLink = _ref => {
8107
+ let {
8108
+ href,
8109
+ children,
8110
+ 'data-testid': testId
8111
+ } = _ref;
8112
+ return /*#__PURE__*/React__default.createElement("a", {
8113
+ href: href,
8114
+ target: "_blank",
8115
+ rel: "noopener noreferrer",
8116
+ "data-testid": testId
8117
+ }, children);
8118
+ };
8119
+
8120
+ /**
8121
+ * Build the five published-certificate sections (Validity, Certificate, Subject
8122
+ * identity, Mark evidence, Verification issues) from IPForensics
8123
+ * VmcPublishedCertificate + VmcPemEvidence data.
8124
+ *
8125
+ * All labels come from @redsift/signal-logic BIMI_KEYS via `t` so they remain
8126
+ * translatable. `now` is injected for deterministic humanized durations in
8127
+ * tests and stories.
8128
+ */
8129
+ const buildPublishedCertificateSections = (cert, pem, t, now) => {
8130
+ var _cert$certifiedDomain, _cert$certifiedDomain2, _pem$errors;
8131
+ const sections = [];
8132
+
8133
+ // --- Validity ---
8134
+ const validFromText = humanizeValidFrom(cert.validFrom, now);
8135
+ const expiryText = humanizeExpiry(cert.expiry, now);
8136
+ const validityItems = [infoRow(t, 'card.bimi.vmc.cert-valid-from_md', {
8137
+ date: validFromText
8138
+ }, 'bimi-cert-valid-from', validFromText), infoRow(t, 'card.bimi.vmc.cert-expiry_md', {
8139
+ date: expiryText
8140
+ }, 'bimi-cert-expiry', expiryText)].filter(i => i !== null);
8141
+ if (validityItems.length) {
8142
+ sections.push({
8143
+ id: 'bimi-cert-validity',
8144
+ title: t('card.bimi.vmc.cert-section-validity'),
8145
+ items: validityItems,
8146
+ testId: 'bimi-cert-validity-section'
8147
+ });
8148
+ }
8149
+
8150
+ // --- Certificate ---
8151
+ const certItems = [];
8152
+ const issuerCommon = infoRow(t, 'card.bimi.vmc.cert-issuer-common-name_md', {
8153
+ issuerCommonName: cert.issuerCommonName
8154
+ }, 'bimi-cert-issuer-common-name', cert.issuerCommonName);
8155
+ if (issuerCommon) certItems.push(issuerCommon);
8156
+ const issuerOrg = infoRow(t, 'card.bimi.vmc.cert-issuer-organization_md', {
8157
+ issuerOrganization: cert.issuerOrganization
8158
+ }, 'bimi-cert-issuer-organization', cert.issuerOrganization);
8159
+ if (issuerOrg) certItems.push(issuerOrg);
8160
+ const issuerCountry = infoRow(t, 'card.bimi.vmc.cert-issuer-country_md', {
8161
+ issuerCountry: cert.issuerCountry
8162
+ }, 'bimi-cert-issuer-country', cert.issuerCountry);
8163
+ if (issuerCountry) certItems.push(issuerCountry);
8164
+
8165
+ // Certificate type row: a bold "Certificate type:" label with the VMC/CMC
8166
+ // value as an external-link badge. We interpolate a placeholder for the value
8167
+ // so the label markdown (**…**) parses correctly, then splice the linked
8168
+ // badge in where the value goes — only the value links, not the label.
8169
+ if (cert.markType) {
8170
+ const VALUE_TOKEN = '';
8171
+ const template = t('card.bimi.vmc.cert-type_md', {
8172
+ assertionMarkType: VALUE_TOKEN
8173
+ });
8174
+ const [before, after = ''] = template.split(VALUE_TOKEN);
8175
+ certItems.push({
8176
+ type: 'no-icon',
8177
+ 'data-testid': 'bimi-cert-type',
8178
+ text: /*#__PURE__*/React__default.createElement("span", null, parseGlossaryMarkdown(before), /*#__PURE__*/React__default.createElement(ExternalLink, {
8179
+ href: CERT_TYPE_REFERENCE_URL,
8180
+ "data-testid": "bimi-cert-type-link"
8181
+ }, cert.markType), after && parseGlossaryMarkdown(after))
8182
+ });
8183
+ }
8184
+
8185
+ // Certified domains as chips with external links, comma-separated.
8186
+ const certifiedDomains = (_cert$certifiedDomain = (_cert$certifiedDomain2 = cert.certifiedDomains) === null || _cert$certifiedDomain2 === void 0 ? void 0 : _cert$certifiedDomain2.filter(d => !!d)) !== null && _cert$certifiedDomain !== void 0 ? _cert$certifiedDomain : [];
8187
+ if (certifiedDomains.length) {
8188
+ certItems.push({
8189
+ type: 'no-icon',
8190
+ 'data-testid': 'bimi-cert-certified-domains',
8191
+ text: /*#__PURE__*/React__default.createElement("span", {
8192
+ "data-testid": "bimi-cert-certified-domains-chips"
8193
+ }, certifiedDomains.map((domain, idx) => /*#__PURE__*/React__default.createElement(React__default.Fragment, {
8194
+ key: domain
8195
+ }, idx > 0 && ', ', /*#__PURE__*/React__default.createElement(ExternalLink, {
8196
+ href: `https://${domain}`
8197
+ }, domain))))
8198
+ });
8199
+ }
8200
+ if (certItems.length) {
8201
+ sections.push({
8202
+ id: 'bimi-cert-certificate',
8203
+ title: t('card.bimi.vmc.cert-section-certificate'),
8204
+ items: certItems,
8205
+ testId: 'bimi-cert-certificate-section'
8206
+ });
8207
+ }
8208
+
8209
+ // --- Subject identity ---
8210
+ const jurisdiction = joinParts([cert.jurisdictionLocality, cert.jurisdictionStateOrProvince, cert.jurisdictionCountry]);
8211
+ const address = joinParts([cert.streetAddress, cert.locality, cert.stateOrProvince, cert.country]);
8212
+ const organizationIdentifier = cert.organizationIdentifier ? cert.organizationIdentifierScheme ? `${cert.organizationIdentifier} (${cert.organizationIdentifierScheme})` : cert.organizationIdentifier : undefined;
8213
+ const subjectItems = [infoRow(t, 'card.bimi.vmc.cert-serial-number_md', {
8214
+ serialNumber: cert.serialNumber
8215
+ }, 'bimi-cert-serial-number', cert.serialNumber), infoRow(t, 'card.bimi.vmc.cert-organization_md', {
8216
+ organization: cert.organization
8217
+ }, 'bimi-cert-organization', cert.organization), infoRow(t, 'card.bimi.vmc.cert-common-name_md', {
8218
+ commonName: cert.commonName
8219
+ }, 'bimi-cert-common-name', cert.commonName), infoRow(t, 'card.bimi.vmc.cert-business-category_md', {
8220
+ businessCategory: cert.businessCategory
8221
+ }, 'bimi-cert-business-category', cert.businessCategory), infoRow(t, 'card.bimi.vmc.cert-organization-identifier_md', {
8222
+ organizationIdentifier
8223
+ }, 'bimi-cert-organization-identifier', organizationIdentifier), infoRow(t, 'card.bimi.vmc.cert-legal-entity-identifier_md', {
8224
+ legalEntityIdentifier: cert.legalEntityIdentifier
8225
+ }, 'bimi-cert-legal-entity-identifier', cert.legalEntityIdentifier), infoRow(t, 'card.bimi.vmc.cert-jurisdiction_md', {
8226
+ jurisdiction
8227
+ }, 'bimi-cert-jurisdiction', jurisdiction), infoRow(t, 'card.bimi.vmc.cert-address_md', {
8228
+ address
8229
+ }, 'bimi-cert-address', address)].filter(i => i !== null);
8230
+ if (subjectItems.length) {
8231
+ sections.push({
8232
+ id: 'bimi-cert-subject-identity',
8233
+ title: t('card.bimi.vmc.cert-section-subject-identity'),
8234
+ items: subjectItems,
8235
+ testId: 'bimi-cert-subject-identity-section'
8236
+ });
8237
+ }
8238
+
8239
+ // --- Mark evidence ---
8240
+ const markItems = [infoRow(t, 'card.bimi.vmc.cert-trademark-registration_md', {
8241
+ trademarkRegistration: cert.trademarkRegistration
8242
+ }, 'bimi-cert-trademark-registration', cert.trademarkRegistration), infoRow(t, 'card.bimi.vmc.cert-trademark-office_md', {
8243
+ trademarkOfficeName: cert.trademarkOfficeName
8244
+ }, 'bimi-cert-trademark-office', cert.trademarkOfficeName), infoRow(t, 'card.bimi.vmc.cert-mark-type_md', {
8245
+ markType: cert.markType
8246
+ }, 'bimi-cert-mark-type', cert.markType), infoRow(t, 'card.bimi.vmc.cert-trademark-country_md', {
8247
+ trademarkCountryOrRegion: cert.trademarkCountryOrRegion
8248
+ }, 'bimi-cert-trademark-country', cert.trademarkCountryOrRegion)].filter(i => i !== null);
8249
+ if (markItems.length) {
8250
+ sections.push({
8251
+ id: 'bimi-cert-mark-evidence',
8252
+ title: t('card.bimi.vmc.cert-section-mark-evidence'),
8253
+ items: markItems,
8254
+ testId: 'bimi-cert-mark-evidence-section'
8255
+ });
8256
+ }
8257
+
8258
+ // --- Verification issues ---
8259
+ // Sourced from PEM evidence errors plus an ambiguous leaf-selection signal.
8260
+ const errorMessages = ((_pem$errors = pem === null || pem === void 0 ? void 0 : pem.errors) !== null && _pem$errors !== void 0 ? _pem$errors : []).map(e => typeof e === 'string' ? e : e === null || e === void 0 ? void 0 : e.message).filter(m => !!m);
8261
+ const isAmbiguous = (pem === null || pem === void 0 ? void 0 : pem.leafSelectionMethod) === 'AMBIGUOUS';
8262
+ const issueItems = [];
8263
+ if (isAmbiguous) {
8264
+ issueItems.push({
8265
+ type: 'warning',
8266
+ text: 'Ambiguous leaf certificate selection',
8267
+ 'data-testid': 'bimi-cert-issue-ambiguous'
8268
+ });
8269
+ }
8270
+ errorMessages.forEach((message, idx) => {
8271
+ issueItems.push({
8272
+ type: 'warning',
8273
+ text: message,
8274
+ 'data-testid': `bimi-cert-issue-${idx}`
8275
+ });
8276
+ });
8277
+ if (!issueItems.length) {
8278
+ issueItems.push({
8279
+ type: 'good',
8280
+ text: t('card.bimi.vmc.cert-no-issues-reported_md'),
8281
+ 'data-testid': 'bimi-cert-no-issues'
8282
+ });
8283
+ }
8284
+ sections.push({
8285
+ id: 'bimi-cert-verification-issues',
8286
+ title: t('card.bimi.vmc.cert-section-verification-issues'),
8287
+ items: issueItems,
8288
+ testId: 'bimi-cert-verification-issues-section'
8289
+ });
8290
+ return sections;
8291
+ };
8292
+
7960
8293
  const _excluded$2 = ["jmap", "onHeightChange", "useInvestigateColors", "isCollapsible", "areAllCollapsed", "onCollapseAll", "className"];
7961
8294
  const COMPONENT_NAME$2 = 'SignalCardBimi';
7962
8295
  const CLASSNAME$2 = 'redsift-signal-card-bimi';
@@ -7966,6 +8299,7 @@ const CLASSNAME$2 = 'redsift-signal-card-bimi';
7966
8299
  * BIMI record validation, VMC certificate details, and SVG logo validation.
7967
8300
  */
7968
8301
  const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
8302
+ var _bimi$vmc;
7969
8303
  const {
7970
8304
  t
7971
8305
  } = useSignalCardTranslation('investigate');
@@ -8024,31 +8358,77 @@ const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
8024
8358
  items
8025
8359
  });
8026
8360
  }, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.svgSection, bimi, isDeclinationToPublish]);
8361
+ const hasPublishedCertificate = !!(bimi !== null && bimi !== void 0 && (_bimi$vmc = bimi.vmc) !== null && _bimi$vmc !== void 0 && _bimi$vmc.publishedCertificate);
8027
8362
 
8028
8363
  // Inject SVGLogo into VMC section (React-specific)
8029
8364
  const vmcSection = useMemo(() => {
8030
- var _bimi$vmc;
8365
+ var _bimi$vmc2;
8031
8366
  if (isDeclinationToPublish || !(adapterResult !== null && adapterResult !== void 0 && adapterResult.vmcSection)) return null;
8032
- const logoSrc = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc = bimi.vmc) === null || _bimi$vmc === void 0 ? void 0 : _bimi$vmc.logoSrc;
8033
- if (!logoSrc) return adapterResult.vmcSection;
8034
- const items = [...adapterResult.vmcSection.items];
8035
- // Insert logo before the first 'no-icon' item (matching original helpers behavior)
8036
- const noIconIdx = items.findIndex(item => item.type === 'no-icon');
8037
- const svgItem = {
8038
- text: /*#__PURE__*/React__default.createElement(SVGLogo$1, {
8039
- svgUrl: logoSrc
8040
- }),
8041
- type: 'image'
8042
- };
8043
- if (noIconIdx >= 0) {
8044
- items.splice(noIconIdx, 0, svgItem);
8045
- } else {
8046
- items.push(svgItem);
8367
+ let items = [...adapterResult.vmcSection.items];
8368
+
8369
+ // When the full published certificate is present, the new metadata sections
8370
+ // (below) supersede several legacy VMC rows with richer equivalents, so drop
8371
+ // the duplicated legacy rows to avoid showing each field twice (DS-93):
8372
+ // issuer → Certificate Issuer
8373
+ // expiry → Validity › Expiry (matched by testid)
8374
+ // valid-for-domains → Certificate › Certified domains
8375
+ // trademark authority → Mark evidence › Trademark office
8376
+ // The legacy assertion-mark and VMC validity-status rows have no equivalent
8377
+ // in the new sections and are kept.
8378
+ if (hasPublishedCertificate) {
8379
+ const stripMd = s => s.replace(/[*`]/g, '').trim();
8380
+ // Label prefixes (value interpolated empty) of the legacy rows to suppress.
8381
+ const suppressedPrefixes = [t('card.bimi.vmc.issuer_md', {
8382
+ issuer: ''
8383
+ }), t('card.bimi.vmc.valid-for-domain_md', {
8384
+ domains: ''
8385
+ }), t('card.bimi.vmc.trademarkAuthority_md', {
8386
+ trademarkAuthority: ''
8387
+ })].map(stripMd).filter(Boolean);
8388
+ const suppressedTestIds = new Set(['vmc-expiration-valid', 'vmc-expiration-expired']);
8389
+ items = items.filter(item => {
8390
+ const testId = item['data-testid'];
8391
+ if (testId && suppressedTestIds.has(testId)) return false;
8392
+ if (typeof item.text === 'string') {
8393
+ const text = stripMd(item.text);
8394
+ if (suppressedPrefixes.some(prefix => text.startsWith(prefix))) return false;
8395
+ }
8396
+ return true;
8397
+ });
8398
+ }
8399
+ const logoSrc = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc2 = bimi.vmc) === null || _bimi$vmc2 === void 0 ? void 0 : _bimi$vmc2.logoSrc;
8400
+ if (logoSrc) {
8401
+ // Insert logo before the first 'no-icon' item (matching original helpers behavior)
8402
+ const noIconIdx = items.findIndex(item => item.type === 'no-icon');
8403
+ const svgItem = {
8404
+ text: /*#__PURE__*/React__default.createElement(SVGLogo$1, {
8405
+ svgUrl: logoSrc
8406
+ }),
8407
+ type: 'image'
8408
+ };
8409
+ if (noIconIdx >= 0) {
8410
+ items.splice(noIconIdx, 0, svgItem);
8411
+ } else {
8412
+ items.push(svgItem);
8413
+ }
8047
8414
  }
8048
8415
  return _objectSpread2(_objectSpread2({}, adapterResult.vmcSection), {}, {
8049
8416
  items
8050
8417
  });
8051
- }, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.vmcSection, bimi, isDeclinationToPublish]);
8418
+ }, [adapterResult === null || adapterResult === void 0 ? void 0 : adapterResult.vmcSection, bimi, isDeclinationToPublish, hasPublishedCertificate, t]);
8419
+
8420
+ // Build the published-certificate metadata sections (VMC/CMC leaf identity,
8421
+ // mark evidence, verification issues). Only present when IPForensics resolved
8422
+ // a unique leaf; otherwise this is empty and the card degrades to the legacy
8423
+ // VMC section above (DS-93). `now` drives the humanized validity durations.
8424
+ const publishedCertSections = useMemo(() => {
8425
+ var _bimi$vmc3, _bimi$vmc4;
8426
+ if (isDeclinationToPublish) return [];
8427
+ const cert = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc3 = bimi.vmc) === null || _bimi$vmc3 === void 0 ? void 0 : _bimi$vmc3.publishedCertificate;
8428
+ if (!cert) return [];
8429
+ const pem = bimi === null || bimi === void 0 ? void 0 : (_bimi$vmc4 = bimi.vmc) === null || _bimi$vmc4 === void 0 ? void 0 : _bimi$vmc4.pem;
8430
+ return buildPublishedCertificateSections(cert, pem, t, new Date());
8431
+ }, [bimi, t, isDeclinationToPublish]);
8052
8432
  const getTranslatedCaption = useCallback(caption => {
8053
8433
  if (!caption) return undefined;
8054
8434
  return t(EXTRACTION_CAPTION_KEYS[caption]);
@@ -8106,6 +8486,20 @@ const SignalCardBimi = /*#__PURE__*/forwardRef((props, ref) => {
8106
8486
  testId: 'bimi-vmc-section'
8107
8487
  });
8108
8488
  }
8489
+
8490
+ // Full published-certificate metadata sections (DS-93). Rendered only when
8491
+ // vmc.publishedCertificate is present; otherwise the card keeps its legacy
8492
+ // VMC rendering above.
8493
+ publishedCertSections.forEach(section => {
8494
+ sections.push({
8495
+ id: section.id,
8496
+ title: section.title,
8497
+ content: /*#__PURE__*/React__default.createElement(Checklist$1, {
8498
+ items: section.items
8499
+ }),
8500
+ testId: section.testId
8501
+ });
8502
+ });
8109
8503
  if (svgSection) {
8110
8504
  sections.push({
8111
8505
  id: 'safeSVG',