Skip to main content

Script events and persistent sessions

Explicit persistent scripts, map events, cleanup, and current host coverage.

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

EventNative hostWeb hostPayload
errorConnectedConnectederror.code/message
sqs.viewchangeConnectedConnectedExisting camera state; precise camera semantics remain pending
sqs.layerschangeConnectedConnectedkind: add/remove/move/update
sqs.taskprogressConnectedUnconnectedoperationId/progress; subscribe according to actual availability
New load/removeFirst load and actual map removal connectedFirst load and actual map removal connectedNo late load replay; inspect firstLoadCompleted
move/zoom/rotate start, change and endCommon planar commands and per-frame changes connectedCommon planar commands connectedHistorical camera snapshots; full animation/gesture semantics remain pending
sourcedataloading/sourcedata/sourcedataabortCommon GeoJSON connectedCommon GeoJSON connectedSource identity and historical loading state; failures use error
click/dblclick/mousedown/mouseup/mousemove/contextmenuLibrary host input and desktop map viewport connectedSDK canvas input connectedCommon planar hits; single-layer and layer-array delegation
pitch/style/render/idle, touch/keyboard familiesNot fully connectedNot fully connectedCheck 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.