HTTP live receivers
SQSAPI-11.4c1 connects shared HTTP polling for GeoJSON sources configured with sqsLive. Start with MapLibre-style addSource/getSource, then use source.sqs.connectLive. See the protocol and manual ingestion and snapshots. WebSocket reconnection is now a separate implemented stage; scene ownership and the mobile host remain subsequent work.
import {map} from 'sqsmap';
map.addSource('positions',{type:'geojson',data:{type:'FeatureCollection',features:[]},sqsLive:{fields:{n:'number'},allowDelta:true}});
await map.sqs.flush();
const source=await map.getSource('positions');
const receiver=await source.sqs.connectLive({protocol:'gis-live-v1',transport:{type:'http-poll',url:'https://your-server.example/live',intervalMs:2000}});
const state=await receiver.getState();
await receiver.pause();
await receiver.resume();
const frozen=await source.sqs.freezeLiveSnapshot();
await receiver.stop();
Replace the placeholder URL with a service returning raw gis-live-v1 JSON batches, one snapshot or delta per response. Browser endpoints must allow the page origin through CORS. Independent SDK code uses the same source.sqs calls and map.flush(); portable scripts use map.sqs.flush(). Connection confirms registration and queued I/O, not first data arrival. Observe sourcedata/error for completion. Never convert decimal u128 sequences to JS numbers.
connectLive returns a handle {id,sourceInstanceId,receiverInstanceId,getState,pause,resume,stop}. getLiveReceiver returns the current handle, or undefined. getState returns an independent small snapshot {source:{id,sourceInstanceId},receiverInstanceId,transport:'http-poll',status:'running'|'paused'|'stopped',loading,intervalMs,lastError,dataRevision}. pause/resume/stop return Promise
Protocol defaults to gis-live-v1; only http-poll transport is implemented here. Unknown fields/protocols/transports yield INVALID_ARGUMENT. URLs are absolute HTTP/HTTPS, at most4096bytes, with no embedded user/password. intervalMs defaults to2000 and accepts500..60000ms, measured from prior completion; requests for one source never overlap. Requests use no-store. Browser request transformations can supply authorization; events/errors never echo URL, tokens or response bodies. Each source has one active/paused receiver; each map allows8, sharing8 download slots with ordinary sources. Receiver options/errors and protocol history count toward source residency budgets. Existing8MiB response,4096points/32fields and related limits apply.
Pause cancels in-flight I/O while retaining data/protocol; resume requests immediately. Stop cancels, releases the active quota and retains final data. Manual applyLiveUpdate conflicts while a receiver is active or paused. Ownership belongs to the map/source: a one-shot script ending, session exit or runner closing does not stop it. Use stop/removeSource/map destruction; remove dependent layers before deleting a source. This is separate from subsequent scene ownership.
Network/schema/continuity/cluster/display failure keeps prior data/protocol, records lastError and retries at the same interval. A continuity error requires the service to supply a full snapshot; the receiver never invents missing deltas. Replays do not advance dataRevision/protocolRevision or rebuild cluster identity, but HTTP completion still emits sourcedata. A completion is not necessarily a data change. Pause/stop emit sourcedataabort; connection/resume/next poll emit sourcedataloading; success emits sourcedata; failure emits error. Historical events contain optional immutable nested sqsLiveReceiver/sqsLive, without URLs. Stale generations and callbacks after destruction cannot write.
Browser capability: map.capabilities.liveHttpPolling. Native flag: SQSM_MAP_LIVE_HTTP (268435456). ABI v1 adds no function. Source JSON methods: sqs.connectLive/getLiveReceiver/liveState/pauseLive/resumeLive/stopLive. Connect/lookup take SourceIdentity (connect also takes options); receiver state/control take {id,sourceInstanceId,receiverInstanceId}. C connect/query return state DTO or null; controls return {changed,state}. Keep pumping resource requests/events and honor state.resources.repaintAfterMs. Metadata format:'gis-live-v1',cache:'no-store' uses the existing response channel and generation cancellation. The core contains no HTTP library/background transport. C hosts own deadlines, streaming8MiB budgets, concurrency, cancellation, cache and submission on the map creation thread.
Users provide layer/button UI. The complete HTML/CSS below includes all five handlers, credits, events and pagehide destruction. Enter your reachable endpoint and serve beside the matched SDK. Download complete HTML and portable acceptance script. Acceptance uses a loopback3131 fixture; start fixture.mjs from the repository tools directory to reproduce. It is not a public data service.
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>SqsMap live HTTP</title>
<style>body{margin:0;font:16px system-ui}#map{height:70vh}form{display:flex;flex-wrap:wrap;gap:.5rem;padding:1rem}input{flex:1;min-width:16rem}button,input{font:inherit;padding:.4rem}pre,footer{padding:0 1rem;white-space:pre-wrap}</style>
<div id="map"></div><form id="tools"><input id="url" type="url" required placeholder="Your gis-live-v1 HTTP endpoint"><button id="connect">Connect</button><button type="button" id="pause">Pause</button><button type="button" id="resume">Resume</button><button type="button" id="stop">Stop</button><button type="button" id="freeze">Freeze snapshot</button></form><pre id="status">Enter your HTTP endpoint.</pre><footer id="credits"></footer>
<script type="module">
import {MapView} from './dist/index.js';
const status=document.querySelector('#status');let map,source,receiver;const offs=[];
async function act(fn){try{await fn();}catch(error){status.textContent=String(error);}}
try{
map=await MapView.create(document.querySelector('#map'),{worker:false});if(!map.capabilities.liveHttpPolling)throw Error('Matched live HTTP SDK/WASM required');
map.jumpTo({center:[0,0],zoom:12});map.addSource('positions',{type:'geojson',data:{type:'FeatureCollection',features:[]},sqsLive:{fields:{n:'number'},allowDelta:true},attribution:'Live positions supplied by the endpoint owner'});map.addLayer({id:'positions',type:'circle',source:'positions',paint:{'circle-radius':8,'circle-color':'#ff0000'}});await map.flush();source=await map.getSource('positions');
for(const type of ['sourcedataloading','sourcedata','sourcedataabort','error'])offs.push(map.on(type,event=>{if(event.sourceId==='positions')status.textContent=JSON.stringify({type,protocol:event.sqsLive,receiver:event.sqsLiveReceiver},null,2);}));
offs.push(map.on('sqs.attributionschange',event=>{document.querySelector('#credits').textContent=event.attributions.text;}));document.querySelector('#credits').textContent=(await map.getAttributions()).text;
document.querySelector('#tools').onsubmit=event=>{event.preventDefault();act(async()=>{if(receiver&&(await receiver.getState()).status!=='stopped')await receiver.stop();receiver=await source.sqs.connectLive({transport:{type:'http-poll',url:document.querySelector('#url').value,intervalMs:1000}});});};
document.querySelector('#pause').onclick=()=>act(async()=>{if(!receiver)throw Error('Connect first.');await receiver.pause();});
document.querySelector('#resume').onclick=()=>act(async()=>{if(!receiver)throw Error('Connect first.');await receiver.resume();});
document.querySelector('#stop').onclick=()=>act(async()=>{if(!receiver)throw Error('Connect first.');await receiver.stop();});
document.querySelector('#freeze').onclick=()=>act(async()=>{status.textContent=JSON.stringify(await source.sqs.freezeLiveSnapshot(),null,2);});
window.addEventListener('pagehide',()=>{offs.forEach(off=>off());map.destroy();},{once:true});
}catch(error){status.textContent=String(error);offs.forEach(off=>off());map?.destroy();}
</script></html>
The identical portable script is checked with retained native QuickJS+C pumping, actual desktop ScriptService+HTTP transport, and browser main/strict Worker. Evidence/limits live in tools/live-http-contract. Linux native uses software Vulkan and browser Gl. The user verifies Windows/macOS elsewhere; mobile devices, hardware WebGPU, formal publication and remote deployment remain pending.
Shared scenes and receiver ownership provides draft/start/pause/resume/stop and historical events; static GeoJSON ownership is available in static scenes; playback, tracks and mobile acceptance continue separately.
Static scene resources and layer visibility covers same-source layers, draft hiding, controls, queries/credits and complete HTML.