#ifndef SQS_MAP_PUBLIC_API_H
#define SQS_MAP_PUBLIC_API_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif

/* High-level map ABI v1. Existing low-level sqsm_engine/terrain exports remain
 * available; this header describes the new public map API only.
 * All lengths are bytes. JSON is UTF-8 and is NOT null-terminated.
 * Map operations run on the thread that created the map. Returned allocations
 * may be read/freed on another thread with application synchronization.
 */
typedef uint64_t sqsm_map_t;
typedef struct sqsm_map_bytes {
    const uint8_t *data;
    uint64_t len;
    uint64_t allocation;
} sqsm_map_bytes_t;

enum sqsm_map_status {
    SQSM_MAP_OK = 0,
    SQSM_MAP_INVALID_ARGUMENT = 1,
    SQSM_MAP_STALE_HANDLE = 2,
    SQSM_MAP_CONFLICT = 3,
    SQSM_MAP_RESOURCE_LIMIT = 4,
    SQSM_MAP_ENGINE_ERROR = 5,
    SQSM_MAP_NOT_FOUND = 6,
    SQSM_MAP_CAPABILITY_UNAVAILABLE = 7,
    SQSM_MAP_CANCELLED = 8
};
enum sqsm_map_runtime_flag { SQSM_MAP_UNWIND_SESSION = 1u, SQSM_MAP_SCRIPT = 2u, SQSM_MAP_SCRIPT_SESSIONS = 4u, SQSM_MAP_COMMAND_BARRIERS = 8u, SQSM_MAP_PLANAR_CAMERA = 16u, SQSM_MAP_HOST_RESOURCES = 32u, SQSM_MAP_GEOJSON_SOURCES = 64u, SQSM_MAP_GEOJSON_STYLE_LAYERS = 128u, SQSM_MAP_SCALE_TOOLS = 256u, SQSM_MAP_CAMERA_LIFECYCLE = 512u, SQSM_MAP_GEOJSON_URL_SOURCES = 1024u, SQSM_MAP_CAMERA_ANIMATIONS = 2048u, SQSM_MAP_POINTER_INPUT = 4096u, SQSM_MAP_ATTRIBUTION_QUERIES = 8192u, SQSM_MAP_ATTRIBUTION_EVENTS = 16384u, SQSM_MAP_GESTURE_POLICY = 32768u, SQSM_MAP_GESTURE_EVENTS = 65536u, SQSM_MAP_GESTURE_ACTIVITY = 131072, SQSM_MAP_KEYBOARD_NAVIGATION = 262144u, SQSM_MAP_KEYBOARD_ROTATION = 524288u, SQSM_MAP_IMAGES = 1048576u, SQSM_MAP_MISSING_IMAGES = 2097152u, SQSM_MAP_LOAD_IMAGE = 4194304u, SQSM_MAP_GLYPH_SERVICE = 8388608u, SQSM_MAP_CLUSTERING = 16777216u, SQSM_MAP_CLUSTER_REDUCERS = 33554432u, SQSM_MAP_CLUSTER_SCALARS = 67108864u, SQSM_MAP_LIVE_UPDATES = 134217728u, SQSM_MAP_LIVE_HTTP = 268435456u, SQSM_MAP_LIVE_WEBSOCKET = 536870912u, SQSM_MAP_RESOURCE_POLICY = 1073741824u };

#define SQSM_MAP_DISPLAY_DENSITY UINT32_C(2147483648)

uint32_t sqsm_map_api_version(void);
uint32_t sqsm_map_runtime_flags(void);
/* 0: pure map build; 1: optional native one-shot script ABI. */
uint32_t sqsm_map_script_api_version(void);
/* UTF-8 ES module, max 128 KiB; JSON output, max 64 KiB.
 * Same owner thread and sqsm_map_bytes_free rules as other map APIs.
 * Requires script feature; pure build returns status 7 (CAPABILITY_UNAVAILABLE).
 * A failed script does not roll back applied map changes. */
