Appearance
Changelog
The current release is 4.0.1 (date-based versioning: 26 = 2026, 7 = July, 1 = release). It supersedes the V3 generation while keeping every V3 and V2 method name working via the migration shim.
[4.0.1]
Current release. Delivers method renames to canonical names (init, on/off, setViewport, navigateToFloor*, setLanguage), structured error codes, an origin-validated postMessage layer, a typed event API with discriminated payloads, an async init() contract, strict-mode-by-default origin validation, a state-subscription API, building-level navigation, and a backward-compatibility shim that keeps V2 and V3 method names working. Includes one BREAKING change to the published npm tarball + one deprecation alias on a public type.
BREAKING
package.jsonfileswhitelist narrowed to["dist"]— previously["dist", "src"]. The published npm tarball no longer ships the raw TypeScript source tree. Customers who imported from@mapsted/maps-js-api/src/...must switch to importing from@mapsted/maps-js-api(resolved viaexportstodist/).
Deprecations (non-breaking — alias retained)
SdkStatetype renamed toApiState— to align with the Mapsted Maps JavaScript API product name.SdkStateremains exported as a type alias ofApiStatefor backwards compatibility and will be removed in the next major release. TheMapState.sdkStateproperty name is unchanged in this release; the field rename is queued for the next major release with its own migration shim.
Internal-API surface tightening
The following functions are reclassified @internal (marked with the @internal JSDoc tag, excluded from the generated TypeDoc reference, and not part of the public sidebar). They remain in the published dist/ for runtime backwards compatibility but are no longer documented as customer-facing:
checkOrigin— framework primitive; usevalidateOriginWithConfigfor customer integrationsbuildOriginMismatchProtocolError— internal protocol-error builder; subscribe to theprotocolErrorevent insteadsanitisePayload— runs automatically on every incoming postMessage; no consumer call neededisPlainObject— generic type-guard helper; use a standard library equivalentresetShimState— test/lifecycle helper; called automatically bydestroy()
Recent additions
- JSDoc backfill:
getFloors,getState,applyBoost,calculateDistance,getBuildingInfo,subscribe,setViewport MapstedMapStatusexported as a named type (import { MapstedMapStatus } from '@mapsted/maps-js-api')- Mobile viewport overflow fix: map iframe no longer bleeds outside container on iOS/Android
- Error code message templates aligned with the canonical product name "Mapsted Maps JavaScript API" (replacing legacy
SDKwording in user-facing error messages); codes 1080–1084 recategorised toSearch RouteOptions.IncludeStairsJSDoc typo fixed (transistion→transition)- Reference doc accuracy:
init-options.mddefaults corrected —language,loader, andshareUrlareundefined(previously documented as static strings). - Browser support: Samsung Internet bumped to 14+ in the supported-browsers matrix.
- Node.js engine pinned to
≥ 20.0.0(build/SSR tooling only).
Breaking changes
npm usage
The API is published to npm as @mapsted/maps-js-api. npm users supply propertyId in InitOptions; mapsDomain is optional and defaults to https://maps.mapsted.com — set it only for a white-label or self-hosted map backend.
ts
// 4.0.1 npm usage
import * as maps from '@mapsted/maps-js-api';
await maps.init({
mapsDomain: 'https://maps.mapsted.com',
propertyId: 603,
});CDN usage
CDN path moves from /v3.0.0/maps.js to /v4.0.1/maps.js:
html
<script src="https://mapi.mapsted.com/v4.0.1/maps.js?id=603"></script>mapi.mapsted.com serves every version directly, so V3 customers on https://mapi.mapsted.com/v3.0.0/maps.js?id=603 keep working with no change — the URL stays alive alongside the new version. Hardcoded legacy <script src> tags never break. The V3 migration shim is removed in the next major release. See Compatibility — CDN Versioning for the canonical schedule.
Method renames (10 methods)
V3 method names still work via a backward-compatibility shim. Strict mode turns them into hard errors; opt into it with strict: true during migration audits.
| V3 method | Current method | Notes |
|---|---|---|
initialize(options) | init(options) | Now returns Promise<MapInstance> |
set(options) | init(options) | V3 set() was the public alias for internal setOptions() |
changeFloorById(id) | navigateToFloorById(id) | |
changeFloorByName(name) | navigateToFloorByName(name) | |
setMapView(view) | setViewport(view) | |
centerOnMapoverlay(id) | centerOnMapOverlay(id) | Casing fix: Mapoverlay → MapOverlay |
setDefaultCustomRoutingConfig(cfg) | setDefaultRoutingConfig(cfg) | |
changeLanguage(code) | setLanguage(code) | |
addEventListener(event, fn) | on(event, fn) | Payloads are typed via discriminated overloads |
removeEventListener(event, fn) | off(event, fn) | Also adds once() for one-shot listeners |
highlightStyle() | (removed) | The function had no runtime effect in V2/V3. It now throws MAPSTED-1093 so removed call sites are easy to find. The HighlightStyle type remains exported (used in MapEntity.highlight). |
Migration strict mode: Default is lenient — each deprecated method logs one console.warn on first call and then delegates to the current equivalent. Opt into strict mode during migration audits by calling setStrictMode(true) or passing strict: true in init() options; deprecated calls will then throw MAPSTED-1093 immediately so you can find remaining call sites. (Note: SecurityConfig.strictMode is a separate setting for origin validation — see the Security section; that one does default to true.)
init() is now async and returns MapInstance
V3's initialize() was synchronous (void return) and left readiness to the caller. init() returns Promise<MapInstance> — await the handshake and you get back a typed instance handle for destroy() and state queries.
ts
// V3 (fire-and-forget, no handle)
maps.initialize({ element: '#map' });
// Current (await the handshake, use the returned MapInstance)
const map = await mapsted.maps.init({ element: '#map' });
// map.destroy() / map.isReady() available; API guaranteed readyThe element input shape (HTMLElement | string) carries over from V3 unchanged.
PRIVATE_CHILD_ACTION removed (CHL-27)
The PRIVATE_CHILD_ACTION constant is removed from public exports for security hardening. It was an internal protocol marker that was accidentally exposed in V3. Remove the import — protocol handling is fully internal now.
ts
// V3 (no longer works)
import { PRIVATE_CHILD_ACTION } from '@mapsted/maps-js-api';
// Current: just remove the import. No replacement needed.Error codes (44 codes)
V3 did not have structured error codes. This release introduces 44 codes in the MAPSTED-1xxx range covering all failure modes. All errors are instances of MapstedError, which extends Error with a code property.
ts
// V3: untyped
try { await maps.initialize({ propertyId: 'bad' }); }
catch (e) { console.error(e.message); } // arbitrary string
// Current: typed
try { await maps.init({ propertyId: 'bad' }); }
catch (e) {
if (e instanceof MapstedError) {
console.error(e.code); // "MAPSTED-1010"
console.error(e.message); // "propertyId is required in API configuration."
}
}See the Error Codes reference for the full list.
Security: origin validation
All postMessage communication between the API and the map iframe is restricted to the resolved origin. The wildcard * target is only used transiently during CDN-mode initialisation and is replaced with the iframe's actual origin immediately after load.
Messages from unexpected origins are silently dropped and trigger a protocolError event with code MAPSTED-1400.
Event system: on / off / once
V3 used DOM-style addEventListener / removeEventListener. This release introduces on(), off(), and once() with discriminated TypeScript overloads so the payload type is inferred from the event name.
ts
// V3 (deprecated — still works via shim)
maps.addEventListener('select', function(data) { /* data: any */ });
// Current (typed overloads)
maps.on('select', (data) => {
// data: EntityData — fully typed, no cast needed
console.log(data.entityId);
});New APIs in this release
| API | Purpose |
|---|---|
setAccessibilityMode(mode) | Toggle accessibility rendering mode |
setStrictMode(enabled) | Toggle strict-mode behaviour at runtime |
navigateToFloorById(id) / navigateToFloorByName(name) | Floor-level navigation, including floors in other buildings of a multi-building property |
getState() + subscribe(fn) | Read-only state snapshot + change subscription |
ApiState / MapState types | Typed state shape (SdkState retained as a legacy alias of ApiState) |
Migration guide (V2 or V3 to the current release)
Step 1 — Update method names
Replace deprecated method calls using the rename table above.
ts
// Before (V2 or V3)
maps.initialize({ containerId: 'map', propertyId: 202 });
maps.changeFloorById(184);
maps.changeLanguage('fr');
maps.addEventListener('select', handler);
// After (current)
await maps.init({ element: '#map', propertyId: 603 });
await maps.navigateToFloorById(184);
await maps.setLanguage('fr');
maps.on('select', handler);Step 2 — await the init() call
V3's initialize() was synchronous. init() returns Promise<MapInstance>, so you must await it and you get back an instance handle.
ts
// V3 (fire-and-forget, implicit wait)
maps.initialize({ element: '#map', propertyId: 603 });
// Current (awaited; returns MapInstance)
const map = await mapsted.maps.init({ element: '#map', propertyId: 603 });
await map.isReady(); // explicit readiness check (async — returns a Promise)
// …later…
await map.destroy(); // typed destroyThe element input shape is unchanged from V3 (HTMLElement | string — CSS selector or element reference). V2's containerId: string was replaced with element back at the V2→V3 boundary.
Step 3 — Handle MapstedError in catch blocks
V2 and V3 errors were untyped strings. Wrap all init() and command method calls in try/catch and check err instanceof MapstedError.
ts
import { MapstedError } from '@mapsted/maps-js-api';
try {
await maps.init({ element: '#map', propertyId: 603 });
} catch (err) {
if (err instanceof MapstedError) {
switch (err.code) {
case 'MAPSTED-1001': // already initialised
await maps.destroy();
break;
case 'MAPSTED-1200': // invalid API key
showKeyError();
break;
default:
console.error(err.code, err.message);
}
}
}Step 4 — Migrate event listeners
Replace addEventListener / removeEventListener with on / off / once.
ts
// V2 / V3
maps.addEventListener('floorChange', onFloor);
maps.removeEventListener('floorChange', onFloor);
// Current
maps.on('floorChange', onFloor);
maps.off('floorChange', onFloor);
// One-time listener
maps.once('load', () => console.log('ready'));Step 5 — Remove highlightStyle() calls
highlightStyle() was dead code in earlier versions and now always throws MAPSTED-1093. Delete any calls to it. Use the highlight field on MapEntity objects instead (see Types reference).
Step 6 — Opt into strict mode for migration audits (optional)
Default behaviour is lenient: a deprecated call logs one console.warn and then delegates to the current equivalent. To catch every remaining deprecated call site at once, opt into strict mode:
ts
import { setStrictMode } from '@mapsted/maps-js-api';
setStrictMode(true); // deprecated calls now throw MAPSTED-1093Or set it at init time:
ts
await mapsted.maps.init({ element: '#map', strict: true });Once you have zero deprecated call sites, flip back to lenient (or leave strict on as a permanent safety net).
Migration shim behaviour
V2 and V3 method names keep working via the shim:
- Lenient mode (default):
console.warnfires on the first call to each deprecated method (once per page load). The current equivalent is then called transparently. - Strict mode (opt in via
setStrictMode(true)orinit({ strict: true })):MAPSTED-1093is thrown immediately on any deprecated call, with a migration message inerr.message. Useful for migration audits. - After
destroy(): Shim state resets — theconsole.warnfires again on next use after re-initialisation.
The shim is scheduled for removal in the next major release.
v3.0.0
Historical release. TypeScript rewrite of the V2 UMD bundle, published to npm as mapsted.maps, built with tsup (ESM + CJS + IIFE + d.ts). V2 method names (initialize, changeFloorById, addEventListener, etc.) continued to work as the canonical public API. Origin-validated postMessage and the typed event API (on/off/once) arrived in the current 4.0.1 generation, not V3.