PageSourceSearch

https://sabr-liart.vercel.app/src/lib/sync.js?v=487

js sabr-liart.vercel.app collected 2026-10-03 07:39:05 UTC 2,637 bytes, 56 lines download raw bytes

1// ════════════════════════════════════════════════════════════════
2// SABR.AI · Sync-Client (v123)
3// ────────────────────────────────────────────────────────────────
4// Spricht mit /api/family (Vercel Serverless). Läuft die App über
5// Tunnel/localhost, wird automatisch die Live-Domain angesprochen
6// (CORS ist serverseitig offen). Graceful: jeder Fehler → die App
7// arbeitet lokal weiter wie bisher.
8//
9// Public:
10//   window.SABR_sync.call(payload)   → Promise<json>
11//   window.SABR_sync.deviceId()      → stabile Geräte-ID
12//   window.SABR_sync.online          → letzter Call ok?
13//   window.SABR_sync.persistent      → Server-Storage dauerhaft?
14// ════════════════════════════════════════════════════════════════
15(function () {
16  'use strict';
17
18  const LIVE_ORIGIN = 'https://sabr-liart.vercel.app';
19  const onLive = /\.vercel\.app$/.test(location.hostname);
20  const API = (onLive ? '' : LIVE_ORIGIN) + '/api/family';
21
22  function deviceId() {
23    let id = null;
24    try { id = localStorage.getItem('sabr_device_id'); } catch (_) {}
25    if (!id) {
26      id = 'd' + Math.random().toString(36).slice(2, 10) + Date.now().toString(36);
27      try { localStorage.setItem('sabr_device_id', id); } catch (_) {}
28    }
29    return id;
30  }
31
32  async function call(payload, timeoutMs) {
33    const ctrl = new AbortController();
34    const to = setTimeout(() => ctrl.abort(), timeoutMs || 7000);
35    try {
36      const r = await fetch(API, {
37        method: 'POST',
38        headers: { 'Content-Type': 'application/json' },
39        body: JSON.stringify(Object.assign({ deviceId: deviceId() }, payload)),
40        signal: ctrl.signal
41      });
42      const j = await r.json().catch(() => ({ ok: false, error: 'parse' }));
43      window.SABR_sync.online = !!j.ok || r.status === 404 || r.status === 403; // Server erreichbar
44      if (typeof j.persistent === 'boolean') window.SABR_sync.persistent = j.persistent;
45      j.httpStatus = r.status;
46      return j;
47    } catch (e) {
48      window.SABR_sync.online = false;
49      return { ok: false, error: 'network', detail: String(e && e.name || e) };
50    } finally {
51      clearTimeout(to);
52    }
53  }
54
55  window.SABR_sync = { call: call, deviceId: deviceId, online: null, persistent: null, api: API };
56})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.