kyd-shared-badge 0.2.23 → 0.2.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kyd-shared-badge",
3
- "version": "0.2.23",
3
+ "version": "0.2.25",
4
4
  "private": false,
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -57,315 +57,227 @@ const getAiIconSrc = (descriptor?: string): string => {
57
57
  return '/badge/aired.png';
58
58
  };
59
59
 
60
- interface ScoreCardProps {
61
- title: React.ReactNode;
62
- score: number;
63
- description: string;
64
- descriptor?: string;
65
- scoreType: 'number' | 'risk' | 'descriptor';
66
- iconImageSrc: string;
67
- }
68
-
69
- const ScoreCard = ({ title, score, description, descriptor, scoreType, iconImageSrc }: ScoreCardProps) => {
70
- const isDescriptor = scoreType === 'descriptor';
71
- const scoreHex = getScoreColor(score);
72
- const overlay = scoreHex ? hexToRgba(scoreHex, 0.08) : 'transparent';
73
- let displayScore;
74
-
75
- if (scoreType === 'risk') {
76
- displayScore = getRiskText(score);
77
- } else if (scoreType === 'descriptor') {
78
- displayScore = descriptor;
79
- } else {
80
- displayScore = `${score}/100`;
81
- }
82
-
83
- return (
84
- <div
85
- className={
86
- 'p-6 rounded-xl flex flex-col items-center justify-start text-center shadow h-full border'
87
- }
88
- style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)', backgroundImage: `linear-gradient(${overlay}, ${overlay})` }}
89
- >
90
- <div className={`text-3xl mb-4`} style={scoreHex ? { color: scoreHex } : undefined}>
91
- <Image src={iconImageSrc} alt="icon" width={32} height={32} className="h-8 w-8 object-contain" />
92
- </div>
93
- <h3 className={`font-semibold text-xl ${isDescriptor ? 'text-neutral-400' : ''}`} style={{ color: 'var(--text-main)' }}>{title}</h3>
94
- <p className={`text-4xl font-bold`} style={scoreHex ? { color: scoreHex } : undefined}>{displayScore}</p>
95
- <p className={'text-sm text-neutral-600 dark:text-neutral-400 mt-4'} style={{ color: 'var(--text-secondary)' }}>{description}</p>
96
- </div>
97
- );
98
- };
99
-
100
60
  const SharedBadgeDisplay = ({ badgeData }: { badgeData: PublicBadgeData }) => {
101
61
  const { badgeId, developerName, assessmentResult, updatedAt, connectedAccounts } = badgeData;
102
- const { summary_scores, report_summary, developer_trust_explanation, key_skills, screening_sources, industry_considerations, top_contributing_rules } = assessmentResult;
62
+ const { summary_scores, report_summary, developer_trust_explanation, key_skills, screening_sources, industry_considerations } = assessmentResult;
103
63
 
104
- const devTrustScore = summary_scores?.developer_trust;
105
- const riskScore = summary_scores?.risk_score;
106
- const aiUsageScore = summary_scores?.ai_usage;
64
+ // const devTrustScore = summary_scores.developer_trust;
65
+ // const riskScore = summary_scores.risk_score;
66
+ // const aiUsageScore = summary_scores.ai_usage;
107
67
 
108
68
  const wrapperMaxWidth = 'max-w-5xl';
109
69
 
110
70
  return (
111
71
  <div className={`${wrapperMaxWidth} mx-auto`}>
112
- {/* Share controls removed; app-level pages render their own actions */}
113
- <ReportHeader
114
- badgeId={badgeId}
115
- developerName={badgeData.developerName}
116
- updatedAt={updatedAt}
117
- score={summary_scores?.kyd_self_check?.score}
118
- isPublic={true}
119
- badgeImageUrl={badgeData.badgeImageUrl || ''}
120
- />
121
- <div
122
- className={'rounded-xl shadow-xl p-6 sm:p-8 mt-8 border'}
123
- style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}
124
- >
125
- {summary_scores && (
126
- <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
127
- <ScoreCard
128
- title="KYD Technical™"
129
- score={devTrustScore?.score || 0}
130
- description={devTrustScore?.description || ''}
131
- scoreType='number'
132
- iconImageSrc={getTechnicalIconSrc(devTrustScore?.score || 0)}
133
- />
134
- <ScoreCard
135
- title="KYD Risk™"
136
- score={riskScore?.score || 0}
137
- description={riskScore?.description || ''}
138
- scoreType='risk'
139
- iconImageSrc={getRiskIconSrc(riskScore?.score || 0)}
140
- />
141
- <ScoreCard
142
- title={<span>KYD AI™ <span className="text-xs font-semibold bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-2 py-1 rounded-full align-middle">Beta</span></span>}
143
- score={aiUsageScore?.score || 0}
144
- description={aiUsageScore?.description || ''}
145
- descriptor={aiUsageScore?.descriptor}
146
- scoreType='descriptor'
147
- iconImageSrc={getAiIconSrc(aiUsageScore?.descriptor)}
148
- />
149
- </div>
150
- )}
72
+ {/* Share controls removed; app-level pages render their own actions */}
73
+ <ReportHeader
74
+ badgeId={badgeId}
75
+ developerName={badgeData.developerName}
76
+ updatedAt={updatedAt}
77
+ score={summary_scores.kyd_self_check.score}
78
+ isPublic={true}
79
+ badgeImageUrl={badgeData.badgeImageUrl || ''}
80
+ />
81
+ <div
82
+ className={'rounded-xl shadow-xl p-6 sm:p-8 mt-8 border'}
83
+ style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}
84
+ >
151
85
 
