Skip to content

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.json files whitelist 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 via exports to dist/).

Deprecations (non-breaking — alias retained)

  • SdkState type renamed to ApiState — to align with the Mapsted Maps JavaScript API product name. SdkState remains exported as a type alias of ApiState for backwards compatibility and will be removed in the next major release. The MapState.sdkState property 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; use validateOriginWithConfig for customer integrations
  • buildOriginMismatchProtocolError — internal protocol-error builder; subscribe to the protocolError event instead
  • sanitisePayload — runs automatically on every incoming postMessage; no consumer call needed
  • isPlainObject — generic type-guard helper; use a standard library equivalent
  • resetShimState — test/lifecycle helper; called automatically by destroy()

Recent additions

  • JSDoc backfill: getFloors, getState, applyBoost, calculateDistance, getBuildingInfo, subscribe, setViewport
  • MapstedMapStatus exported 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 SDK wording in user-facing error messages); codes 1080–1084 recategorised to Search
  • RouteOptions.IncludeStairs JSDoc typo fixed (transistiontransition)
  • Reference doc accuracy: init-options.md defaults corrected — language, loader, and shareUrl are undefined (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 methodCurrent methodNotes
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: MapoverlayMapOverlay
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 ready

The 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

APIPurpose
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 typesTyped 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 destroy

The 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-1093

Or 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.warn fires 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) or init({ strict: true })): MAPSTED-1093 is thrown immediately on any deprecated call, with a migration message in err.message. Useful for migration audits.
  • After destroy(): Shim state resets — the console.warn fires 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.