Custom protocols in desktop and web scripts
Import addProtocol and removeProtocol from sqsmap. Await registration before loading that scheme. You supply the application buttons and panels.
import {map, addProtocol, removeProtocol} from 'sqsmap';
const feature = {type: 'Feature', id: 7, properties: {},
geometry: {type: 'Point', coordinates: [116.4, 39.9]}};
await addProtocol('localdata', async (request, controller) => {
controller.signal.throwIfAborted();
// This example contains ASCII only; encode general text as UTF-8.
const text = JSON.stringify(feature);
return {data: Uint8Array.from(text, char => char.charCodeAt(0))};
});
const loaded = new Promise(resolve => {
const sub = map.on('sourcedata', event => {
if (event.sourceId === 'point' && event.isSourceLoaded) {sub.unsubscribe(); resolve();}
});
});
map.addSource('point', {type: 'geojson', data: 'localdata://point'});
map.addLayer({id: 'point-circle', type: 'circle', source: 'point',
paint: {'circle-color': 'blue', 'circle-radius': 10}});
await map.sqs.flush();
await loaded;
await map.sqs.flush({render: true});
await removeProtocol('localdata');
Read-only request fields are url, resourceType, maxBytes, and method: 'GET'. The controller exposes a read-only signal with aborted, throwIfAborted, addEventListener('abort', fn), and removeEventListener. Results accept only {data: ArrayBuffer | Uint8Array}; the exact view is copied before transfer. Strings, DOM images and cache metadata are outside the common script result contract. Browser fetch, TextEncoder and timers remain unavailable in the portable script environment; use host APIs.
Each session allows16 schemes,8 actually running callbacks and8 abort listeners per request. Responses are limited to8MiB and the authoritative request budget; replies awaiting host acceptance total at most16MiB/32 replies. Cancelled but unsettled callback promises still consume running slots. Resource deadlines, source removal, replacement, unregistering and stopping cancel affected requests. Ownership conflicts fail explicitly; cleanup cannot delete a handler subsequently replaced by an external SDK caller. Registration failures enter the same confirmation history as other map writes; inspect and recover using the observed failure watermark described in the common camera guide.
(await map.sqs.getCapabilities()).sharedScriptProtocols === true reports a connected host. Both map main-thread and rendering-Worker backends work with the script Worker. Classic raw SDK named registrations remain local to their JavaScript realm. Raw SDK callers can create an independent scope routed to a rendering Worker:
const protocols = view.sqs.resources.createProtocolScope();
await protocols.addProtocol('assetdata', async (request, controller) => {
controller.signal.throwIfAborted();
return {data: new TextEncoder().encode(JSON.stringify({type: 'Feature', properties: {}, geometry: {type: 'Point', coordinates: [116.4, 39.9]}}))};
});
await protocols.removeProtocol('assetdata');
protocols.close();
A map allows32 scopes. Each scope owns its registrations, accepts encoded bytes or text up to8MiB, and releases only its own handlers when closed or when the map is destroyed. Classic SDK addProtocol/removeProtocol retain their original realm-local replacement behavior.
The desktop GIS host connects the same named functions to native resource jobs for shared sources, style documents, tiles, sprites, glyphs and loadImage. Closures remain in QuickJS; ArrayBuffer bytes are copied into Rust-owned buffers. A map allows16 schemes with ownership isolation. Native resource threads queue at most8 requests and allow2 concurrent binary-response consumers with a16MiB response bound. Replacement, removal, task completion and resource cancellation release only affected owned requests. Unconnected custom hosts and mobile GIS application hosts still report CAPABILITY_UNAVAILABLE. Standalone native retained QuickJS has the named functions; see native protocols. Windows/macOS external verification, devices and formal releases remain separate tasks.
The same script passes8 checks on main-thread/strict rendering Worker×DPR1/2, including actual blue pixels/feature identity, request metadata, deadlines and source-removal abort delivery: script, complete HTML fixture.