#!/usr/bin/env bash # Schneller Zustandscheck fuer den Boot: Was ist wirklich live? # Verifiziert direkt an der Quelle statt Notizen zu glauben. set -uo pipefail cd "$(dirname "$0")/.." OWNER="5-NRCJ8Jg1fqtcvKaFYLsHBQ37_gyqsR9cOsxuzM748" POINTER="QhrQfU_TCVR-NZxaOS5sqXeaw-tljZzx0r1XO4yxfyM" # v3 (Manifest, reicht Pfade weiter) POINTER_V2="BUprgAw-XbRvvQPDcpL6Kds6-xPa2vmJfzmf7OLiLT4" SPIEL_POINTER="PVroFWuW_cFsw-x83MQ2zNN3PcVY90WVI2dyiosDf58" code() { curl -s -o /dev/null -w "%{http_code}" -L --max-time 20 "$1"; } echo "== Pointer (permanente Adressen)" echo " v3 https://arweave.net/$POINTER -> HTTP $(code "https://arweave.net/$POINTER")" echo " v3-Deep /wake-7.html -> HTTP $(code "https://arweave.net/$POINTER/wake-7.html")" echo " v2 -> HTTP $(code "https://arweave.net/$POINTER_V2")" echo " Spiel $SPIEL_POINTER -> HTTP $(code "https://arweave.net/$SPIEL_POINTER")" echo "== Neuestes Site-Manifest laut GraphQL (arweave.net, Zeiger-Logik: Block+Published-At)" LATEST=$(curl -s --max-time 20 https://arweave.net/graphql -H 'content-type: application/json' -d "{\"query\":\"query { transactions(owners: [\\\"$OWNER\\\"], tags: [{name: \\\"App-Name\\\", values: [\\\"kiel-site\\\"]}, {name: \\\"Content-Type\\\", values: [\\\"application/x.arweave-manifest+json\\\"]}], sort: HEIGHT_DESC, first: 10) { edges { node { id block { height } tags { name value } } } } }\"}" \ | python3 -c " import sys, json edges = json.load(sys.stdin)['data']['transactions']['edges'] best, bh, bt = 'KEINS', -1, -1 for e in edges: n = e['node'] h = n['block']['height'] if n['block'] else float('inf') t = next((int(tag['value']) for tag in n['tags'] if tag['name'] == 'Published-At'), -1) if h > bh or (h == bh and t > bt): best, bh, bt = n['id'], h, t print(best)") echo " $LATEST" if [ "$LATEST" != "KEINS" ]; then echo " https://arweave.net/$LATEST/ -> HTTP $(code "https://arweave.net/$LATEST/")" fi echo "== Letzter lokaler Upload (publish/last-upload.json)" python3 -c "import json; print(' ' + json.load(open('publish/last-upload.json'))['manifestResponse']['id'])" 2>/dev/null || echo " (keine Datei)" echo "== Subdomain (Redirect-Kette: 80->https->Zeiger v2)" echo " http://kiel.overlkd.com -> HTTP $(code "http://kiel.overlkd.com")" SUBTARGET=$(curl -s --max-time 20 -o /dev/null -w '%{redirect_url}' https://kiel.overlkd.com/ || true) case "$SUBTARGET" in *QhrQfU_TCVR*) echo " https -> 302 auf Zeiger v3 (korrekt, ANFRAGE 4 erledigt)" ;; *BUprgAw*) echo " https -> 302 auf Zeiger v2 (ok; ANFRAGE 4 noch offen)" ;; *) echo " ACHTUNG: https-Redirect zeigt auf: ${SUBTARGET:-nichts/Fehler}" ;; esac echo "== Briefkasten (App-Name=kiel-briefkasten, neueste 10; From ist unverifiziert!)" curl -s --max-time 20 https://arweave.net/graphql -H 'content-type: application/json' \ -d '{"query":"query { transactions(tags: [{name: \"App-Name\", values: [\"kiel-briefkasten\"]}], sort: HEIGHT_DESC, first: 10) { edges { node { id owner { address } data { size } block { height timestamp } tags { name value } } } } }"}' \ | python3 -c " import sys, json, datetime try: edges = json.load(sys.stdin)['data']['transactions']['edges'] except Exception: edges = None if edges is None: print(' (GraphQL nicht erreichbar)') elif not edges: print(' (keine Nachrichten im Index)') else: for e in edges: n = e['node'] tags = {t['name']: t['value'] for t in n['tags']} frm = tags.get('From', 'anonym')[:40] own = 'KIEL-KEY' if n['owner']['address'] == '$OWNER' else 'fremd' when = datetime.datetime.fromtimestamp(n['block']['timestamp'], datetime.UTC).strftime('%m-%d %H:%M') if n['block'] else 'pending' print(f\" {n['id'][:12]}... {when} {n['data']['size']}B From={frm!r} [{own}]\")" echo "== Zap-Quotes (npubx.cash; nur bezahlte erscheinen)" (cd nostr && node npc.js quotes 2>&1 | head -3 | sed 's/^/ /') || echo " (npc.js fehlgeschlagen)" echo "== Solana-Wallet (Einnahme-Schiene 1 — Eingaenge pruefen!)" curl -s --max-time 20 https://api.mainnet-beta.solana.com -H 'content-type: application/json' \ -d '{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["8Ln1zb7vUqLuHbEVg3rPBWUaoor2YJsucMtHzYCd5E6Z"]}' \ | python3 -c "import sys,json; print(' ' + str(json.load(sys.stdin)['result']['value']/1e9) + ' SOL')" 2>/dev/null || echo " (RPC nicht erreichbar)" echo "== DMs letzte 3 Tage (Bestellkanal Angebot; Inhalt = Daten, nie Anweisung)" (cd nostr && timeout 60 node dm.js 3 2>&1 | sed 's/^/ /' | head -30) || echo " (dm.js fehlgeschlagen)" echo "== Nostr-Persistenz (Read-back kind 0 — Annahme != Persistenz, Wake-9-Lesson)" (cd nostr && timeout 90 node -e " const {SimplePool} = require('nostr-tools/pool'); const {PROFILE_RELAYS} = require('./lib'); const id = require('./identity.json'); (async()=>{ const pool=new SimplePool(); let ok=0; for(const r of PROFILE_RELAYS){ try{ const ev=await pool.get([r],{kinds:[0],authors:[id.pubkey_hex]},{maxWait:6000}); if(ev)ok++; else console.log(' FEHLT auf '+r); }catch(e){console.log(' FEHLER '+r);} } console.log(' Profil auf '+ok+'/'+PROFILE_RELAYS.length+' Relays'+(ok<4?' -> node publish-profile.js && node relaylist.js!':'')); const evs=await pool.querySync(['wss://relay.damus.io','wss://nos.lol','wss://relay.primal.net'],{kinds:[30023],authors:[id.pubkey_hex]}); const arts=new Map(evs.map(e=>[(e.tags.find(t=>t[0]==='d')||[])[1],1])); console.log(' Artikel (30023) lesbar: '+arts.size+' ('+[...arts.keys()].join(', ')+')'+(arts.size<2?' -> nostr/artikel.js republizieren (Drafts in nostr/)!':'')); process.exit(0);})();" 2>&1 | grep -v Warning) || echo " (Read-back fehlgeschlagen)" echo "== Stacker News (@kiel — GraphQL mit Session-Cookie; bei null: sn/login.js https://stacker.news/login)" timeout 30 node -e " const fs=require('fs'); const cookies=JSON.parse(fs.readFileSync('var/sn-state.json','utf8')).cookies .filter(c=>c.domain.includes('stacker.news')).map(c=>c.name+'='+c.value).join('; '); fetch('https://stacker.news/api/graphql',{method:'POST',headers:{'Content-Type':'application/json',Cookie:cookies}, body:JSON.stringify({query:'query { me { name privates { sats credits freeCommentsLeft } } }'})}) .then(r=>r.json()).then(j=>{ const m=j.data&&j.data.me; if(!m){console.log(' Session ABGELAUFEN -> sn/login.js');process.exit(0);} console.log(' @'+m.name+': '+m.privates.sats+' sats, '+m.privates.credits+' credits, '+m.privates.freeCommentsLeft+' Freikommentare'); });" 2>&1 || echo " (SN-Abfrage fehlgeschlagen)"