Skip to main content

Browser custom protocols

The standalone browser SDK exposes addProtocol(name, handler) and removeProtocol(name), following the call shape of MapLibre addProtocol. SqsMap uses its own engine and implementation. This implemented callback subset does not establish general MapLibre plugin compatibility.

Minimal usage

import { MapView, ResourceType, addProtocol, removeProtocol } from '@sqsmap/core';

const bytes = new Uint8Array(/* Your valid encoded PNG bytes */);
addProtocol('memory', async (params, controller) => {
  controller.signal.throwIfAborted();
  if (params.url !== 'memory://images/icon.png') throw new Error('Unknown image');
  return { data: bytes };
});
const map = await MapView.create(document.querySelector('#map'), {
  worker: false,
  transformRequest: (url, type) =>
    url === 'https://assets.example/icon.png' && type === ResourceType.Image
      ? { url: 'memory://images/icon.png' } : undefined,
});
const image = await map.loadImage('https://assets.example/icon.png');
map.addImage('icon', image.data);
await map.flush();
// A corresponding symbol layer is needed to display the icon.
// On page teardown: map.destroy(); removeProtocol('memory');

The complete HTML/CSS/JavaScript example includes a valid embedded PNG, actual image decoding, and all register/remove/reload/destroy button handlers. Download or copy it directly. It uses no online basemap or test keys; the browser must initialize WebGPU/WebGL2.

URLs and platform boundaries

13.6b extends shared planning and vector/raster/raster-dem tile templates to real custom-protocol addresses. Style URL, TileJSON url, GeoJSON and media URL entries retain HTTP(S). The transformRequest approach below remains compatible; see shared custom planning for direct tile URLs. Relative resource URLs resolve against the original HTTP(S) identity. Registrations are local to each JavaScript realm, with at most 16 names of 1–32 lowercase characters, starting with a letter and optionally containing digits, plus, dot or hyphen. Reserved HTTP, WebSocket, local and executable schemes cannot be replaced.

Callbacks belong to browser host code, rather than the common map script facade. Desktop, native C/QuickJS and mobile applications do not accept JavaScript protocol registrations. Cross-platform scripts continue to use the serializable resource policy.

A main-thread transformRequest selects main-thread rendering by default. Combining an explicit strict createWorker with function-valued request options rejects with CAPABILITY_UNAVAILABLE. Main-thread registrations are not automatically forwarded to Workers; this example does not demonstrate Worker forwarding.

Responses, cancellation and failures

Handlers receive captured parameters containing the normalized URL, expected decoder type, headers and abort signal. The second argument is this request's AbortController. Return Promise<{ data }> with an ArrayBuffer, the exact Uint8Array view, or text. Text budgets count UTF-8 bytes; accepted results are copied. JSON objects, DOM images, ImageBitmap, streams and additional response fields such as cacheControl/expires are rejected.

Callbacks share map concurrency, total/attempt deadlines and byte budgets. Resource replacement, layer removal, caller cancellation or map destruction signals the handler and rejects the wait. Pass this signal to any fetch operation. User code ignoring cancellation may keep running, but late results never enter the map. Memory allocated inside arbitrary callbacks remains the caller's responsibility.

Registering the same name replaces handlers for subsequent attempts. Removing an absent valid name is idempotent. Started requests keep their handler/controller and are not cancelled merely by unregistering; map destruction still cancels them. Callback failure or timeout does not automatically repeat user code or continue to HTTP fallback candidates. Automatic API tokens are never injected into custom schemes. Authorization, caching, HTTP error handling, CORS and retries inside the callback belong to the host.

Verification scope

The real Rust/WASM planner and browser transport verify registration limits, UTF-8 budgets, views, capture, cancellation, deadlines and late results. An actual software GL map verifies PNG decoding, repeat loads, remove/restore and destruction. Existing HTTP transport regressions remain covered. Local evidence does not substitute for public services, hardware, mobile devices or formal SDK release acceptance.

13.6b now accepts actual custom addresses in shared planning and tiled templates; other URL entry points retain HTTP(S). See shared planning.