int32_t sqsm_map_script_run_json(uint64_t map, const uint8_t *source, uint64_t len, sqsm_map_bytes_t *out);
/* Retained script session ABI v1 (0 without script feature).
 * Owner thread only. Separate event subscription from map_poll_events.
 * start evaluates synchronous code; pump advances promises/host calls/events.
 * max_events: 1..32. Each start/pump has a 2s JS budget; native calls cannot be
 * preempted. state reads cached metadata only. Stop is idempotent until release.
 * Terminal handles (including cancelled by map_destroy) remain inspectable;
 * release each handle once. Max 16 retained handles/process, 4/map.
 * Failure clears outputs but does not roll back callbacks or map changes.
 * All JSON buffers follow map_bytes_free ownership rules.
 */
typedef uint64_t sqsm_map_script_session_t;
uint32_t sqsm_map_script_session_api_version(void);
int32_t sqsm_map_script_session_start(sqsm_map_t map, const uint8_t *source, uint64_t len, sqsm_map_script_session_t *out);
int32_t sqsm_map_script_session_pump_json(sqsm_map_script_session_t session, uint32_t max_events, sqsm_map_bytes_t *out);
int32_t sqsm_map_script_session_state_json(sqsm_map_script_session_t session, sqsm_map_bytes_t *out);
int32_t sqsm_map_script_session_stop(sqsm_map_script_session_t session);
int32_t sqsm_map_script_session_release(sqsm_map_script_session_t session);
/* Thread-local message, valid until the next map API call. Do not free it. */
const char *sqsm_map_last_error(void);
/* Public initialization needs no private unlock key. out is zero on failure.
 * width/height: physical RGBA pixels, each in 1..4096. Creates an empty 2D WGS84
 * offscreen map. Use release-capi for native distribution (panic unwinding).
 */
int32_t sqsm_map_create(uint32_t width, uint32_t height, sqsm_map_t *out);
/* Destruction dispatches one final remove notice to retained JavaScript sessions.
 * New host calls reject CANCELLED. Final callbacks have a 2-second/4096-job budget;
 * callback errors/timeouts remain inspectable on the retained session and do not prevent map release.
 * Stopping/releasing a script session alone does not dispatch map removal. */
int32_t sqsm_map_destroy(sqsm_map_t map);
/* Legacy resize uses physical/input dimensions together and restores pixelRatio1. */
int32_t sqsm_map_resize(sqsm_map_t map, uint32_t width, uint32_t height);
/* Bit31 (0x80000000) DISPLAY_DENSITY. Logical/input dimensions and pixels per logical
 * pixel; ratio 0.125..16 (native f32 precision), rounded output edges each <=4096.
 * State width/height are physical output pixels; logicalWidth/logicalHeight and
 * pixelRatio describe input units. Existing create/resize calls retain DPR1.
 * Camera/project/query/pointer points and style widths remain logical pixels.
 * Invalid size/ratio rejects before visible mutation; owned old outputs survive.
 */
int32_t sqsm_map_set_viewport(sqsm_map_t map, uint32_t logical_width, uint32_t logical_height, double pixel_ratio);
/* Native renderer degrees, normalized to 0..360. Unified MapLibre camera and
 * projection APIs will be added separately; this is explicitly a native view.
 */
int32_t sqsm_map_set_native_bearing(sqsm_map_t map, double bearing);
/* Convenience WGS84 GeoJSON display, NOT the complete Style Source/Layer API.
 * Input copied/parsed before return; <=16MiB, <=50000 features, <=500000 points.
 */
int32_t sqsm_map_add_geojson(sqsm_map_t map, const uint8_t *data, uint64_t len, uint64_t *out_layer);
int32_t sqsm_map_remove_layer(sqsm_map_t map, uint64_t layer);
/* Each output must be unused/previously freed; failure clears its fields.
 * Outputs remain valid across resize, subsequent calls and map destruction.
 */
/* State includes lifecycle: initialized, firstLoadCompleted, actual frameSequence, idle and work:
 * pendingResources/pendingSources/animating/pendingRender/failed.
 * Camera JSON {method:"sqs.lifecycleState",args:[]} returns the same read-only snapshot;
 * {method:"loaded",args:[]} requires an actual frame, settled work and no terminal failure.
 * Reads never draw or sample motion. render/idle are historical successful-frame notices;
 * idle is a busy-to-settled transition, not repeated for unchanged redraws.
 * First successful complete content frame emits sqs.load once (render, sqs.load, idle);
 * animations need not end for load. Legacy constructor load remains separate.
 * Persistent JavaScript maps sqs.load to standard load, without replay on attachment.
 * Foreign pixel/receipt allocation failure leaves successful frame/load/idle uncommitted. */
