betterwithage commited on
Commit
84b7275
·
verified ·
1 Parent(s): 7f8c86f

feat(frontier): NEW neuromorphic/spiking organ (LIF, MODELED) + honesty/sunset-domain fixes

Browse files

Adds /api/a11oy/v1/neuromorphic/spikes + neuromorphic 3D surface; repoints 6 user-facing a11oy.net refs to a-11-oy.com; ecosystem label LIVE->LIVE-STATIC.

spaces/sda/assets/sda-fabric.js ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ============================================================================
2
+ * SZL SDA — sda-fabric.js
3
+ * Honest, vendored, 0-CDN runtime wiring:
4
+ * 1. Live read of a11oy /v1/compute-pool with captured SNAPSHOT fallback.
5
+ * 2. Optional live read of killinchu /mosaic feed -> COP score panel (LIVE label).
6
+ * 3. Mount the "ask the fabric — verify a receipt" widget.
7
+ * 4. Poll for an SDA validation figure and swap it in when present.
8
+ * NEVER fabricates live status / numbers. Honest degradation per doctrine v11.
9
+ * ==========================================================================*/
10
+ (function () {
11
+ 'use strict';
12
+ var A11OY = 'https://a-11-oy.com';
13
+ var POOL = '/api/a11oy/v1/compute-pool';
14
+ var KILLINCHU = 'https://szlholdings-killinchu.hf.space'; // estate killinchu surface (HF Space host)
15
+ var MOSAIC_COP = '/api/killinchu/v1/mosaic/cop'; // fused COP + anomaly scores (PR #118)
16
+ var TIMEOUT = 9000;
17
+
18
+ function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){
19
+ return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; }); }
20
+
21
+ function pull(url, timeoutMs){
22
+ var ctl = (typeof AbortController!=='undefined') ? new AbortController() : null;
23
+ var to = ctl ? setTimeout(function(){ try{ctl.abort();}catch(e){} }, timeoutMs||TIMEOUT) : null;
24
+ return fetch(url, { signal: ctl ? ctl.signal : undefined, cache:'no-store' })
25
+ .then(function(r){ if(to)clearTimeout(to); if(!r.ok) throw new Error('http '+r.status); return r.json(); })
26
+ .catch(function(e){ if(to)clearTimeout(to); throw e; });
27
+ }
28
+
29
+ /* ---- compute-pool node list ---- */
30
+ function nodeRow(n){
31
+ var up = !!n.reachable;
32
+ var sov = !!n.sovereign;
33
+ var kindCls = sov ? 'sov' : (n.kind && n.kind.indexOf('hosted')===0 ? 'hosted' : '');
34
+ var kindLabel = sov ? 'sovereign' : (n.kind || 'node');
35
+ var meta = (n.endpoint ? esc(n.endpoint) : '') +
36
+ (sov ? '' : (n.kind && n.kind.indexOf('hosted')===0 ? ' · hosted fallback — not compute you own' : ''));
37
+ return '<li class="node">'+
38
+ '<span class="ndot '+(up?'up':'down')+'" title="'+(up?'reachable':'unreachable')+'"></span>'+
39
+ '<span class="ninfo"><span class="nname">'+esc(n.name||'node')+
40
+ (up?'':' · <span style="color:#FF6B7A">unreachable</span>')+'</span>'+
41
+ '<span class="nmeta">'+meta+'</span></span>'+
42
+ '<span class="nkind '+kindCls+'">'+esc(kindLabel)+'</span>'+
43
+ '</li>';
44
+ }
45
+
46
+ function renderPool(d, isLive){
47
+ var list = document.getElementById('node-list');
48
+ var srcBadge = document.getElementById('pool-src');
49
+ var connBadge = document.getElementById('conn-badge');
50
+ var connLabel = document.getElementById('conn-label');
51
+ if(!list) return;
52
+
53
+ var nodes = (d && d.nodes) || [];
54
+ list.innerHTML = nodes.map(nodeRow).join('') || '<li class="node"><span class="ninfo"><span class="nname">No nodes reported.</span></span></li>';
55
+
56
+ var c = (d && d.counts) || {};
57
+ var summary = document.createElement('li');
58
+ summary.className = 'node'; summary.style.background='transparent'; summary.style.border='none';
59
+ summary.innerHTML = '<span class="ninfo"><span class="nmeta tabular">'+
60
+ (c.nodes_reachable!=null?esc(c.nodes_reachable):'?')+'/'+(c.nodes_total!=null?esc(c.nodes_total):'?')+' reachable · '+
61
+ (c.gpu_nodes_reachable!=null?esc(c.gpu_nodes_reachable):'?')+' GPU node(s) · sovereign_gpu_live='+
62
+ esc(String((c.sovereign_gpu_live!=null)?c.sovereign_gpu_live:'?'))+'</span></span>';
63
+ list.appendChild(summary);
64
+
65
+ if(isLive){
66
+ if(srcBadge){ srcBadge.textContent='LIVE'; srcBadge.classList.add('live'); }
67
+ if(connBadge){ connBadge.classList.remove('snapshot'); }
68
+ if(connLabel){ connLabel.textContent='FABRIC: LIVE'; }
69
+ } else {
70
+ if(srcBadge){ srcBadge.textContent='SNAPSHOT'; srcBadge.classList.remove('live'); }
71
+ if(connBadge){ connBadge.classList.add('snapshot'); }
72
+ if(connLabel){ connLabel.textContent='FABRIC: SNAPSHOT'; }
73
+ }
74
+ }
75
+
76
+ function loadPool(){
77
+ pull(A11OY+POOL)
78
+ .then(function(d){ renderPool(d, true); })
79
+ .catch(function(){
80
+ pull('./assets/snapshot-compute-pool.json', 4000)
81
+ .then(function(d){ renderPool(d, false); })
82
+ .catch(function(){
83
+ var list = document.getElementById('node-list');
84
+ var connLabel = document.getElementById('conn-label');
85
+ if(list) list.innerHTML = '<li class="node"><span class="ninfo"><span class="nname">Fabric unreachable.</span>'+
86
+ '<span class="nmeta">Live read and snapshot both unavailable — status not shown rather than faked.</span></span></li>';
87
+ if(connLabel) connLabel.textContent='FABRIC: UNREACHABLE';
88
+ });
89
+ });
90
+ }
91
+
92
+ /* ---- killinchu /mosaic COP feed (LIVE upgrade of the demo COP) ----
93
+ * If killinchu's /mosaic/cop is reachable, push real anomaly scores into the
94
+ * COP panel and re-label the COP badges LIVE. Otherwise the demo stands,
95
+ * clearly labelled. NEVER fakes a live read. */
96
+ function loadMosaicCOP(){
97
+ pull(KILLINCHU+MOSAIC_COP)
98
+ .then(function(d){
99
+ var tracks = (d && (d.tracks || d.cop || d.fused)) || [];
100
+ var norm = tracks.map(function(t){
101
+ return { id: t.track_id || t.id || ('T-'+(t.fused_track_id||'?')),
102
+ score: (t.anomaly_score!=null?t.anomaly_score:(t.score!=null?t.score:0)) };
103
+ }).filter(function(t){ return t.id; });
104
+ if (norm.length && window.SDA_COP && window.SDA_COP.setTracks){
105
+ window.SDA_COP.setTracks(norm);
106
+ markCopLive();
107
+ }
108
+ })
109
+ .catch(function(){ /* keep honest DEMO label; no fabrication */ });
110
+ }
111
+ function markCopLive(){
112
+ ['cop-src','cop-feed-src'].forEach(function(id){
113
+ var b=document.getElementById(id); if(b){ b.textContent='LIVE · killinchu /mosaic'; b.classList.add('live'); }
114
+ });
115
+ var note=document.getElementById('cop-demo-note');
116
+ if(note){ note.innerHTML='<strong>Live read.</strong> The COP panel is showing real anomaly scores from the killinchu <code>/api/killinchu/v1/mosaic/cop</code> endpoint. Track motion remains an illustrative rendering; the scores and verdicts are live.'; }
117
+ }
118
+
119
+ /* ---- SDA validation figure swap-in (silent HEAD probe; no 404 noise) ---- */
120
+ function tryFigure(){
121
+ var img = document.getElementById('sda-fig-img');
122
+ if(!img) return;
123
+ fetch('assets/sda_validation.png', { method:'HEAD', cache:'no-store' })
124
+ .then(function(r){ if(!r.ok) throw new Error('absent'); return r; })
125
+ .then(function(){
126
+ img.onload = function(){
127
+ img.style.display='block';
128
+ var stage=document.querySelector('.cop-stage');
129
+ var note=document.getElementById('cop-demo-note');
130
+ var src=document.getElementById('cop-src');
131
+ if(stage) stage.parentNode && stage.parentNode.insertBefore(img, stage);
132
+ if(note){ note.innerHTML='<strong>SZL SDA validation figure.</strong> Produced by the khipu-sda-core validation harness.'; }
133
+ if(src){ src.textContent='SZL SDA — VALIDATION'; src.classList.add('live'); }
134
+ };
135
+ img.src='assets/sda_validation.png';
136
+ })
137
+ .catch(function(){ /* keep honest labelled demo COP */ });
138
+ }
139
+
140
+ function boot(){
141
+ loadPool();
142
+ loadMosaicCOP();
143
+ tryFigure();
144
+ if (window.SZLVerify && typeof window.SZLVerify.mount === 'function') {
145
+ try { window.SZLVerify.mount('#verify-mount', { base: A11OY }); } catch(e){}
146
+ }
147
+ }
148
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
149
+ else boot();
150
+ })();
spaces/sda/assets/szl_verify_widget.js ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ============================================================================
2
+ * SZL "ask the fabric" — verify-a-claim widget (vendored, self-contained)
3
+ * ----------------------------------------------------------------------------
4
+ * 0 runtime CDN · system fonts only · AbortController · honest fallback.
5
+ * Calls the REAL a11oy verify endpoint and renders its REAL honest verdict.
6
+ * POST {base}/api/a11oy/v1/verify body = a receipt / DSSE envelope / in-toto stmt
7
+ * GET {base}/api/a11oy/v1/verify?url=<public receipt url>
8
+ *
9
+ * Doctrine v11: this widget NEVER fabricates a verdict. It shows exactly what
10
+ * the server returns (verdict: VERIFIED | STRUCTURAL-ONLY | FAILED | UNRECOGNISED).
11
+ * "STRUCTURAL-ONLY" is shown as advisory, NOT green. Network/timeout/429 degrade
12
+ * to an honest "unreachable / rate-limited" state — never to a false green.
13
+ *
14
+ * Attribution (clean-room rebuild of permissive ideas — see dev7 report):
15
+ * - Tool-call / receipt trace UI pattern inspired by smolagents (Apache-2.0,
16
+ * huggingface/smolagents) and assistant-ui (MIT). Rebuilt SZL-native; no code copied.
17
+ * - AbortController fetch contract reuses anatomy V8 (SZL own prior art).
18
+ * ==========================================================================*/
19
+ (function (global) {
20
+ 'use strict';
21
+
22
+ var DEFAULT_BASE = 'https://a-11-oy.com'; // same fabric the estate already talks to
23
+ var TIMEOUT_MS = 12000;
24
+ var SAMPLE = {
25
+ _type: 'https://in-toto.io/Statement/v1',
26
+ subject: [{ name: 'szl-lake/homflyreceipt_gate',
27
+ digest: { sha256: '0a2d153d81c00688b576e5a012ae6117465639807456d1bb72eb590cac3b1e9d' } }],
28
+ predicateType: 'https://szlholdings.com/attestations/innovation/v1',
29
+ predicate: { note: 'paste your own receipt JSON here, or a public receipt URL' }
30
+ };
31
+
32
+ function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){
33
+ return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]; }); }
34
+
35
+ /* honest fetch contract: AbortController + try/catch. NEVER throws. ----- */
36
+ function pull(url, opts, timeoutMs){
37
+ var ctl = (typeof AbortController!=='undefined') ? new AbortController() : null;
38
+ var to = ctl ? setTimeout(function(){ try{ctl.abort();}catch(e){} }, timeoutMs||TIMEOUT_MS) : null;
39
+ opts = opts || {};
40
+ opts.signal = ctl ? ctl.signal : undefined;
41
+ opts.cache = 'no-store';
42
+ opts.mode = 'cors';
43
+ return fetch(url, opts).then(function(r){
44
+ if(to) clearTimeout(to);
45
+ var status = r.status;
46
+ return r.json().then(function(data){ return {ok:r.ok, status:status, data:data}; },
47
+ function(){ return {ok:false, status:status, data:null}; });
48
+ }).catch(function(e){
49
+ if(to) clearTimeout(to);
50
+ var aborted = e && (e.name==='AbortError');
51
+ return {ok:false, status:0, data:null, err:String(e&&e.message||e), aborted:aborted};
52
+ });
53
+ }
54
+
55
+ /* map an HONEST verdict string -> {label, cls, advisory} ---------------- */
56
+ function verdictView(v){
57
+ var s = String(v||'').toUpperCase();
58
+ if(s==='VERIFIED') return {label:'VERIFIED', cls:'ok', advisory:false};
59
+ if(s==='STRUCTURAL-ONLY') return {label:'STRUCTURAL-ONLY', cls:'warn', advisory:true};
60
+ if(s==='FAILED') return {label:'FAILED', cls:'fail', advisory:false};
61
+ if(s==='UNRECOGNISED') return {label:'UNRECOGNISED', cls:'muted',advisory:false};
62
+ return {label: s||'—', cls:'muted', advisory:false};
63
+ }
64
+
65
+ function renderChecks(checks){
66
+ if(!Array.isArray(checks) || !checks.length) return '';
67
+ var rows = checks.map(function(c){
68
+ var st = String(c.status||'').toLowerCase();
69
+ var cls = st==='pass' ? 'ok' : (st==='fail' ? 'fail' : 'muted');
70
+ return '<li class="szlv-chk"><span class="szlv-pill '+cls+'">'+esc(c.status||'?')+'</span>'+
71
+ '<code>'+esc(c.name||'check')+'</code>'+
72
+ (c.detail ? '<span class="szlv-det">'+esc(c.detail)+'</span>' : '')+'</li>';
73
+ }).join('');
74
+ return '<ul class="szlv-checks">'+rows+'</ul>';
75
+ }
76
+
77
+ function renderResult(res){
78
+ // res is the {ok,status,data,err,aborted} envelope from pull()
79
+ if(res.status===429){
80
+ return '<div class="szlv-state fail">rate-limited · the fabric caps at 60/min per IP. '+
81
+ 'This is honest backpressure, not a failure of your receipt. Try again shortly.</div>';
82
+ }
83
+ if(!res.ok || !res.data){
84
+ var why = res.aborted ? 'timed out' : (res.status ? ('HTTP '+res.status) : 'unreachable');
85
+ return '<div class="szlv-state muted">offline · fabric '+esc(why)+
86
+ '. No verdict shown — the widget never invents a green. '+
87
+ 'Re-run the checks yourself per docs/developers/VERIFY.md.</div>';
88
+ }
89
+ var d = res.data;
90
+ var vv = verdictView(d.verdict);
91
+ var head = '<div class="szlv-verdict '+vv.cls+'">'+
92
+ '<span class="szlv-dot"></span><b>'+esc(vv.label)+'</b>'+
93
+ (vv.advisory ? '<span class="szlv-adv">advisory · not a cryptographic green</span>' : '')+
94
+ '</div>';
95
+ var detail = d.detail ? '<p class="szlv-detail">'+esc(d.detail)+'</p>' : '';
96
+ var kinds = (Array.isArray(d.kinds)&&d.kinds.length)
97
+ ? '<p class="szlv-kinds">recognised as: '+d.kinds.map(esc).join(', ')+'</p>' : '';
98
+ var checks = renderChecks(d.checks);
99
+ var foot = '<p class="szlv-foot">engine '+esc(d.engine_version||'?')+
100
+ ' · doctrine '+esc((d.doctrine&&d.doctrine.version)||'v11')+
101
+ ' · Λ='+esc((d.doctrine&&d.doctrine.lambda)||'Conjecture 1')+
102
+ (d.verified_at ? ' · '+esc(d.verified_at) : '')+
103
+ '<br><span class="szlv-trust">No trust in the server is required — re-verify with cosign / rekor-cli / lake build.</span></p>';
104
+ return head+detail+kinds+checks+foot;
105
+ }
106
+
107
+ var CSS = [
108
+ '.szlv{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;',
109
+ 'color:#cdccca;background:#1c1b19;border:1px solid #393836;border-radius:10px;padding:16px;max-width:640px}',
110
+ '.szlv h3{font-size:15px;margin:0 0 4px;font-weight:600;letter-spacing:.2px}',
111
+ '.szlv .szlv-sub{font-size:12px;color:#797876;margin:0 0 12px}',
112
+ '.szlv textarea{width:100%;min-height:120px;box-sizing:border-box;background:#171614;color:#cdccca;',
113
+ 'border:1px solid #393836;border-radius:8px;padding:10px;font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;resize:vertical}',
114
+ '.szlv-row{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}',
115
+ '.szlv input[type=text]{flex:1;min-width:200px;background:#171614;color:#cdccca;border:1px solid #393836;border-radius:8px;padding:8px 10px;font-size:12px}',
116
+ '.szlv button{background:#01696f;color:#fff;border:0;border-radius:8px;padding:9px 16px;font-size:13px;font-weight:600;cursor:pointer}',
117
+ '.szlv button:hover{background:#0c4e54}.szlv button:disabled{opacity:.5;cursor:wait}',
118
+ '.szlv button.ghost{background:transparent;color:#4f98a3;border:1px solid #393836}',
119
+ '.szlv-out{margin-top:12px;font-size:13px;min-height:24px}',
120
+ '.szlv-load{color:#797876;font-size:12px}',
121
+ '.szlv-verdict{display:flex;align-items:center;gap:8px;font-size:15px;padding:8px 10px;border-radius:8px;border:1px solid #393836}',
122
+ '.szlv-verdict .szlv-dot{width:9px;height:9px;border-radius:50%}',
123
+ '.szlv-verdict.ok .szlv-dot{background:#6daa45}.szlv-verdict.ok{border-color:#3a5a26}',
124
+ '.szlv-verdict.warn .szlv-dot{background:#e8af34}.szlv-verdict.warn{border-color:#6b5418}',
125
+ '.szlv-verdict.fail .szlv-dot{background:#d163a7}.szlv-verdict.fail{border-color:#7a2c5a}',
126
+ '.szlv-verdict.muted .szlv-dot{background:#797876}',
127
+ '.szlv-adv{font-size:11px;color:#e8af34;font-weight:400;margin-left:auto}',
128
+ '.szlv-detail{font-size:12px;color:#a9a8a5;margin:8px 0}',
129
+ '.szlv-kinds{font-size:11px;color:#797876;margin:4px 0}',
130
+ '.szlv-checks{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:4px}',
131
+ '.szlv-chk{display:flex;align-items:center;gap:8px;font-size:12px;flex-wrap:wrap}',
132
+ '.szlv-pill{font-size:10px;text-transform:uppercase;letter-spacing:.4px;padding:2px 6px;border-radius:4px;font-weight:700}',
133
+ '.szlv-pill.ok{background:rgba(109,170,69,.18);color:#6daa45}',
134
+ '.szlv-pill.fail{background:rgba(209,99,167,.18);color:#d163a7}',
135
+ '.szlv-pill.muted{background:#2a2927;color:#797876}',
136
+ '.szlv-chk code{color:#cdccca}.szlv-det{color:#797876;font-size:11px}',
137
+ '.szlv-foot{font-size:10px;color:#5a5957;margin:10px 0 0;line-height:1.5}',
138
+ '.szlv-trust{color:#797876}',
139
+ '.szlv-state{font-size:12px;padding:8px 10px;border-radius:8px}',
140
+ '.szlv-state.fail{background:rgba(209,99,167,.10);color:#d163a7}',
141
+ '.szlv-state.muted{background:#211f1d;color:#a9a8a5}',
142
+ /* DEV B mobile refinement: 12px type floor + 44px touch targets (additive, no logic change) */
143
+ '@media (max-width:768px){',
144
+ '.szlv-adv,.szlv-kinds,.szlv-chk .szlv-det,.szlv-foot,.szlv-pill{font-size:12px}',
145
+ '.szlv button{min-height:44px;padding:11px 18px;font-size:14px}',
146
+ '.szlv input[type=text]{min-height:44px;font-size:13px}',
147
+ '.szlv textarea{font-size:13px}',
148
+ '.szlv-sub,.szlv-load,.szlv-detail,.szlv-state{font-size:13px}',
149
+ '}'].join('');
150
+
151
+ function injectCSS(){
152
+ if(document.getElementById('szlv-css')) return;
153
+ var st = document.createElement('style'); st.id='szlv-css'; st.textContent = CSS;
154
+ document.head.appendChild(st);
155
+ }
156
+
157
+ /* Public mount: SZLVerify.mount('#id', {base}) ------------------------- */
158
+ function mount(target, opts){
159
+ opts = opts || {};
160
+ var base = (opts.base || DEFAULT_BASE).replace(/\/+$/,'');
161
+ var host = (typeof target==='string') ? document.querySelector(target) : target;
162
+ if(!host) return null;
163
+ injectCSS();
164
+ host.classList.add('szlv');
165
+ host.innerHTML =
166
+ '<h3>ask the fabric — verify a receipt</h3>'+
167
+ '<p class="szlv-sub">Paste a Khipu receipt / DSSE envelope / in-toto statement, '+
168
+ 'or fetch a public receipt by URL. Verdicts are the fabric\u2019s real, honest output '+
169
+ '(unsigned \u2192 STRUCTURAL-ONLY, never a false green).</p>'+
170
+ '<textarea class="szlv-ta" spellcheck="false"></textarea>'+
171
+ '<div class="szlv-row">'+
172
+ '<input type="text" class="szlv-url" placeholder="\u2026or a public receipt URL (https://\u2026/receipt.json)">'+
173
+ '</div>'+
174
+ '<div class="szlv-row">'+
175
+ '<button class="szlv-go" type="button">Verify</button>'+
176
+ '<button class="szlv-sample ghost" type="button">Load sample receipt</button>'+
177
+ '</div>'+
178
+ '<div class="szlv-out" aria-live="polite"></div>';
179
+
180
+ var ta = host.querySelector('.szlv-ta');
181
+ var url = host.querySelector('.szlv-url');
182
+ var out = host.querySelector('.szlv-out');
183
+ var go = host.querySelector('.szlv-go');
184
+ var smp = host.querySelector('.szlv-sample');
185
+
186
+ smp.addEventListener('click', function(){ ta.value = JSON.stringify(SAMPLE, null, 2); url.value=''; });
187
+
188
+ go.addEventListener('click', function(){
189
+ go.disabled = true;
190
+ out.innerHTML = '<span class="szlv-load">calling <code>'+esc(base)+'/api/a11oy/v1/verify</code>\u2026</span>';
191
+ var p, u = url.value.trim(), body = ta.value.trim();
192
+ if(u){
193
+ p = pull(base+'/api/a11oy/v1/verify?url='+encodeURIComponent(u), {method:'GET'});
194
+ } else if(body){
195
+ var parsed = null;
196
+ try{ parsed = JSON.parse(body); }catch(e){
197
+ out.innerHTML = '<div class="szlv-state muted">input is not valid JSON — paste a receipt object or use a URL.</div>';
198
+ go.disabled = false; return;
199
+ }
200
+ p = pull(base+'/api/a11oy/v1/verify', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(parsed)});
201
+ } else {
202
+ out.innerHTML = '<div class="szlv-state muted">paste a receipt JSON, or enter a public receipt URL.</div>';
203
+ go.disabled = false; return;
204
+ }
205
+ p.then(function(res){ out.innerHTML = renderResult(res); go.disabled = false; });
206
+ });
207
+
208
+ return { reload:function(){}, base:base };
209
+ }
210
+
211
+ var api = { mount: mount, pull: pull, _sample: SAMPLE, version: '1.0.0' };
212
+ if (typeof module!=='undefined' && module.exports) module.exports = api;
213
+ global.SZLVerify = api;
214
+ })(typeof window!=='undefined' ? window : this);