@thessor/widget 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/dist/index.d.ts +28 -0
- package/dist/logo.d.ts +2 -0
- package/dist/styles.d.ts +1 -0
- package/dist/theme.d.ts +7 -0
- package/dist/thessor-widget.js +578 -0
- package/dist/thessor-widget.js.map +7 -0
- package/dist/thessor-widget.umd.js +403 -0
- package/dist/thessor-widget.umd.js.map +7 -0
- package/dist/types.d.ts +8 -0
- package/package.json +42 -0
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
// src/styles.ts
|
|
2
|
+
var styles = `
|
|
3
|
+
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap');
|
|
4
|
+
|
|
5
|
+
:host {
|
|
6
|
+
all: initial;
|
|
7
|
+
display: inline-block;
|
|
8
|
+
font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
9
|
+
-webkit-font-smoothing: antialiased;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
* {
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.root {
|
|
17
|
+
position: relative;
|
|
18
|
+
display: inline-block;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.badge {
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
gap: 11px;
|
|
25
|
+
padding: 10px 14px;
|
|
26
|
+
border-radius: 10px;
|
|
27
|
+
border: 1px solid var(--tw-border, rgba(0, 0, 0, 0.12));
|
|
28
|
+
background: var(--tw-bg, #ffffff);
|
|
29
|
+
color: var(--tw-fg, #16171a);
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
font-size: 13px;
|
|
32
|
+
font-weight: 500;
|
|
33
|
+
line-height: 1.2;
|
|
34
|
+
user-select: none;
|
|
35
|
+
transition: border-color 150ms ease, background 150ms ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.badge:hover {
|
|
39
|
+
border-color: var(--tw-border-hover, rgba(0, 0, 0, 0.22));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.badge:focus-visible {
|
|
43
|
+
outline: 2px solid #6c8cf5;
|
|
44
|
+
outline-offset: 2px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:host([data-theme='dark']) .badge,
|
|
48
|
+
.root.theme-dark .badge {
|
|
49
|
+
--tw-bg: #17181c;
|
|
50
|
+
--tw-fg: #f3f3f5;
|
|
51
|
+
--tw-border: rgba(255, 255, 255, 0.14);
|
|
52
|
+
--tw-border-hover: rgba(255, 255, 255, 0.26);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.dot {
|
|
56
|
+
width: 8px;
|
|
57
|
+
height: 8px;
|
|
58
|
+
border-radius: 50%;
|
|
59
|
+
background: #2fbf6c;
|
|
60
|
+
flex-shrink: 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.dot.dot-muted {
|
|
64
|
+
background: #9a9aa2;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.dot.dot-loading {
|
|
68
|
+
animation: pulse 1.4s ease-in-out infinite;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.logo {
|
|
72
|
+
display: inline-flex;
|
|
73
|
+
align-items: center;
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
height: 16px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.logo-img {
|
|
79
|
+
display: block;
|
|
80
|
+
height: 100%;
|
|
81
|
+
width: auto;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.logo-dark {
|
|
85
|
+
display: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
:host([data-theme='dark']) .logo-light,
|
|
89
|
+
.root.theme-dark .logo-light {
|
|
90
|
+
display: none;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
:host([data-theme='dark']) .logo-dark,
|
|
94
|
+
.root.theme-dark .logo-dark {
|
|
95
|
+
display: block;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.label {
|
|
99
|
+
white-space: nowrap;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.label .muted-text {
|
|
103
|
+
color: var(--tw-fg);
|
|
104
|
+
opacity: 0.6;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* --- Proof panel --- */
|
|
108
|
+
|
|
109
|
+
.panel-wrapper {
|
|
110
|
+
display: grid;
|
|
111
|
+
grid-template-rows: 0fr;
|
|
112
|
+
transition: grid-template-rows 220ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
113
|
+
position: absolute;
|
|
114
|
+
top: calc(100% + 8px);
|
|
115
|
+
left: 0;
|
|
116
|
+
width: max-content;
|
|
117
|
+
min-width: 320px;
|
|
118
|
+
max-width: min(380px, 92vw);
|
|
119
|
+
z-index: 2147483000;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.panel-wrapper.open {
|
|
123
|
+
grid-template-rows: 1fr;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.panel-inner {
|
|
127
|
+
overflow: hidden;
|
|
128
|
+
min-height: 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.panel {
|
|
132
|
+
background: #0b0b0e;
|
|
133
|
+
color: #f3f3f5;
|
|
134
|
+
border-radius: 14px;
|
|
135
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
136
|
+
padding: 16px;
|
|
137
|
+
opacity: 0;
|
|
138
|
+
transform: scale(0.96);
|
|
139
|
+
transform-origin: top left;
|
|
140
|
+
transition: opacity 220ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
141
|
+
transform 220ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
142
|
+
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.panel-wrapper.open .panel {
|
|
146
|
+
opacity: 1;
|
|
147
|
+
transform: scale(1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@media (prefers-reduced-motion: reduce) {
|
|
151
|
+
.panel-wrapper,
|
|
152
|
+
.panel {
|
|
153
|
+
transition: none !important;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.panel-header {
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
justify-content: space-between;
|
|
161
|
+
margin-bottom: 14px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.panel-title {
|
|
165
|
+
font-size: 13px;
|
|
166
|
+
font-weight: 600;
|
|
167
|
+
letter-spacing: 0.01em;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.live-indicator {
|
|
171
|
+
display: inline-flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: 6px;
|
|
174
|
+
font-size: 11px;
|
|
175
|
+
color: #6adf9a;
|
|
176
|
+
font-weight: 500;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.live-dot {
|
|
180
|
+
width: 6px;
|
|
181
|
+
height: 6px;
|
|
182
|
+
border-radius: 50%;
|
|
183
|
+
background: #2fbf6c;
|
|
184
|
+
box-shadow: 0 0 0 0 rgba(47, 191, 108, 0.5);
|
|
185
|
+
animation: live-pulse 2s ease-out infinite;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@keyframes live-pulse {
|
|
189
|
+
0% {
|
|
190
|
+
box-shadow: 0 0 0 0 rgba(47, 191, 108, 0.45);
|
|
191
|
+
}
|
|
192
|
+
70% {
|
|
193
|
+
box-shadow: 0 0 0 6px rgba(47, 191, 108, 0);
|
|
194
|
+
}
|
|
195
|
+
100% {
|
|
196
|
+
box-shadow: 0 0 0 0 rgba(47, 191, 108, 0);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@media (prefers-reduced-motion: reduce) {
|
|
201
|
+
.live-dot {
|
|
202
|
+
animation: none;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* stage chain */
|
|
207
|
+
|
|
208
|
+
.stage-chain {
|
|
209
|
+
display: grid;
|
|
210
|
+
grid-template-columns: auto 1fr auto 1fr auto 1fr auto;
|
|
211
|
+
row-gap: 8px;
|
|
212
|
+
margin-bottom: 16px;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.stage-dot {
|
|
216
|
+
grid-row: 1;
|
|
217
|
+
align-self: center;
|
|
218
|
+
width: 10px;
|
|
219
|
+
height: 10px;
|
|
220
|
+
border-radius: 50%;
|
|
221
|
+
flex-shrink: 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.stage-track {
|
|
225
|
+
grid-row: 1;
|
|
226
|
+
align-self: center;
|
|
227
|
+
height: 2px;
|
|
228
|
+
min-width: 14px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.stage-label {
|
|
232
|
+
grid-row: 2;
|
|
233
|
+
font-size: 10px;
|
|
234
|
+
text-align: center;
|
|
235
|
+
color: rgba(255, 255, 255, 0.6);
|
|
236
|
+
line-height: 1.3;
|
|
237
|
+
padding: 0 2px;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/* data rows */
|
|
241
|
+
|
|
242
|
+
.rows {
|
|
243
|
+
display: flex;
|
|
244
|
+
flex-direction: column;
|
|
245
|
+
gap: 9px;
|
|
246
|
+
padding: 12px 0;
|
|
247
|
+
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
248
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.row {
|
|
252
|
+
display: flex;
|
|
253
|
+
align-items: baseline;
|
|
254
|
+
justify-content: space-between;
|
|
255
|
+
gap: 12px;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.row-label {
|
|
259
|
+
font-size: 11px;
|
|
260
|
+
color: rgba(255, 255, 255, 0.5);
|
|
261
|
+
flex-shrink: 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.row-value {
|
|
265
|
+
font-family: 'IBM Plex Mono', ui-monospace, monospace;
|
|
266
|
+
font-size: 11px;
|
|
267
|
+
color: #f3f3f5;
|
|
268
|
+
text-align: right;
|
|
269
|
+
overflow-wrap: anywhere;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/* footer */
|
|
273
|
+
|
|
274
|
+
.panel-footer {
|
|
275
|
+
display: flex;
|
|
276
|
+
align-items: center;
|
|
277
|
+
justify-content: space-between;
|
|
278
|
+
margin-top: 12px;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.view-link {
|
|
282
|
+
font-size: 12px;
|
|
283
|
+
color: #a3b4f7;
|
|
284
|
+
text-decoration: none;
|
|
285
|
+
font-weight: 500;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.view-link:hover {
|
|
289
|
+
text-decoration: underline;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.watermark {
|
|
293
|
+
font-size: 10px;
|
|
294
|
+
color: rgba(255, 255, 255, 0.28);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* skeleton */
|
|
298
|
+
|
|
299
|
+
.skeleton-line {
|
|
300
|
+
height: 10px;
|
|
301
|
+
border-radius: 4px;
|
|
302
|
+
background: linear-gradient(
|
|
303
|
+
90deg,
|
|
304
|
+
rgba(255, 255, 255, 0.06) 25%,
|
|
305
|
+
rgba(255, 255, 255, 0.14) 37%,
|
|
306
|
+
rgba(255, 255, 255, 0.06) 63%
|
|
307
|
+
);
|
|
308
|
+
background-size: 400% 100%;
|
|
309
|
+
animation: shimmer 1.4s ease infinite;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
@keyframes shimmer {
|
|
313
|
+
0% {
|
|
314
|
+
background-position: 100% 50%;
|
|
315
|
+
}
|
|
316
|
+
100% {
|
|
317
|
+
background-position: 0 50%;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
@keyframes pulse {
|
|
322
|
+
0%, 100% {
|
|
323
|
+
opacity: 1;
|
|
324
|
+
}
|
|
325
|
+
50% {
|
|
326
|
+
opacity: 0.4;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
@media (prefers-reduced-motion: reduce) {
|
|
331
|
+
.skeleton-line,
|
|
332
|
+
.dot-loading {
|
|
333
|
+
animation: none;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.error-message {
|
|
338
|
+
font-size: 12px;
|
|
339
|
+
color: rgba(255, 255, 255, 0.65);
|
|
340
|
+
padding: 8px 0 4px;
|
|
341
|
+
line-height: 1.5;
|
|
342
|
+
}
|
|
343
|
+
`;
|
|
344
|
+
|
|
345
|
+
// src/assets/thessor-logo-black.png
|
|
346
|
+
var thessor_logo_black_default = "data:image/png;base64,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";
|
|
347
|
+
|
|
348
|
+
// src/assets/thessor-logo-white.png
|
|
349
|
+
var thessor_logo_white_default = "data:image/png;base64,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";
|
|
350
|
+
|
|
351
|
+
// src/logo.ts
|
|
352
|
+
var THESSOR_LOGO_LIGHT = thessor_logo_black_default;
|
|
353
|
+
var THESSOR_LOGO_DARK = thessor_logo_white_default;
|
|
354
|
+
|
|
355
|
+
// src/theme.ts
|
|
356
|
+
function parseRgbLightness(color) {
|
|
357
|
+
const match = color.match(/rgba?\(([^)]+)\)/);
|
|
358
|
+
if (!match || !match[1]) return null;
|
|
359
|
+
const parts = match[1].split(",").map((p) => parseFloat(p.trim()));
|
|
360
|
+
const [r, g, b, a] = parts;
|
|
361
|
+
if (r === void 0 || g === void 0 || b === void 0) return null;
|
|
362
|
+
if ([r, g, b].some((n) => Number.isNaN(n))) return null;
|
|
363
|
+
if (a === 0) return null;
|
|
364
|
+
return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
|
|
365
|
+
}
|
|
366
|
+
function detectHostTheme(el) {
|
|
367
|
+
const override = el.getAttribute("data-theme");
|
|
368
|
+
if (override === "light" || override === "dark") return override;
|
|
369
|
+
let node = el.parentElement;
|
|
370
|
+
while (node) {
|
|
371
|
+
const lightness = parseRgbLightness(getComputedStyle(node).backgroundColor);
|
|
372
|
+
if (lightness !== null) return lightness < 0.5 ? "dark" : "light";
|
|
373
|
+
node = node.parentElement;
|
|
374
|
+
}
|
|
375
|
+
return "light";
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// src/index.ts
|
|
379
|
+
var STAGES = [
|
|
380
|
+
{ label: "Hashed", color: "#6C8CF5" },
|
|
381
|
+
{ label: "Signed (ML-DSA-65)", color: "#8E84F2" },
|
|
382
|
+
{ label: "Merkle checkpoint", color: "#A186EF" },
|
|
383
|
+
{ label: "Bitcoin", color: "#B189EC" }
|
|
384
|
+
];
|
|
385
|
+
var API_BASE = "https://api.thessor.com/verify";
|
|
386
|
+
var PROOF_BASE = "https://thessor.com/verify";
|
|
387
|
+
function escapeHtml(value) {
|
|
388
|
+
const div = document.createElement("div");
|
|
389
|
+
div.textContent = value;
|
|
390
|
+
return div.innerHTML;
|
|
391
|
+
}
|
|
392
|
+
function formatTimestamp(iso) {
|
|
393
|
+
const date = new Date(iso);
|
|
394
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
395
|
+
return date.toLocaleString(void 0, { dateStyle: "medium", timeStyle: "short" });
|
|
396
|
+
}
|
|
397
|
+
function renderStageChainMarkup() {
|
|
398
|
+
let row = "";
|
|
399
|
+
STAGES.forEach((stage, i) => {
|
|
400
|
+
row += `<span class="stage-dot" style="background:${stage.color}"></span>`;
|
|
401
|
+
const next = STAGES[i + 1];
|
|
402
|
+
if (next) {
|
|
403
|
+
row += `<span class="stage-track" style="background:linear-gradient(to right, ${stage.color}, ${next.color})"></span>`;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
const labels = STAGES.map(
|
|
407
|
+
(stage, i) => `<span class="stage-label" style="grid-column:${i * 2 + 1}">${escapeHtml(stage.label)}</span>`
|
|
408
|
+
).join("");
|
|
409
|
+
return row + labels;
|
|
410
|
+
}
|
|
411
|
+
var ThessorBadge = class extends HTMLElement {
|
|
412
|
+
constructor() {
|
|
413
|
+
super();
|
|
414
|
+
this.state = "loading";
|
|
415
|
+
this.proof = null;
|
|
416
|
+
this.isOpen = false;
|
|
417
|
+
this.abortController = null;
|
|
418
|
+
this.hasRendered = false;
|
|
419
|
+
this.shadow = this.attachShadow({ mode: "open" });
|
|
420
|
+
}
|
|
421
|
+
connectedCallback() {
|
|
422
|
+
this.render();
|
|
423
|
+
this.applyTheme();
|
|
424
|
+
void this.fetchProof();
|
|
425
|
+
}
|
|
426
|
+
disconnectedCallback() {
|
|
427
|
+
this.abortController?.abort();
|
|
428
|
+
}
|
|
429
|
+
attributeChangedCallback(name) {
|
|
430
|
+
if (!this.hasRendered) return;
|
|
431
|
+
if (name === "data-theme") this.applyTheme();
|
|
432
|
+
if (name === "decision-id") void this.fetchProof();
|
|
433
|
+
}
|
|
434
|
+
applyTheme() {
|
|
435
|
+
const theme = detectHostTheme(this);
|
|
436
|
+
const root = this.shadow.querySelector(".root");
|
|
437
|
+
root?.classList.toggle("theme-dark", theme === "dark");
|
|
438
|
+
root?.classList.toggle("theme-light", theme === "light");
|
|
439
|
+
}
|
|
440
|
+
async fetchProof() {
|
|
441
|
+
const id = this.getAttribute("decision-id");
|
|
442
|
+
this.abortController?.abort();
|
|
443
|
+
if (!id) {
|
|
444
|
+
this.setState("error");
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
this.setState("loading");
|
|
448
|
+
const controller = new AbortController();
|
|
449
|
+
this.abortController = controller;
|
|
450
|
+
try {
|
|
451
|
+
const res = await fetch(`${API_BASE}/${encodeURIComponent(id)}`, { signal: controller.signal });
|
|
452
|
+
if (!res.ok) throw new Error(`Request failed with status ${res.status}`);
|
|
453
|
+
const data = await res.json();
|
|
454
|
+
this.proof = data;
|
|
455
|
+
this.setState("success");
|
|
456
|
+
} catch (err) {
|
|
457
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
458
|
+
this.proof = null;
|
|
459
|
+
this.setState("error");
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
setState(state) {
|
|
463
|
+
this.state = state;
|
|
464
|
+
this.renderBadgeContent();
|
|
465
|
+
this.renderPanelContent();
|
|
466
|
+
}
|
|
467
|
+
togglePanel() {
|
|
468
|
+
this.isOpen = !this.isOpen;
|
|
469
|
+
this.shadow.querySelector(".panel-wrapper")?.classList.toggle("open", this.isOpen);
|
|
470
|
+
this.shadow.querySelector(".badge")?.setAttribute("aria-expanded", String(this.isOpen));
|
|
471
|
+
}
|
|
472
|
+
render() {
|
|
473
|
+
this.shadow.innerHTML = `
|
|
474
|
+
<style>${styles}</style>
|
|
475
|
+
<div class="root">
|
|
476
|
+
<button type="button" class="badge" part="badge" aria-expanded="false" aria-haspopup="true">
|
|
477
|
+
<span class="dot dot-loading"></span>
|
|
478
|
+
<span class="label">Verified \xB7 Sealed by Thessor</span>
|
|
479
|
+
<span class="logo">
|
|
480
|
+
<img class="logo-img logo-light" src="${THESSOR_LOGO_LIGHT}" alt="Thessor" />
|
|
481
|
+
<img class="logo-img logo-dark" src="${THESSOR_LOGO_DARK}" alt="Thessor" />
|
|
482
|
+
</span>
|
|
483
|
+
</button>
|
|
484
|
+
<div class="panel-wrapper">
|
|
485
|
+
<div class="panel-inner">
|
|
486
|
+
<div class="panel" role="region" aria-label="Thessor verification proof">
|
|
487
|
+
<div class="panel-content"></div>
|
|
488
|
+
</div>
|
|
489
|
+
</div>
|
|
490
|
+
</div>
|
|
491
|
+
</div>
|
|
492
|
+
`;
|
|
493
|
+
this.shadow.querySelector(".badge")?.addEventListener("click", () => this.togglePanel());
|
|
494
|
+
this.hasRendered = true;
|
|
495
|
+
this.renderBadgeContent();
|
|
496
|
+
this.renderPanelContent();
|
|
497
|
+
}
|
|
498
|
+
renderBadgeContent() {
|
|
499
|
+
const dot = this.shadow.querySelector(".dot");
|
|
500
|
+
const label = this.shadow.querySelector(".label");
|
|
501
|
+
if (!dot || !label) return;
|
|
502
|
+
dot.className = "dot";
|
|
503
|
+
if (this.state === "error") {
|
|
504
|
+
dot.classList.add("dot-muted");
|
|
505
|
+
label.innerHTML = `<span class="muted-text">Unable to verify</span>`;
|
|
506
|
+
} else {
|
|
507
|
+
if (this.state === "loading") dot.classList.add("dot-loading");
|
|
508
|
+
label.textContent = "Verified \xB7 Sealed by Thessor";
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
renderPanelContent() {
|
|
512
|
+
const content = this.shadow.querySelector(".panel-content");
|
|
513
|
+
if (!content) return;
|
|
514
|
+
const id = escapeHtml(this.getAttribute("decision-id") ?? "");
|
|
515
|
+
const header = `
|
|
516
|
+
<div class="panel-header">
|
|
517
|
+
<span class="panel-title">Verification Proof</span>
|
|
518
|
+
<span class="live-indicator"><span class="live-dot"></span>Verified</span>
|
|
519
|
+
</div>
|
|
520
|
+
`;
|
|
521
|
+
const footer = (linkable) => `
|
|
522
|
+
<div class="panel-footer">
|
|
523
|
+
${linkable ? `<a class="view-link" href="${PROOF_BASE}/${id}" target="_blank" rel="noopener noreferrer">View full proof \u2192</a>` : "<span></span>"}
|
|
524
|
+
<span class="watermark">thessor.com</span>
|
|
525
|
+
</div>
|
|
526
|
+
`;
|
|
527
|
+
if (this.state === "loading") {
|
|
528
|
+
content.innerHTML = `
|
|
529
|
+
${header}
|
|
530
|
+
<div class="stage-chain">${renderStageChainMarkup()}</div>
|
|
531
|
+
<div class="rows">
|
|
532
|
+
<div class="skeleton-line" style="width: 90%"></div>
|
|
533
|
+
<div class="skeleton-line" style="width: 70%"></div>
|
|
534
|
+
<div class="skeleton-line" style="width: 55%"></div>
|
|
535
|
+
</div>
|
|
536
|
+
${footer(false)}
|
|
537
|
+
`;
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
if (this.state === "error") {
|
|
541
|
+
content.innerHTML = `
|
|
542
|
+
${header}
|
|
543
|
+
<p class="error-message">We couldn't reach Thessor to verify this credential right now. This doesn't necessarily mean it's invalid \u2014 please try again shortly.</p>
|
|
544
|
+
${footer(Boolean(this.getAttribute("decision-id")))}
|
|
545
|
+
`;
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const proof = this.proof;
|
|
549
|
+
if (!proof) return;
|
|
550
|
+
content.innerHTML = `
|
|
551
|
+
${header}
|
|
552
|
+
<div class="stage-chain">${renderStageChainMarkup()}</div>
|
|
553
|
+
<div class="rows">
|
|
554
|
+
<div class="row">
|
|
555
|
+
<span class="row-label">Envelope ID</span>
|
|
556
|
+
<span class="row-value">${escapeHtml(proof.envelope_id)}</span>
|
|
557
|
+
</div>
|
|
558
|
+
<div class="row">
|
|
559
|
+
<span class="row-label">Sealed</span>
|
|
560
|
+
<span class="row-value">${escapeHtml(formatTimestamp(proof.created_at))}</span>
|
|
561
|
+
</div>
|
|
562
|
+
<div class="row">
|
|
563
|
+
<span class="row-label">Signature suite</span>
|
|
564
|
+
<span class="row-value">${escapeHtml(proof.signature_suite)}</span>
|
|
565
|
+
</div>
|
|
566
|
+
</div>
|
|
567
|
+
${footer(true)}
|
|
568
|
+
`;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
ThessorBadge.observedAttributes = ["decision-id", "data-theme"];
|
|
572
|
+
if (!customElements.get("thessor-badge")) {
|
|
573
|
+
customElements.define("thessor-badge", ThessorBadge);
|
|
574
|
+
}
|
|
575
|
+
export {
|
|
576
|
+
ThessorBadge
|
|
577
|
+
};
|
|
578
|
+
//# sourceMappingURL=thessor-widget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/styles.ts", "../src/logo.ts", "../src/theme.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["export const styles = `\n@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap');\n\n:host {\n all: initial;\n display: inline-block;\n font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;\n -webkit-font-smoothing: antialiased;\n}\n\n* {\n box-sizing: border-box;\n}\n\n.root {\n position: relative;\n display: inline-block;\n}\n\n.badge {\n display: inline-flex;\n align-items: center;\n gap: 11px;\n padding: 10px 14px;\n border-radius: 10px;\n border: 1px solid var(--tw-border, rgba(0, 0, 0, 0.12));\n background: var(--tw-bg, #ffffff);\n color: var(--tw-fg, #16171a);\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.2;\n user-select: none;\n transition: border-color 150ms ease, background 150ms ease;\n}\n\n.badge:hover {\n border-color: var(--tw-border-hover, rgba(0, 0, 0, 0.22));\n}\n\n.badge:focus-visible {\n outline: 2px solid #6c8cf5;\n outline-offset: 2px;\n}\n\n:host([data-theme='dark']) .badge,\n.root.theme-dark .badge {\n --tw-bg: #17181c;\n --tw-fg: #f3f3f5;\n --tw-border: rgba(255, 255, 255, 0.14);\n --tw-border-hover: rgba(255, 255, 255, 0.26);\n}\n\n.dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #2fbf6c;\n flex-shrink: 0;\n}\n\n.dot.dot-muted {\n background: #9a9aa2;\n}\n\n.dot.dot-loading {\n animation: pulse 1.4s ease-in-out infinite;\n}\n\n.logo {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n height: 16px;\n}\n\n.logo-img {\n display: block;\n height: 100%;\n width: auto;\n}\n\n.logo-dark {\n display: none;\n}\n\n:host([data-theme='dark']) .logo-light,\n.root.theme-dark .logo-light {\n display: none;\n}\n\n:host([data-theme='dark']) .logo-dark,\n.root.theme-dark .logo-dark {\n display: block;\n}\n\n.label {\n white-space: nowrap;\n}\n\n.label .muted-text {\n color: var(--tw-fg);\n opacity: 0.6;\n}\n\n/* --- Proof panel --- */\n\n.panel-wrapper {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows 220ms cubic-bezier(0.4, 0, 0.2, 1);\n position: absolute;\n top: calc(100% + 8px);\n left: 0;\n width: max-content;\n min-width: 320px;\n max-width: min(380px, 92vw);\n z-index: 2147483000;\n}\n\n.panel-wrapper.open {\n grid-template-rows: 1fr;\n}\n\n.panel-inner {\n overflow: hidden;\n min-height: 0;\n}\n\n.panel {\n background: #0b0b0e;\n color: #f3f3f5;\n border-radius: 14px;\n border: 1px solid rgba(255, 255, 255, 0.08);\n padding: 16px;\n opacity: 0;\n transform: scale(0.96);\n transform-origin: top left;\n transition: opacity 220ms cubic-bezier(0.4, 0, 0.2, 1),\n transform 220ms cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);\n}\n\n.panel-wrapper.open .panel {\n opacity: 1;\n transform: scale(1);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .panel-wrapper,\n .panel {\n transition: none !important;\n }\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 14px;\n}\n\n.panel-title {\n font-size: 13px;\n font-weight: 600;\n letter-spacing: 0.01em;\n}\n\n.live-indicator {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n color: #6adf9a;\n font-weight: 500;\n}\n\n.live-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: #2fbf6c;\n box-shadow: 0 0 0 0 rgba(47, 191, 108, 0.5);\n animation: live-pulse 2s ease-out infinite;\n}\n\n@keyframes live-pulse {\n 0% {\n box-shadow: 0 0 0 0 rgba(47, 191, 108, 0.45);\n }\n 70% {\n box-shadow: 0 0 0 6px rgba(47, 191, 108, 0);\n }\n 100% {\n box-shadow: 0 0 0 0 rgba(47, 191, 108, 0);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .live-dot {\n animation: none;\n }\n}\n\n/* stage chain */\n\n.stage-chain {\n display: grid;\n grid-template-columns: auto 1fr auto 1fr auto 1fr auto;\n row-gap: 8px;\n margin-bottom: 16px;\n}\n\n.stage-dot {\n grid-row: 1;\n align-self: center;\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.stage-track {\n grid-row: 1;\n align-self: center;\n height: 2px;\n min-width: 14px;\n}\n\n.stage-label {\n grid-row: 2;\n font-size: 10px;\n text-align: center;\n color: rgba(255, 255, 255, 0.6);\n line-height: 1.3;\n padding: 0 2px;\n}\n\n/* data rows */\n\n.rows {\n display: flex;\n flex-direction: column;\n gap: 9px;\n padding: 12px 0;\n border-top: 1px solid rgba(255, 255, 255, 0.08);\n border-bottom: 1px solid rgba(255, 255, 255, 0.08);\n}\n\n.row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 12px;\n}\n\n.row-label {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.5);\n flex-shrink: 0;\n}\n\n.row-value {\n font-family: 'IBM Plex Mono', ui-monospace, monospace;\n font-size: 11px;\n color: #f3f3f5;\n text-align: right;\n overflow-wrap: anywhere;\n}\n\n/* footer */\n\n.panel-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 12px;\n}\n\n.view-link {\n font-size: 12px;\n color: #a3b4f7;\n text-decoration: none;\n font-weight: 500;\n}\n\n.view-link:hover {\n text-decoration: underline;\n}\n\n.watermark {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.28);\n}\n\n/* skeleton */\n\n.skeleton-line {\n height: 10px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n rgba(255, 255, 255, 0.06) 25%,\n rgba(255, 255, 255, 0.14) 37%,\n rgba(255, 255, 255, 0.06) 63%\n );\n background-size: 400% 100%;\n animation: shimmer 1.4s ease infinite;\n}\n\n@keyframes shimmer {\n 0% {\n background-position: 100% 50%;\n }\n 100% {\n background-position: 0 50%;\n }\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.4;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .skeleton-line,\n .dot-loading {\n animation: none;\n }\n}\n\n.error-message {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.65);\n padding: 8px 0 4px;\n line-height: 1.5;\n}\n`;\n", "import logoBlack from './assets/thessor-logo-black.png';\nimport logoWhite from './assets/thessor-logo-white.png';\n\n// Real Thessor cube-grid mark, bundled as inlined data URIs so the widget\n// stays a single file (no separate asset requests when loaded via CDN).\nexport const THESSOR_LOGO_LIGHT = logoBlack; // black mark, for light-background hosts\nexport const THESSOR_LOGO_DARK = logoWhite; // white mark, for dark-background hosts\n", "import type { ThemeMode } from './types';\n\n/**\n * Coarse perceptual lightness from an rgb()/rgba() computed-style string.\n * Not the sRGB-linearized WCAG formula \u2014 we only need a light/dark call,\n * not an accessibility contrast ratio.\n */\nfunction parseRgbLightness(color: string): number | null {\n const match = color.match(/rgba?\\(([^)]+)\\)/);\n if (!match || !match[1]) return null;\n const parts = match[1].split(',').map((p) => parseFloat(p.trim()));\n const [r, g, b, a] = parts;\n if (r === undefined || g === undefined || b === undefined) return null;\n if ([r, g, b].some((n) => Number.isNaN(n))) return null;\n if (a === 0) return null;\n return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;\n}\n\n/**\n * Walks up from the host element looking for the nearest ancestor with a\n * non-transparent background-color to decide light vs. dark. A\n * `data-theme` attribute on the badge itself always wins.\n */\nexport function detectHostTheme(el: HTMLElement): ThemeMode {\n const override = el.getAttribute('data-theme');\n if (override === 'light' || override === 'dark') return override;\n\n let node: Element | null = el.parentElement;\n while (node) {\n const lightness = parseRgbLightness(getComputedStyle(node).backgroundColor);\n if (lightness !== null) return lightness < 0.5 ? 'dark' : 'light';\n node = node.parentElement;\n }\n return 'light';\n}\n", "import { styles } from './styles';\nimport { THESSOR_LOGO_LIGHT, THESSOR_LOGO_DARK } from './logo';\nimport { detectHostTheme } from './theme';\nimport type { BadgeState, ProofData } from './types';\n\nconst STAGES: Array<{ label: string; color: string }> = [\n { label: 'Hashed', color: '#6C8CF5' },\n { label: 'Signed (ML-DSA-65)', color: '#8E84F2' },\n { label: 'Merkle checkpoint', color: '#A186EF' },\n { label: 'Bitcoin', color: '#B189EC' },\n];\n\nconst API_BASE = 'https://api.thessor.com/verify';\nconst PROOF_BASE = 'https://thessor.com/verify';\n\nfunction escapeHtml(value: string): string {\n const div = document.createElement('div');\n div.textContent = value;\n return div.innerHTML;\n}\n\nfunction formatTimestamp(iso: string): string {\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return iso;\n return date.toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' });\n}\n\nfunction renderStageChainMarkup(): string {\n let row = '';\n STAGES.forEach((stage, i) => {\n row += `<span class=\"stage-dot\" style=\"background:${stage.color}\"></span>`;\n const next = STAGES[i + 1];\n if (next) {\n row += `<span class=\"stage-track\" style=\"background:linear-gradient(to right, ${stage.color}, ${next.color})\"></span>`;\n }\n });\n const labels = STAGES.map(\n (stage, i) => `<span class=\"stage-label\" style=\"grid-column:${i * 2 + 1}\">${escapeHtml(stage.label)}</span>`\n ).join('');\n return row + labels;\n}\n\n/**\n * Framework-agnostic verification badge. Renders a pill showing Thessor's\n * verification status; clicking it expands an inline proof panel populated\n * from `GET /verify/{decision-id}`.\n *\n * Usage: <thessor-badge decision-id=\"env_...\"></thessor-badge>\n * Theme override: <thessor-badge decision-id=\"...\" data-theme=\"dark\">\n */\nexport class ThessorBadge extends HTMLElement {\n static observedAttributes = ['decision-id', 'data-theme'];\n\n private shadow: ShadowRoot;\n private state: BadgeState = 'loading';\n private proof: ProofData | null = null;\n private isOpen = false;\n private abortController: AbortController | null = null;\n private hasRendered = false;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.render();\n this.applyTheme();\n void this.fetchProof();\n }\n\n disconnectedCallback(): void {\n this.abortController?.abort();\n }\n\n attributeChangedCallback(name: string): void {\n if (!this.hasRendered) return;\n if (name === 'data-theme') this.applyTheme();\n if (name === 'decision-id') void this.fetchProof();\n }\n\n private applyTheme(): void {\n const theme = detectHostTheme(this);\n const root = this.shadow.querySelector('.root');\n root?.classList.toggle('theme-dark', theme === 'dark');\n root?.classList.toggle('theme-light', theme === 'light');\n }\n\n private async fetchProof(): Promise<void> {\n const id = this.getAttribute('decision-id');\n this.abortController?.abort();\n\n if (!id) {\n this.setState('error');\n return;\n }\n\n this.setState('loading');\n const controller = new AbortController();\n this.abortController = controller;\n\n try {\n const res = await fetch(`${API_BASE}/${encodeURIComponent(id)}`, { signal: controller.signal });\n if (!res.ok) throw new Error(`Request failed with status ${res.status}`);\n const data = (await res.json()) as ProofData;\n this.proof = data;\n this.setState('success');\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n this.proof = null;\n this.setState('error');\n }\n }\n\n private setState(state: BadgeState): void {\n this.state = state;\n this.renderBadgeContent();\n this.renderPanelContent();\n }\n\n private togglePanel(): void {\n this.isOpen = !this.isOpen;\n this.shadow.querySelector('.panel-wrapper')?.classList.toggle('open', this.isOpen);\n this.shadow.querySelector('.badge')?.setAttribute('aria-expanded', String(this.isOpen));\n }\n\n private render(): void {\n this.shadow.innerHTML = `\n <style>${styles}</style>\n <div class=\"root\">\n <button type=\"button\" class=\"badge\" part=\"badge\" aria-expanded=\"false\" aria-haspopup=\"true\">\n <span class=\"dot dot-loading\"></span>\n <span class=\"label\">Verified \u00B7 Sealed by Thessor</span>\n <span class=\"logo\">\n <img class=\"logo-img logo-light\" src=\"${THESSOR_LOGO_LIGHT}\" alt=\"Thessor\" />\n <img class=\"logo-img logo-dark\" src=\"${THESSOR_LOGO_DARK}\" alt=\"Thessor\" />\n </span>\n </button>\n <div class=\"panel-wrapper\">\n <div class=\"panel-inner\">\n <div class=\"panel\" role=\"region\" aria-label=\"Thessor verification proof\">\n <div class=\"panel-content\"></div>\n </div>\n </div>\n </div>\n </div>\n `;\n this.shadow.querySelector('.badge')?.addEventListener('click', () => this.togglePanel());\n this.hasRendered = true;\n this.renderBadgeContent();\n this.renderPanelContent();\n }\n\n private renderBadgeContent(): void {\n const dot = this.shadow.querySelector('.dot');\n const label = this.shadow.querySelector('.label');\n if (!dot || !label) return;\n\n dot.className = 'dot';\n if (this.state === 'error') {\n dot.classList.add('dot-muted');\n label.innerHTML = `<span class=\"muted-text\">Unable to verify</span>`;\n } else {\n if (this.state === 'loading') dot.classList.add('dot-loading');\n label.textContent = 'Verified \u00B7 Sealed by Thessor';\n }\n }\n\n private renderPanelContent(): void {\n const content = this.shadow.querySelector('.panel-content');\n if (!content) return;\n\n const id = escapeHtml(this.getAttribute('decision-id') ?? '');\n const header = `\n <div class=\"panel-header\">\n <span class=\"panel-title\">Verification Proof</span>\n <span class=\"live-indicator\"><span class=\"live-dot\"></span>Verified</span>\n </div>\n `;\n const footer = (linkable: boolean) => `\n <div class=\"panel-footer\">\n ${\n linkable\n ? `<a class=\"view-link\" href=\"${PROOF_BASE}/${id}\" target=\"_blank\" rel=\"noopener noreferrer\">View full proof \u2192</a>`\n : '<span></span>'\n }\n <span class=\"watermark\">thessor.com</span>\n </div>\n `;\n\n if (this.state === 'loading') {\n content.innerHTML = `\n ${header}\n <div class=\"stage-chain\">${renderStageChainMarkup()}</div>\n <div class=\"rows\">\n <div class=\"skeleton-line\" style=\"width: 90%\"></div>\n <div class=\"skeleton-line\" style=\"width: 70%\"></div>\n <div class=\"skeleton-line\" style=\"width: 55%\"></div>\n </div>\n ${footer(false)}\n `;\n return;\n }\n\n if (this.state === 'error') {\n content.innerHTML = `\n ${header}\n <p class=\"error-message\">We couldn't reach Thessor to verify this credential right now. This doesn't necessarily mean it's invalid \u2014 please try again shortly.</p>\n ${footer(Boolean(this.getAttribute('decision-id')))}\n `;\n return;\n }\n\n const proof = this.proof;\n if (!proof) return;\n\n content.innerHTML = `\n ${header}\n <div class=\"stage-chain\">${renderStageChainMarkup()}</div>\n <div class=\"rows\">\n <div class=\"row\">\n <span class=\"row-label\">Envelope ID</span>\n <span class=\"row-value\">${escapeHtml(proof.envelope_id)}</span>\n </div>\n <div class=\"row\">\n <span class=\"row-label\">Sealed</span>\n <span class=\"row-value\">${escapeHtml(formatTimestamp(proof.created_at))}</span>\n </div>\n <div class=\"row\">\n <span class=\"row-label\">Signature suite</span>\n <span class=\"row-value\">${escapeHtml(proof.signature_suite)}</span>\n </div>\n </div>\n ${footer(true)}\n `;\n }\n}\n\nif (!customElements.get('thessor-badge')) {\n customElements.define('thessor-badge', ThessorBadge);\n}\n"],
|
|
5
|
+
"mappings": ";AAAO,IAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|