int32_t sqsm_map_state_json(sqsm_map_t map, sqsm_map_bytes_t *out);
/* Synchronous GPU readback; tightly packed RGBA8, width*height*4 bytes. */
int32_t sqsm_map_render_rgba(sqsm_map_t map, sqsm_map_bytes_t *out);
/* Confirm captured submitted/applied command watermarks. since is a previously
 * observed safe-integer watermark; 0 observes all retained failures. flags 0:
 * applied; flags 1: synchronously confirm a newly rendered RGBA frame. No idle or
 * network-readiness promise. Historical command failures return ENGINE_ERROR;
 * last_error contains JSON with commandSequence and submittedSequence. Failure
 * history is bounded to 256; overflow requires a new map. Output/free as above.
 */
/* Runtime flags bit 4 (16): validated planar camera command envelope, max 64 KiB.
 * Reads return JSON data, writes return JSON null and join the flush journal.
 * Bit 8 (256), SCALE_TOOLS: getMinZoom/getMaxZoom and sqs.scaleAt. The latter
 * takes zero args or [{point:[x,y],maxWidth:80}], in CSS/logical viewport pixels.
 * Returns local horizontal spherical ground metersPerPixel, nice metric distance
 * and width. Read-only, planar only; not terrain/ellipsoid surveying. */
/* Runtime flags bit 5 (32): host-driven URL basemap resources. No HTTP in core.
 * setStyle: {"style":"https://..." or version-8 object,"options":{"diff":false}},
 * null clears. Inline sources/layers use shared validators; 4MiB style plus64KiB envelope.
 * Poll 1..32 requests; successful output allocation consumes them. The host owns
 * deadlines, streaming maxBytes limits, credentials, cancellation and HTTP cache.
 * Response metadata: {"generation":"1","id":0}, or add nonempty error (<=1024 B).
 * Data is copied (max 64 MiB; smaller per-request limit still applies). error and
 * nonempty data are mutually exclusive. accepted=0: stale/unknown/already answered.
 * Each generation is scoped to this map. Cancel old I/O on generation change or
 * destruction; host callbacks must return on the map creation thread. Outputs
 * follow the existing independent allocation/free ownership rules.
 */
int32_t sqsm_map_set_style_json(uint64_t handle, const uint8_t *json, uint64_t len);
/* Snapshot of the current validated style, including editable common layers.
 * Unloaded style documents return CAPABILITY_UNAVAILABLE. Same allocation lifetime as state_json. */
int32_t sqsm_map_get_style_json(sqsm_map_t map, sqsm_map_bytes_t *out);
/* Additive host policy API (ABI 1), JSON {method,args}. configure replaces all
 * settings; getConfiguration reads; plan computes an HTTP(S) request schedule.
 * Input <=512KiB, output <=1MiB. Allocate output before committing a configuration.
 * Every non-cancel HTTP request now includes requestPlan (version 1): urls, method,
 * resourceType, maxBytes, maxConcurrentRequests, resourceTimeoutMs, attemptTimeoutMs,
 * retries, retryDelayMs, retryOn (network, attemptTimeout, httpStatuses, serverErrors),
 * optional cache. The host must enforce those bounds,
 * cancellation and final-origin authorization. The library does not execute HTTP.
 * Polled requestPlan.maxBytes records the core budget; the C response ceiling is
 * 64MiB. GeoJSON remains 8MiB, encoded images 4MiB; MP4/H.264 video is at most64MiB.
 * Already delivered requests retain their plan. WebSocket requests have no HTTP plan.
 * Free output with sqsm_map_bytes_free. Invalid writes preserve configuration. */