152
- <div className={'space-y-12 divide-y'} style={{ borderColor: 'var(--icon-button-secondary)' }}>
153
- <div className="pt-8 first:pt-0">
154
- <h3 className={'text-2xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>1. Summary Findings</h3>
155
- <div className={'prose prose-sm max-w-none'} style={{ color: 'var(--text-secondary)' }}>
156
- <p>{report_summary}</p>
157
- </div>
158
- {top_contributing_rules && top_contributing_rules.length > 0 && (
86
+ <div className={'space-y-12 divide-y'} style={{ borderColor: 'var(--icon-button-secondary)' }}>
87
+ <div className="pt-8 first:pt-0">
88
+ <h3 className={'text-2xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>1. Summary Findings</h3>
89
+ <div className={'prose prose-sm max-w-none'} style={{ color: 'var(--text-secondary)' }}>
90
+ <p>{report_summary}</p>
91
+ </div>
92
+ {/* {key_skills && key_skills.length > 0 && (
159
93
  <div className="mt-6">
160
- <h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Top Contributing Rules</h4>
161
- <ul className="list-disc list-inside" style={{ color: 'var(--text-secondary)' }}>
162
- {top_contributing_rules.map((r, i) => (
163
- <li key={i}><strong style={{ color: 'var(--text-main)' }}>{r.provider}:</strong> {r.rule_label} — {r.why}</li>
164
- ))}
165
- </ul>
94
+ <h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Key Skills Observed</h4>
95
+ <div className="flex flex-wrap gap-2">
96
+ {key_skills.map((skill: string, index: number) => (
97
+ <span key={index} className={'text-xs font-medium px-2.5 py-1 rounded-full'} style={{ backgroundColor: 'var(--icon-button-secondary)', color: 'var(--text-main)' }}>
98
+ {skill}
99
+ </span>
100
+ ))}
101
+ </div>
166
102
  </div>
167
- )}
168
- {key_skills && key_skills.length > 0 && (
169
- <div className="mt-6">
170
- <h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Key Skills Observed</h4>
171
- <div className="flex flex-wrap gap-2">
172
- {key_skills.map((skill: string, index: number) => (
173
- <span key={index} className={'text-xs font-medium px-2.5 py-1 rounded-full'} style={{ backgroundColor: 'var(--icon-button-secondary)', color: 'var(--text-main)' }}>
174
- {skill}
175
- </span>
176
- ))}
103
+ )} */}
104
+ </div>
105
+
106
+ <div className="pt-8">
107
+ <h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>2. KYD Technical™ Signals</h3>
108
+ <div className={'prose prose-sm max-w-none mb-6'} style={{ color: 'var(--text-secondary)' }}>
109
+ <p>{developer_trust_explanation}</p>
110
+ </div>
111
+ <ProviderInsights
112
+ platforms={connectedAccounts || []}
113
+ insights={assessmentResult.provider_insights}
114
+ />
115
+ </div>
116
+
117
+ <div className="pt-8">
118
+ <h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>3. KYD Risk™ Signals</h3>
119
+ {badgeData.optOutScreening ? (
120
+ <div className={'mb-4 p-4 rounded-lg border'} style={{ backgroundColor: 'var(--icon-button-secondary)', borderColor: 'var(--icon-button-secondary)' }}>
121
+ <div className="flex items-start">
122
+ <span className="h-5 w-5 mr-3 mt-0.5 flex-shrink-0" style={{ color: yellow }}>
123
+ <FiAlertTriangle size={20} />
124
+ </span>
125
+ <div>
126
+ <h4 className={'font-bold'} style={{ color: 'var(--text-main)' }}>User Opted Out of Screening</h4>
127
+ <p className={'text-sm mt-1'} style={{ color: 'var(--text-secondary)' }}>
128
+ The user chose not to participate in the automated sanctions and risk screening process. The risk score reflects this decision and is for informational purposes only.
129
+ </p>
130
+ </div>
177
131
  </div>
178
132
  </div>
179
- )}
180
- </div>
181
-
182
- <div className="pt-8">
183
- <h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>2. KYD Technical™ Signals</h3>
184
- <div className={'prose prose-sm max-w-none mb-6'} style={{ color: 'var(--text-secondary)' }}>
185
- <p>{developer_trust_explanation}</p>
186
- </div>
187
- <ProviderInsights
188
- platforms={connectedAccounts || []}
189
- insights={assessmentResult.provider_insights}
190
- />
191
- </div>
192
-
193
- <div className="pt-8">
194
- <h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>3. KYD Risk™ Signals</h3>
195
- {badgeData.optOutScreening ? (
196
- <div className={'mb-4 p-4 rounded-lg border'} style={{ backgroundColor: 'var(--icon-button-secondary)', borderColor: 'var(--icon-button-secondary)' }}>
197
- <div className="flex items-start">
198
- <span className="h-5 w-5 mr-3 mt-0.5 flex-shrink-0" style={{ color: yellow }}>
199
- <FiAlertTriangle size={20} />
200
- </span>
133
+ ) : (
134
+ <>
135
+ {(() => {
136
+ const ss = assessmentResult?.screening_sources;
137
+ const ofacMatches = ss?.ofac_screen?.matches && (ss.ofac_screen.matches.length > 0);
138
+ const cslDetails = ss?.csl_details && (Array.isArray(ss.csl_details) ? ss.csl_details.length > 0 : Object.keys(ss.csl_details).length > 0);
139
+ const fbiMatches = ss?.fbi_matches && (ss.fbi_matches.length > 0);
140
+ if (!(ofacMatches || cslDetails || fbiMatches)) return null;
141
+ return (
142
+ <div className={'mb-8 rounded-lg border p-4'} style={{ borderColor: 'var(--icon-button-secondary)', backgroundColor: 'var(--content-card-background)' }}>
143
+ <h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>3A. Sanctions Matches</h4>
144
+ {/* OFAC matches */}
145
+ {ofacMatches && (
146
+ <div className={'mb-4'}>
147
+ <h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>OFAC API Matches</h5>
201
148
  <div>
202
- <h4 className={'font-bold'} style={{ color: 'var(--text-main)' }}>User Opted Out of Screening</h4>
203
- <p className={'text-sm mt-1'} style={{ color: 'var(--text-secondary)' }}>
204
- The user chose not to participate in the automated sanctions and risk screening process. The risk score reflects this decision and is for informational purposes only.
205
- </p>
206
- </div>
207
- </div>
208
- </div>
209
- ) : (
210
- <>
211
- {riskScore?.description && (
212
- <div className={'prose prose-sm max-w-none space-y-4 mb-6'} style={{ color: 'var(--text-secondary)' }}>
213
- <p>{riskScore.description}</p>
214
- </div>
215
- )}
216
- {(() => {
217
- const ss = assessmentResult?.screening_sources;
218
- const ofacMatches = ss?.ofac_screen?.matches && (ss.ofac_screen.matches.length > 0);
219
- const cslDetails = ss?.csl_details && (Array.isArray(ss.csl_details) ? ss.csl_details.length > 0 : Object.keys(ss.csl_details).length > 0);
220
- const fbiMatches = ss?.fbi_matches && (ss.fbi_matches.length > 0);
221
- if (!(ofacMatches || cslDetails || fbiMatches)) return null;
222
- return (
223
- <div className={'mb-8 rounded-lg border p-4'} style={{ borderColor: 'var(--icon-button-secondary)', backgroundColor: 'var(--content-card-background)' }}>
224
- <h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>3A. Sanctions Matches</h4>
225
- {/* OFAC matches */}
226
- {ofacMatches && (
227
- <div className={'mb-4'}>
228
- <h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>OFAC API Matches</h5>
229
- <div>
230
- {ss!.ofac_screen!.matches!.map((m: any, i: number) => {
231
- const s = m?.sanction || {};
232
- const title = s.name || 'Unknown';
233
- const programs = (s.programs && s.programs.length) ? ` — Programs: ${s.programs.join(', ')}` : '';
234
- return (
235
- <div key={i} style={{ display: 'grid', gridTemplateColumns: '12px 1fr', columnGap: 8, alignItems: 'start', marginBottom: 6 }}>
236
- <div aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', marginTop: 6, backgroundColor: 'var(--text-secondary)' }} />
237
- <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>
238
- <span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{title}</span>
239
- <span>{programs}</span>
240
- {s.entityLink ? (
241
- <>
242
- {' '}— <a href={s.entityLink} target='_blank' rel='noopener noreferrer' className={'underline'} style={{ color: 'var(--icon-accent)' }}>Details</a>
243
- </>
244
- ) : null}
245
- </div>
246
- </div>
247
- );
248
- })}
249
- </div>
250
- <details className={'mt-2'}>
251
- <summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View OFAC Raw JSON</summary>
252
- <pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.ofac_screen!.raw, null, 2)}</pre>
253
- </details>
254
- </div>
255
- )}
256
- {/* CSL details */}
257
- {cslDetails && (
258
- <div className={'mb-4'}>
259
- <h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>U.S. CSL Details</h5>
260
- <details>
261
- <summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View CSL Raw JSON</summary>
262
- <pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.csl_details, null, 2)}</pre>
263
- </details>
264
- </div>
265
- )}
266
- {/* FBI matches */}
267
- {fbiMatches && (
268
- <div className={'mb-2'}>
269
- <h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>FBI Wanted List Matches</h5>
270
- <div>
271
- {ss!.fbi_matches!.map((f: any, i: number) => (
149
+ {ss!.ofac_screen!.matches!.map((m: any, i: number) => {
150
+ const s = m?.sanction || {};
151
+ const title = s.name || 'Unknown';
152
+ const programs = (s.programs && s.programs.length) ? ` — Programs: ${s.programs.join(', ')}` : '';
153
+ return (
272
154
  <div key={i} style={{ display: 'grid', gridTemplateColumns: '12px 1fr', columnGap: 8, alignItems: 'start', marginBottom: 6 }}>
273
155
  <div aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', marginTop: 6, backgroundColor: 'var(--text-secondary)' }} />
274
156
  <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>
275
- <span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{f.title || 'Match'}</span>
276
- {f.url ? <> — <a href={f.url} target='_blank' rel='noopener noreferrer' className={'underline'} style={{ color: 'var(--icon-accent)' }}>Details</a></> : null}
157
+ <span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{title}</span>
158
+ <span>{programs}</span>
159
+ {s.entityLink ? (
160
+ <>
161
+ {' '}— <a href={s.entityLink} target='_blank' rel='noopener noreferrer' className={'underline'} style={{ color: 'var(--icon-accent)' }}>Details</a>
162
+ </>
163
+ ) : null}
277
164
  </div>
278
165
  </div>
279
- ))}
280
- </div>
166
+ );
167
+ })}
168
+ </div>
169
+ <details className={'mt-2'}>
170
+ <summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View OFAC Raw JSON</summary>
171
+ <pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.ofac_screen!.raw, null, 2)}</pre>
172
+ </details>
173
+ </div>
174
+ )}
175
+ {/* CSL details */}
176
+ {cslDetails && (
177
+ <div className={'mb-4'}>
178
+ <h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>U.S. CSL Details</h5>
179
+ <details>
180
+ <summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View CSL Raw JSON</summary>
181
+ <pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.csl_details, null, 2)}</pre>
182
+ </details>
183
+ </div>
184
+ )}
185
+ {/* FBI matches */}
186
+ {fbiMatches && (
187
+ <div className={'mb-2'}>
188
+ <h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>FBI Wanted List Matches</h5>
189
+ <div>
190
+ {ss!.fbi_matches!.map((f: any, i: number) => (
191
+ <div key={i} style={{ display: 'grid', gridTemplateColumns: '12px 1fr', columnGap: 8, alignItems: 'start', marginBottom: 6 }}>
192
+ <div aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', marginTop: 6, backgroundColor: 'var(--text-secondary)' }} />
193
+ <div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>
194
+ <span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{f.title || 'Match'}</span>
195
+ {f.url ? <> — <a href={f.url} target='_blank' rel='noopener noreferrer' className={'underline'} style={{ color: 'var(--icon-accent)' }}>Details</a></> : null}
196
+ </div>
197
+ </div>
198
+ ))}
281
199
  </div>
282
- )}
283
- </div>
284
- );
285
- })()}
286
- <IpRiskAnalysisDisplay ipRiskAnalysis={screening_sources?.ip_risk_analysis} />
287
- </>
200
+ </div>
201
+ )}
202
+ </div>
203
+ );
204
+ })()}
205
+ <IpRiskAnalysisDisplay ipRiskAnalysis={screening_sources?.ip_risk_analysis} />
206
+ </>
207
+ )}
208
+ </div>
209
+
210
+ <div className="pt-8">
211
+ <h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>4. KYD AI™ Signals <span className="text-sm font-semibold bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-2 py-1 rounded-full align-middle">Beta</span></h3>
212
+ <div className={'prose prose-sm max-w-none mb-6 space-y-4'} style={{ color: 'var(--text-secondary)' }}>
213
+ <p>{assessmentResult.ai_usage_summary?.explanation}</p>
214
+ {assessmentResult.ai_usage_summary?.key_findings && (
215
+ <ul className="list-disc list-inside">
216
+ {assessmentResult.ai_usage_summary.key_findings.map((finding, index) => (
217
+ <li key={index}>{finding}</li>
218
+ ))}
219
+ </ul>
288
220
  )}
