GeoJSON URL sources
Shared sources accept in-memory GeoJSON and absolute HTTP/HTTPS URLs. Application scripts, browser scripts and retained native-library sessions use the same addSource, getSource and setData methods. Registering a source does not create a display layer or layer-management UI.
Script
Replace DATA_URL with your endpoint. Browser cross-origin endpoints must support CORS. Loading adds no separate authorization dialog. Native hosts must drive the resource queue below; one-shot native scripts cannot wait for events.
// @gis-api 0.5-session
// @permissions ["project.read", "map.write"]
import { map } from 'sqsmap';
const DATA_URL = 'https://example.com/points.geojson';
const subscriptions = [];
const loaded = new Promise((resolve, reject) => {
function finish(event) {
if (event.sourceId !== 'points') return;
for (const subscription of subscriptions) subscription.unsubscribe();
if (event.type === 'sourcedata' && event.isSourceLoaded) resolve(event);
else reject(Object.assign(new Error(event.error?.message ?? 'Load cancelled'), {
code: event.error?.code ?? 'CANCELLED'
}));
}
for (const type of ['sourcedata', 'sourcedataabort', 'error']) {
subscriptions.push(map.on(type, finish));
}
});
map.addSource('points', { type: 'geojson', data: DATA_URL });
map.addLayer({ id: 'points', type: 'circle', source: 'points',
paint: { 'circle-radius': 8, 'circle-color': '#2563eb' } });
await loaded;
await map.sqs.flush({ render: true });
console.log(await map.sqs.getSourceInfo('points'));
Refresh with await (await map.getSource('points')).setData(DATA_URL). Its Promise confirms only this update's application, not network readiness. Subscribe before updating so fast responses cannot be missed. Remove referencing layers before removing the source.
Current state
map.sqs.getSourceInfo(id) returns a current snapshot, or undefined when absent. The browser SDK uses MapView.getSourceInfo(id). It includes source identity, data/request revisions, feature count and bounds, plus:
| Field | Meaning |
|---|---|
| loading | A current request has not terminated |
| loaded | Data for the current request loaded successfully |
| hasData | Usable data exists, including previous data retained after a failed refresh |
| loadError | Last load failure as {code,message}, or null after success |
An initial URL source has data revision 0; its first successful response produces 1. Failed refreshes preserve previous geometry, data revision and feature state. loaded=false and hasData=true can both be true. Invalid JSON/geometry produces INVALID_ARGUMENT; HTTP failure/timeout produces IO_ERROR; exhausted budgets produce RESOURCE_LIMIT; cancellation produces CANCELLED. Never infer codes from prose. updateData returns CONFLICT during loading to prevent a late response overwriting incremental edits.
Loading events
Each sourcedataloading terminates with sourcedata, sourcedataabort or error. Replacement reports the old request's abort before the new request's loading. Immutable notices contain sourceId, sourceInstanceId, requestRevision, dataRevision, isSourceLoaded, loading, hasData and error snapshots, with dataType='source', sourceDataType='content'. Nested errors are frozen. Notices contain no GeoJSON, URL or credentials.
The public vocabulary and lifecycle follow MapLibre GL JS v6.13.0's event definitions, independently implemented by SqsMap. This stage covers shared GeoJSON content only. Tile/style-source lifecycle, idle and layer-filtered subscriptions remain later tasks.
Native resource host
Check sqsm_map_runtime_flags() & SQSM_MAP_GEOJSON_URL_SOURCES, bit value 1024. Use existing sqsm_map_resource_requests_json and sqsm_map_resource_response calls. Source requests have generation='source:<number>', id=0, resource.resourceType='Source'. Immediately abort owned I/O for cancel:true. Failure responses may include errorCode and error; otherwise return bytes. Obsolete, duplicate or undelivered responses return accepted=0. Free every output allocation and retain no borrowed pointer.
Responses are limited to 8 MiB. Browser and desktop hosts each allow eight source download jobs, with a default 30-second timeout. URLs are limited to 4096 bytes and must not embed credentials. The core performs no HTTP; native hosts own downloads, cancellation and destruction. Mobile shells can connect the same API; device acceptance remains separate.
The identical portable acceptance input uses this repository's owned loopback fixture to verify real loading, retained state after failure, cancellation and rendered-feature queries. Its test URL is only for acceptance; configure your own endpoint in user scripts.
For refreshes and re-registration, match sourceInstanceId and requestRevision; a historical notice does not replace current source state.