int32_t sqsm_map_resource_policy_json(sqsm_map_t map, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);
int32_t sqsm_map_resource_requests_json(uint64_t handle, uint32_t limit, sqsm_map_bytes_t *out);
int32_t sqsm_map_resource_response(uint64_t handle, const uint8_t *json, uint64_t json_len, const uint8_t *data, uint64_t data_len, uint32_t *accepted);
/* Bit 12 POINTER_INPUT: host-owned planar/spherical pointer snapshots. JSON fields:
 * type (click/dblclick/mousedown/mouseup/mousemove/mouseenter/mouseleave/contextmenu), point {x,y},
 * optional layers (1..128 IDs), pointerType mouse/pen/touch, button 0..4,
 * buttons 0..31 and altKey/ctrlKey/metaKey/shiftKey booleans. Defaults: mouse,
 * button/buttons 0, modifiers false. Logical viewport pixels; no DOM event.
 * Only mouseleave accepts finite points outside the viewport; lngLat is null and features empty.
 * Spherical sky and planar points without a ground location (outside the world, pitched
 * rays without a ground hit) also have lngLat:null. Other input points must lie inside the viewport.
 * Input <=8 KiB, snapshot <=64 KiB. Output: point/lngLat/features/cameraState/input.
 * Missing layer, invalid/unsupported input, queue/allocation pressure reject;
 * no silent truncation. Publishes type and pointerEvent through poll_events_json
 * only after successful allocation. No gesture, selection or command journal
 * mutation. Drain events before retry; release independent output once.
 * Not a touch gesture engine or a delegated script subscription capability.
 */
int32_t sqsm_map_pointer_json(uint64_t handle, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);
/* Read-only logical source credits; complete UTF-8 JSON <=64 KiB, independently owned.
 * Free with sqsm_map_bytes_free, even after map destruction. Outputs clear on failure.
 * Includes sources managed by this session; external host overlays must register their own metadata. */
int32_t sqsm_map_attributions_json(uint64_t handle, sqsm_map_bytes_t *out);
/* Bit 16 (65536) GESTURE_EVENTS: future-only sqs.gestureschange in poll_events_json
 * carries gestureEvent.gestures, a complete historical three-boolean policy.
 * Each successful changed policy emits once; idempotent/failed writes emit none.
 * Drain the 128-entry queue before retrying a rejected write. */
/* Six default navigation switches plus independent keyboardRotation/touchRotation options. Host injects actual input; script policy does not suppress pointer events. */
/* Bit 17 GESTURE_ACTIVITY: host reports recognized input, <=1KiB JSON.
 * {"handler":"dragPan"|"scrollZoom"|"doubleClickZoom"|"keyboard"|"touchZoomRotate"|"touchPitch","active":true|false}.
 * Output is {handler,active}; a late begin for a disabled handler acknowledges false.
 * No command journal/policy event. Allocate output before commit; output survives destruction.
 * Call end on release/cancel/focus loss. disable clears matching activity; enable never resumes.
 * .isActive queries use sqsm_map_gesture_json. Enabled policy is not physical activity. */
/* Shared key recognition, no camera mutation. 1 KiB strict JSON: key plus optional
 * shiftKey/ctrlKey/altKey/metaKey booleans. Result null means unhandled/disabled;
 * otherwise {type:"pan",offset:[x,y]}, {type:"zoom",delta:number}, or {type:"rotate",delta:degrees}.
 * keyboard.disableRotation disables all arrows but preserves zoom; Shift left/right rotates 15 degrees.
 * Shift up/down pitch remains unhandled until shared 3D keyboard navigation is connected.
 * Shell owns focus and applies the action via camera API; outputs are independently owned. */
int32_t sqsm_map_keyboard_plan_json(uint64_t map, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);
int32_t sqsm_map_gesture_input_json(uint64_t handle, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);
int32_t sqsm_map_gesture_json(uint64_t handle, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);
/* Manual editing of numeric layers from sqsm_map_add_geojson (2D only).
 * Request: {"method":"begin","layerId":id}, then {"method":"draw","geometry":...}.
 * apply/discard end the session; getData exports current WGS84 GeoJSON while active.
 * Coordinates: WGS84 [lng,lat]; screen points/radii: logical pixels.
 * Writes return JSON null; getters return JSON; always release out with sqsm_map_bytes_free.
 * A failed output allocation leaves writes unapplied. See the bilingual editing API guide. */
int32_t sqsm_map_edit_json(uint64_t handle, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);
int32_t sqsm_map_camera_json(uint64_t handle, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);
/* A rejected command retains its original status; last_error is a JSON envelope
 * with code, message, commandSequence and submittedSequence. since explicitly
 * excludes observed failures; acknowledgement never clears historical failures. */
