Script events and persistent sessions
Contract 0.5-session connects persistent browser Worker and native QuickJS sessions while retaining existing gis scripts. Linux native GPU and browser WebGL maps have run the same event script. Windows/macOS validation is assigned to another machine. The mobile contract compiles, but the actual mobile script host remains unconnected.
Keep listeners active
Scripts close after top-level completion by default. export const sessionMode = 'persistent' makes completion mean initialization is ready; listeners remain active. The website Examples console displays a listening state and supports stopping or rerunning. Changing examples cleans up the previous session.
// @gis-api 0.5-session
// @permissions ["project.read"]
import { map } from 'sqsmap';
import { map as legacy } from 'gis';
export const sessionMode = 'persistent';
await map.sqs.ready();
const changed = async (event) => {
const state = await legacy.state();
// Use event.camera / state to update application-owned UI.
};
const subscription = map.on('sqs.viewchange', changed);
// subscription.unsubscribe(); // Idempotent.
// map.off('sqs.viewchange', changed); // Returns map.
map.once('sqs.viewchange', event => { /* Callback form returns map. */ });
map.once('sqs.viewchange').then(event => { /* Promise form. */ });
export default { initialized: true, events: map.sqs.events() };
The sqsmap module provides common camera, GeoJSON source, style-layer, query, feature-state and event APIs. See the shared map reference for the current scope. Extended GIS operations remain available from gis. Legacy on/once keep returning Subscription. New on returns Subscription; off and callback-based once return map; once without a callback returns a Promise. Registering the same function for the same listener category does not duplicate it. Unsubscribed listeners are excluded from subsequent delivery.
Download the shared acceptance script. Complete declarations are in the web types.
Current event catalog
| Event | Native host | Web host | Payload |
|---|---|---|---|
error | Connected | Connected | error.code/message |
sqs.viewchange | Connected | Connected | Existing camera state; precise camera semantics remain pending |
sqs.layerschange | Connected | Connected | kind: add/remove/move/update |
sqs.taskprogress | Connected | Unconnected | operationId/progress; subscribe according to actual availability |
New load/remove | First load and actual map removal connected | First load and actual map removal connected | No late load replay; inspect firstLoadCompleted |
| move/zoom/rotate start, change and end | Common planar commands and per-frame changes connected | Common planar commands connected | Historical camera snapshots; full animation/gesture semantics remain pending |
| sourcedataloading/sourcedata/sourcedataabort | Common GeoJSON connected | Common GeoJSON connected | Source identity and historical loading state; failures use error |
| click/dblclick/mousedown/mouseup/mousemove/contextmenu | Library host input and desktop map viewport connected | SDK canvas input connected | Common planar hits; single-layer and layer-array delegation |
| pitch/style/render/idle, touch/keyboard families | Not fully connected | Not fully connected | Check capabilities; ordinary redraws do not establish readiness |
map.sqs.events() returns the events actually forwarded by the host. Known but unconnected events, and overloads for events that do not support layer delegation, return CAPABILITY_UNAVAILABLE; unknown names or invalid handlers return INVALID_ARGUMENT. Events carry type, the receiving map as target, stable mapInstanceId, and increasing sequence. An attached session does not imply loaded resources or rendering idle.
Cleanup and budgets
Stopping, rerunning, and host shutdown release subscriptions, timers, waits, and unapplied operations. Ordinary applied map content remains, including after callback failure. Synchronous/asynchronous callback exceptions and unhandled rejections terminate the session. Hosts stop scripts before destroying a map; native hosts close ScriptService on exit. Complete map lifecycle integration remains a subsequent task.
Initialization defaults to 60 seconds. Persistent sessions have no fixed total lifetime, but allow 32 listeners, 32 waits, and 32 concurrent calls. Calls and waits each permit 256 starts per 60-second window. Event queues hold 128 items, each at most 64 KiB. Views and progress for one operation may coalesce; discrete events stay ordered and overflow fails explicitly. Native continuous execution is limited to 2 seconds; a foreground web Worker without a heartbeat for about 5 seconds is terminated. Background throttling is not treated as failure.
Native TaskInfo.initialized becomes true while state remains running, with the initialization summary retained. Inspect the terminal state after cancellation. Web ScriptRunner.run returns the initialization summary while runner.running remains true. runner.closed reports actual closure; receive later errors through onSessionError or closed. Default one-shot tasks remain available.
See existing scripts and map script design.
Top-level asynchronous errors
Native QuickJS preserves the error code, registered API guidance and safe argument path when a top-level await rejects because of invalid API arguments. A generic unhandled-rejection message no longer replaces that guidance. Actual argument values and arbitrary exception messages remain redacted; detached unhandled rejections still terminate the session. The compatibility gis module now declares map.setStyle with an Operation<void> return. The common sqsmap module keeps the map-returning chainable form.
Standalone SDK canonical source/layer names, aliases and observer policy: event names.
Layer enter and leave events use the same visible-feature snapshots.
Actual frames and idle: reads do not draw; subscribe before changing content, and explicit render does not imply resource readiness.