289
221
  </div>
222
+ </div>
290
223
 
291
- <div className="pt-8">
292
- <h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>4. KYD AI™ Signals <span className="text-sm font-semibold bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-2 py-1 rounded-full align-middle">Beta</span></h3>
293
- <div className={'prose prose-sm max-w-none mb-6 space-y-4'} style={{ color: 'var(--text-secondary)' }}>
294
- <p>{assessmentResult.ai_usage_summary?.explanation}</p>
295
- {assessmentResult.ai_usage_summary?.key_findings && (
296
- <ul className="list-disc list-inside">
297
- {assessmentResult.ai_usage_summary.key_findings.map((finding, index) => (
298
- <li key={index}>{finding}</li>
299
- ))}
300
- </ul>
301
- )}
224
+ {!badgeData.optOutScreening && screening_sources && (
225
+ <div className="pt-8">
226
+ <h3 className={'text-2xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>6. Appendix: Data Sources</h3>
227
+ <div className="space-y-8">
228
+ <div>
229
+ <h4 className={'text-xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>Sanctions & Watchlists</h4>
230
+ {(() => {
231
+ const ofacProvided = screening_sources.ofac_screen?.sources || [];
232
+ const lists = [...(screening_sources.ofac_lists || []), ...ofacProvided];
233
+ const seen: { [k: string]: boolean } = {};
234
+ const dedup: string[] = [];
235
+ for (let i = 0; i < lists.length; i++) {
236
+ const val = lists[i];
237
+ if (!seen[val]) { seen[val] = true; dedup.push(val); }
238
+ }
239
+ const detailed = screening_sources.sanctions_sources_detailed || [];
240
+ const useDetailed = detailed && detailed.length > 0;
241
+ return (
242
+ <AppendixTables
243
+ type="sanctions"
244
+ sources={useDetailed ? detailed : dedup}
245
+ searchedAt={updatedAt}
246
+ developerName={developerName || 'this developer'}
247
+ />
248
+ );
249
+ })()}
250
+ </div>
251
+ <div>
252
+ <h4 className={'text-xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>Country-specific Entity Affiliations</h4>
253
+ <AppendixTables
254
+ type="domains"
255
+ sources={screening_sources.risk_profile_domains || []}
256
+ searchedAt={updatedAt}
257
+ developerName={developerName || 'this developer'}
258
+ />
259
+ </div>
260
+ </div>
302
261
  </div>
303
- </div>
304
-
305
- <div className="pt-8">
306
- <h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>5. Industry Considerations</h3>
307
- <div className={'prose prose-sm max-w-none'} style={{ color: 'var(--text-secondary)' }}>
308
- <p>{industry_considerations}</p>
309
- </div>
310
- </div>
262
+ )}
311
263
 
312
- {!badgeData.optOutScreening && screening_sources && (
313
- <div className="pt-8">
314
- <h3 className={'text-2xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>6. Appendix: Data Sources</h3>
315
- <div className="space-y-8">
316
- <div>
317
- <h4 className={'text-xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>Sanctions & Watchlists</h4>
318
- {(() => {
319
- const ofacProvided = screening_sources.ofac_screen?.sources || [];
320
- const lists = [...(screening_sources.ofac_lists || []), ...ofacProvided];
321
- const seen: { [k: string]: boolean } = {};
322
- const dedup: string[] = [];
323
- for (let i = 0; i < lists.length; i++) {
324
- const val = lists[i];
325
- if (!seen[val]) { seen[val] = true; dedup.push(val); }
326
- }
327
- const detailed = screening_sources.sanctions_sources_detailed || [];
328
- const useDetailed = detailed && detailed.length > 0;
329
- return (
330
- <AppendixTables
331
- type="sanctions"
332
- sources={useDetailed ? detailed : dedup}
333
- searchedAt={updatedAt}
334
- developerName={developerName || 'this developer'}
335
- />
336
- );
337
- })()}
338
- </div>
339
- <div>
340
- <h4 className={'text-xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>Country-specific Entity Affiliations</h4>
341
- <AppendixTables
342
- type="domains"
343
- sources={screening_sources.risk_profile_domains || []}
344
- searchedAt={updatedAt}
345
- developerName={developerName || 'this developer'}
346
- />
347
- </div>
348
- </div>
349
- </div>
350
- )}
351
-
352
- <div className={'pt-8 text-sm text-center'} style={{ color: 'var(--text-secondary)' }}>
353
- Report Completed: {new Date(updatedAt).toLocaleString(undefined, {
354
- year: 'numeric',
355
- month: 'long',
356
- day: 'numeric',
357
- hour: 'numeric',
358
- minute: '2-digit',
359
- timeZoneName: 'short',
360
- })}
361
- </div>
362
- </div>
363
- </div>
364
- <footer className={'mt-12 pt-6 border-t'} style={{ borderColor: 'var(--icon-button-secondary)' }}>
365
- <p className={'text-center text-xs max-w-4xl mx-auto'} style={{ color: 'var(--text-secondary)' }}>
366
- © 2025 Know Your Developer, LLC. All rights reserved. KYD Self-Check™, and associated marks are trademarks of Know Your Developer, LLC. This document is confidential, proprietary, and intended solely for the individual or entity to whom it is addressed. Unauthorized use, disclosure, copying, or distribution of this document or any of its contents is strictly prohibited and may be unlawful. Know Your Developer, LLC assumes no responsibility or liability for any errors or omissions contained herein. Report validity subject to the terms and conditions stated on the official Know Your Developer website located at https://knowyourdeveloper.ai.
367
- </p>
368
- </footer>
264
+ <div className={'pt-8 text-sm text-center'} style={{ color: 'var(--text-secondary)' }}>
265
+ Report Completed: {new Date(updatedAt).toLocaleString(undefined, {
266
+ year: 'numeric',
267
+ month: 'long',
268
+ day: 'numeric',
269
+ hour: 'numeric',
270
+ minute: '2-digit',
271
+ timeZoneName: 'short',
272
+ })}
273
+ </div>
274
+ </div>
275
+ </div>
276
+ <footer className={'mt-12 pt-6 border-t'} style={{ borderColor: 'var(--icon-button-secondary)' }}>
277
+ <p className={'text-center text-xs max-w-4xl mx-auto'} style={{ color: 'var(--text-secondary)' }}>
278
+ © 2025 Know Your Developer, LLC. All rights reserved. KYD Self-Check™, and associated marks are trademarks of Know Your Developer, LLC. This document is confidential, proprietary, and intended solely for the individual or entity to whom it is addressed. Unauthorized use, disclosure, copying, or distribution of this document or any of its contents is strictly prohibited and may be unlawful. Know Your Developer, LLC assumes no responsibility or liability for any errors or omissions contained herein. Report validity subject to the terms and conditions stated on the official Know Your Developer website located at https://knowyourdeveloper.ai.
279
+ </p>
280
+ </footer>
369
281
  </div>
370
282
  );
371
283
  };