int32_t sqsm_map_flush_json(sqsm_map_t map, uint64_t since, uint32_t flags, sqsm_map_bytes_t *out);
/* Bit 9 (512), CAMERA_LIFECYCLE: immediate planar movestart/move/moveend,
 * zoomstart/zoom/zoomend and rotatestart/rotate/rotateend. Start cameraState is
 * historical pre-update; later snapshots are applied. Not animation/idle. */
/* sqs.attributionschange carries attributionEvent.attributions (complete text/items).
 * The pump samples current logical credits; intermediate unpumped writes may coalesce.
 * Attribution budget failure emits error with attributionEvent.context=attributions;
 * recovery emits a change. Query initial credits separately; no subscription replay.
 * Nonblocking poll, returns JSON array (including []); consumes only after
 * successful allocation. At 128 queued events, changes reject RESOURCE_LIMIT
 * until the host polls; discrete events are never silently dropped.
 */
int32_t sqsm_map_poll_events_json(sqsm_map_t map, sqsm_map_bytes_t *out);
/* Free once using allocation, NOT data. 0 is a no-op. Old allocation IDs are
 * never reused, so a stale ID cannot free a newly allocated buffer.
 */
int32_t sqsm_map_bytes_free(uint64_t allocation);

/* Shared inline GeoJSON source registry; runtime flag bit 6.
 * setFeatureState/getFeatureState/removeFeatureState use args [{source,id},state/key?].
 * State is merged independently of dataRevision and drives shared paint expressions.
 * get returns a snapshot; remove supports one key, one feature or the whole source.
 * State/source/display mutation is atomic and subject to the bounded event queue.
 * Request: {"method":"addSource","args":["id",{"type":"geojson","data":...}]}.
 * Methods: addSource/getSource/removeSource/isSourceLoaded/setData/updateData/getData.
 * setData/updateData/getData use {"id":"...","sourceInstanceId":"..."} as args[0].
 * Returned JSON is owned and must be released with sqsm_map_bytes_free.
 * Allocation failure preserves source state; mutations join the map command journal.
 * IDs are not display layers. Inline WGS84 GeoJSON only; other source types report unavailable.
 * Envelope limit: 16 MiB + 64 KiB; source data limit: 16 MiB. Script queues retain their 64 KiB limit.
 */
/* Runtime flag SQSM_MAP_CLUSTERING: clustered GeoJSON Point sources. Options:
 * cluster, clusterRadius (0..512; default 50 CSS px per 512 tile), clusterMaxZoom
 * (rounded 0..23; default 17), clusterMinPoints (2..4096), clusterProperties
 * (up to 8 numeric map/reduce expressions). At most 4096 Mercator-valid Points.
 * SQSM_MAP_CLUSTER_SCALARS adds finite number/boolean/string statistics and
 * all/any/concat shorthands. Each string is at most 4096 UTF-8 bytes; each
 * mapping/working-level buffer is bounded to 8 MiB, separately from the 32 MiB index.
 * Arrays/objects/null statistics are rejected; custom reducers may change scalar type.
 * SQSM_MAP_CLUSTER_REDUCERS adds +,-,*,/,min,max and custom numeric reducers with
 * accumulated scoped to reduce; get reads configured child statistics.
 * Expressions: <=32 levels/1024 nodes/64 KiB; estimated evaluation <=8M nodes.
 * Each parent folds its child clusters in stable identity order.
 * getClusterOptions / setClusterOptions / getClusterChildren / getClusterLeaves /
 * getClusterExpansionZoom use bound source identity as args[0]. Children and zoom
 * take cluster_id; leaves additionally take limit (default 10, <=1000) / offset.
 * Synthetic feature.id is "sqs:cluster:<cluster_id>"; the numeric cluster_id remains
 * in properties. IDs expire after data/config rebuild; getData stays original.
 * Queries use current integer camera zoom, not raw unclustered rows. */
/* SQSM_MAP_LIVE_UPDATES: GeoJSON options sqsLive {fields,allowDelta:false} require
 * an empty FeatureCollection and no promoteId/generateId. Source methods
 * sqs.applyLiveUpdate(identity,frame), sqs.getLiveState(identity),
 * sqs.freezeLiveSnapshot(identity) share this channel, journal and atomic display commit.
 * gis-live-v1: snapshot/delta, decimal u128 sequence strings, <=4096 points/32 fields,
 * <=8MiB batch and snapshot output. Manual setData/updateData conflict on live sources.
 * Duplicate batches return applied:false without advancing data/protocol revisions.
 * This is batch ingestion; transport ownership and network receivers are separate. */
/* SQSM_MAP_LIVE_HTTP: sqs.connectLive(sourceIdentity,{protocol?:"gis-live-v1",
 * transport:{type:"http-poll",url,intervalMs?:2000}}) returns receiver state.
 * sqs.getLiveReceiver(sourceIdentity) returns state/null; sqs.liveState and
 * sqs.pauseLive/resumeLive/stopLive take {id,sourceInstanceId,receiverInstanceId}.
 * Each map allows 8 active/paused receivers, one per live source; interval 500..60000ms.
 * Core emits existing Source requests marked format:"gis-live-v1", cache:"no-store";
 * pump resource_requests/response on the map owner thread. No HTTP thread in core.
 * Pause/stop cancel pending generations, preserve data, and reject stale responses.
 * Live polling owns ingestion: manual applyLiveUpdate conflicts until stopped.
 * Replays preserve data revisions/index but HTTP completion may publish loading state.
 * State/events contain sqsLiveReceiver without URL/credentials. Map destruction ends ownership. */
/* SQSM_MAP_LIVE_WEBSOCKET: connectLive also accepts
 * transport:{type:"websocket",url,reconnectDelayMs?:2000}, WS/WSS without embedded
 * credentials. Delay 500..60000ms; intervalMs is invalid for sockets.
 * Source requests carry transport:"websocket" and format:"gis-live-v1". Acknowledge
 * once, submit successive text JSON batches with the same generation/id. Each fresh
 * connection requires snapshot first. Ready replays publish no data-change event.
 * State transport:"websocket", intervalMs:0, connection:connecting/open/retrying/
 * paused/stopped. Typed terminal errors end the generation and schedule reconnect.
 * Pause, stop, source removal and map destruction require closing the owned socket.
 * Hosts bound data queues to 8 frames/16MiB per map and 8MiB per message; overflow
 * terminates/resynchronizes, never coalesces delta frames. Up to 8 zero-payload
 * terminal records are separate. Core contains no socket client or network thread. */
/* Shared scene lifecycle (JSON envelope {method,args}; method create/get/list/getState/start/pause/
 * resume/stop/remove). Identity {id,sceneInstanceId}; draft creates no receiver I/O.
 * connectLive optional owner identity binds a receiver. Scene pause and manual pause
 * are independent; stop/remove close receivers but preserve source data. Scene event
 * sqs.scenechange carries an immutable historical scene snapshot, including sources.
 * getClock takes [sceneIdentity] and returns {id,sceneInstanceId,state,elapsedMs}.
 * Time uses the host monotonic clock, excludes pauses, includes host background gaps,
 * and survives script exit. It does not promise playback or frame completion.
 * attachSource/detachSource take [sceneIdentity,{id,sourceInstanceId}]. Static GeoJSON
 * ownership controls all referencing shared style layers: draft/stopped hides,
 * running/paused follows user layout/zoom; remove detaches, retains sources/layers,
 * and restores their ordinary visibility. No URL-loading suspension or individual
 * child-layer ownership. Explicit receiver/static owners must agree; both count
 * against 128 registrations. Map-owned playback uses the same channel below.
 * Returned bytes use sqsm_map_bytes_free. */
/* Map-owned route playback uses this same channel (no additional C exports):
 * animation.route [{id,source:{id,sourceInstanceId},target:{id,sourceInstanceId},
 *   duration?:ms,offsets?:ms[],loop?:bool,delay?:ms},{owner:{id,sceneInstanceId}}].
 * Target must be one static noncluster Point, explicitly attached to its scene;
 * source must be one static noncluster LineString. Duration and offsets are exclusive.
 * WGS84 Mercator interpolation takes the shortest dateline path and retains explicit
 * longitude world copies (source longitude absolute value <=1000000 degrees).
 * playback.get [id], playback.list [], playback.getState [playbackIdentity] are pure reads.
 * playback.play/pause/stop/remove [playbackIdentity], playback.seek [identity,timeMs].
 * Identity = {id,playbackInstanceId}; JSON capability sceneRoutePlayback true;
 * sceneLinePlayback and sceneTracks are also true. At most64 playback controllers per map;
 * the128-resource scene budget counts controllers, static sources and receivers.
 * Completion follows accepted target data/cache submission, not frame presentation.
 * Render or retained script pump advances host time. Poll public events to release pressure.
 * sqs.playbackchange envelopes carry playbackEvent {type,reason,playback}.
 * Owner stop cancels unfinished rounds; owner remove retires controllers but retains sources.
 * Failed output/cache preparation does not publish a candidate target or completion.
 * All JSON allocations keep the existing free/poll/destroy rules below. */
/* Shared planar line playback also uses this channel:
 * animation.line [{id,layer:{id,layerInstanceId},timing:{duration:ms,delay?:ms,
 *   loop?:bool,direction?:"forward"|"reverse"|"alternate",easing?:"linear"|"ease-in-out",
 *   fill?:"forwards"|"none"},effects:[{type:"flow"|"dash"|"reveal"|"arrows"|"glow"|"pattern",...}],
 *   tracks?:{color?:[{offset,value:"#RRGGBB"}],opacity?:[{offset,value}],widthScale?:[{offset,value}]},
 *   stagger?:bool,cap?:"butt"|"round",phaseField?:string,speedField?:string},{owner:sceneIdentity}].
 * Raw C JSON requires the explicit layer identity from getLayers. JS facades additionally
 * bind layer names. Source must be loaded, static, noncluster GeoJSON with lineMetrics:true,
 * explicitly attached to the owner; layers must be 2D line layers (no globe/3D lines).
 * Pattern image is a caller-registered image name, never a path or sprite alias; SDF unsupported.
 * Nonempty tracks contain 2..32 increasing offsets covering 0..1; opacity 0..1, widthScale 0..8.
 * At most6 distinct effects,4096 paths/100000 points per controller;32 line materials/256MiB.
 * Controllers/events use kind:"route"|"line". Line snapshots include layer,frame,
 * sourceStateRevision,visibleEffect and optional captured pattern identity. visibleEffect
 * describes a retained overlay; scene/layer visibility applies separately. Samples preserve
 * original source data, paint and geometry caches. External revisions/instances invalidate
 * old overlays without overwriting new values. Owner/controller removal restores caller layers.
 * Future finished waits need a retained script session; completed rounds resolve in one-shot scripts.
 * Scene/controller pause are independent; replay changes the epoch and cancels old waits. */
int32_t sqsm_map_scene_json(uint64_t handle,const uint8_t *json,uint64_t len,sqsm_map_bytes_t *out);
/* Extensible implemented-capability JSON; no mutation; same bytes ownership. */
int32_t sqsm_map_capabilities_json(uint64_t handle,sqsm_map_bytes_t *out);
/* querySourceFeatures uses this same channel. Options: filter, validate:true and sqs
 * {offset,limit,sourceInstanceId,dataRevision}. Default: complete array, <=1000 features,
 * <=8 MiB; oversized queries fail. Explicit sqs pages allow limits, 1..1000.
 * Reads do not move the camera or emit mutation events.
 * Shared label-placement configuration uses this channel with
 * {method:"sqs.getLabelFadeDuration",args:[]} or
 * {method:"sqs.setLabelFadeDuration",args:[milliseconds]}. Default 300;
 * finite 0..3600000 ms; zero settles on the next actual frame. Negative/nonfinite
 * values fail INVALID_ARGUMENT, values above the bound fail RESOURCE_LIMIT.
 * This map configuration survives full style replacement and is independent of
 * materialFadeDuration. Getters do not advance the placement clock. */
int32_t sqsm_map_source_json(uint64_t handle,const uint8_t *json,uint64_t len,sqsm_map_bytes_t *out);
/* Host-decoded RGBA8. The source identity is JSON {id,sourceInstanceId}; pixels are copied.
 * Positive safe sequence, dimensions 1..4096, exact width*height*4; 32MiB/frame,64MiB/map.
 * Output admission fails atomically; late/recreated-source frames never replace current pixels. */
int32_t sqsm_map_media_frame(uint64_t map, const uint8_t *identity, uint64_t identity_len,
    uint64_t sequence, uint32_t width, uint32_t height, const uint8_t *rgba,
    uint64_t rgba_len, sqsm_map_bytes_t *out);


/* Runtime flag bit 7 (128): shared GeoJSON style layers.
 * Shared GeoJSON style layers; same method/args envelope and allocation rules as sources.
 * circle / line / fill only in this stage; queries preserve raw metadata.
 * addLayer / removeLayer / moveLayer / getLayer / getLayers,
 * set/getPaintProperty, set/getLayoutProperty, set/getFilter, setLayerZoomRange,
 * set/getLayerMetadata (SqsMap extension; metadata.name is the optional display label).
 * Adding a layer preserves the view; a referenced source cannot be removed. */
/* queryRenderedFeatures uses this channel: optional CSS point, two-point box, or
 * viewport options; options.layers/filter/validate:true. Shared circle/line/fill only.
 * Complete results: <=1000 logical-parent features and <=8 MiB. Missing layers fail.
 * Reads preserve selection/business data; they may refresh camera-dependent caches.
 * Queries describe display geometry, not GPU occlusion or frame presentation. */
int32_t sqsm_map_layer_json(uint64_t handle,const uint8_t *json,uint64_t len,sqsm_map_bytes_t *out);
/* Shared image methods: addImage/updateImage/removeImage/hasImage/getImage/listImages/getImageInfo.
 * Envelope {method,args}; <=8MiB request, <=32MiB owned JSON response. ABI1.
 * Pixels are straight-alpha RGBA8. Writes use the journal and emit sqs.imageschange.
 * Sprite and runtime images share queries; owned output survives map destruction.
 * loadImage(url) returns {requestId}; pump Image descriptors through the existing
 * resource queue, then loadImageResult(requestId) returns {pending:true} or
 * {data:{width,height,data}}. Successful result output releases the request.
 * cancelLoadImage(requestId) releases it; late resource responses are rejected.
 * Delivered pending requests enqueue cancel=true Image descriptors; abort their owned
 * I/O before continuing. Pending cancellation notices retain one of the eight slots.
 * Eight pending/ready requests, HTTP(S), 4 MiB encoded, 512 px per side.
 * Loads do not register images or advance the command journal.
 * Free with sqsm_map_bytes_free. Failed allocation/validation preserves pixels/atlas/results. */
/* Glyph service: same envelope with getGlyphs [] or setGlyphs [url|null,{validate:true}?].
 * Runtime flag SQSM_MAP_GLYPH_SERVICE. Getter JSON null means unset/unparsed style.
 * Setter requires a parsed style and both {fontstack}/{range} template tokens in HTTP(S).
 * No credentials/fragments; 4096 UTF-8 bytes. validate:false reports CAPABILITY_UNAVAILABLE.
 * Ready tiles and images survive; all old style-resource requests are canceled by generation.
 * Hosts must stop obsolete downloads when the resource generation changes. Native core owns no HTTP.
 * Output allocation succeeds before mutation. Label language is style text-field, independent of UI locale.
 * Official WASM and default native builds share bundled HarmonyOS Chinese/Latin glyph fallback.
 */
int32_t sqsm_map_image_json(uint64_t handle, const uint8_t *json, uint64_t len, sqsm_map_bytes_t *out);

#ifdef __cplusplus
}
#endif
#endif

/* Bit 10 (1024): HTTP/HTTPS GeoJSON URLs use the existing host resource queue.
 * generation="source:<non-reused id>", id=0. cancel=true asks the host to abort
 * owned I/O; return buffers follow the unchanged resource response ownership.
 * Optional errorCode accompanies error: IO_ERROR/CANCELLED/RESOURCE_LIMIT/
 * INVALID_ARGUMENT/ENGINE_ERROR/CAPABILITY_UNAVAILABLE. Source events are
 * sourcedataloading/sourcedata/sourcedataabort/error with sourceEvent metadata.
 * Resource-ready is separate from sqsm_map_flush command/render confirmation. */
