# @neshan-maps-platform/maplibre-sdk

[![npm version](https://img.shields.io/npm/v/@neshan-maps-platform/maplibre-sdk.svg)](https://www.npmjs.com/package/@neshan-maps-platform/maplibre-sdk)
[![license](https://img.shields.io/npm/l/@neshan-maps-platform/maplibre-sdk.svg)](./LICENSE)

A drop-in wrapper around [MapLibre GL JS](https://maplibre.org/) that
transparently decodes the platform's encoded, gzip-compressed vector tiles,
injects a client API key on every tile request, enables RTL text, and applies
custom branding — while being used **exactly like plain `maplibre-gl`**.
MapLibre is bundled into the package, so consumers install one thing.

## Contents

- [Getting started](./GETTING_STARTED.md)
- [Install & quick start](#neshan-maps-platformmaplibre-sdk)
- [How it works](#how-it-works)
  - [API key](#api-key)
  - [Logo and copyright placement](#logo-and-copyright-placement)
  - [RTL text](#rtl-text-on-by-default)
  - [Styles](#styles)
- [Browser support](#browser-support)
- [Package contents](#package-contents)
- [License](#license)

```bash
npm install @neshan-maps-platform/maplibre-sdk
```

```js
import maplibregl from "@neshan-maps-platform/maplibre-sdk";
import "@neshan-maps-platform/maplibre-sdk/style.css";

const map = new maplibregl.Map({
  container: "map",
  style: "https://static.neshan.org/sdk/maplibre/styles/light.json",
  center: [59.6, 36.3],
  zoom: 12,
  apiKey: "YOUR_API_KEY",
});
```

That's the whole API. No protocol registration, no key handling, no
decompression, no control wiring — the subclass does all of it.

## How it works

### API key

Get an API key from [platform.neshan.org](https://platform.neshan.org/), then
pass it as `apiKey` to `new Map(...)`. It is appended as a `key` query
parameter to every tile request. It is your access/quota credential — not
secret in any meaningful sense, and enforced server-side.

`apiKey` is required — constructing a `Map` without one throws immediately.

### Logo and copyright placement

The logo and copyright are added at the bottom of the map. The user can
change the location of the logo and copyright, but they are not allowed to
remove or hide them.

Placement is configurable via `NeshanMapOptions` — note that, despite the
names, `logoPosition` places the attribution control and `copyRightPosition`
places the brand logo:

```js
new maplibregl.Map({
  /* ... */
  logoPosition: "bottom-left",
  copyRightPosition: "bottom-right",
});
```

Both accept MapLibre's `ControlPosition` (`'top-left'`, `'top-right'`,
`'bottom-left'`, `'bottom-right'`). `logoPosition` defaults to `'bottom-left'`;
`copyRightPosition` defaults to `'bottom-right'`.

### RTL text (on by default)

Arabic/Persian/Hebrew labels need MapLibre's `mapbox-gl-rtl-text` plugin. The
SDK registers it **automatically** — RTL shaping is on by default with no
consumer action. The plugin is bundled locally, so there's no separate file to
host and no CDN dependency.

To customize or opt out per map:

```js
new maplibregl.Map({ /* ... */, rtl: false });          // disable
new maplibregl.Map({ /* ... */, rtl: { lazy: false } }); // evaluate eagerly
new maplibregl.Map({ /* ... */, rtl: { url: '/rtl.js' }}); // self-hosted URL instead of inlined
```

Registration is global and idempotent, shared across all maps on the page.

### Styles

`style` is passed straight through to MapLibre, same as plain `maplibre-gl` —
point it at a style JSON URL. Five ready-made styles are hosted at
`https://static.neshan.org/sdk/maplibre/styles/`:

| Style                   | File                    | URL                                                                   |
| ----------------------- | ----------------------- | --------------------------------------------------------------------- |
| Light                   | `light.json`            | `https://static.neshan.org/sdk/maplibre/styles/light.json`            |
| Dark                    | `dark.json`             | `https://static.neshan.org/sdk/maplibre/styles/dark.json`             |
| Neshan Monochrome Light | `monochrome_light.json` | `https://static.neshan.org/sdk/maplibre/styles/monochrome_light.json` |
| Neshan Monochrome Dark  | `monochrome_dark.json`  | `https://static.neshan.org/sdk/maplibre/styles/monochrome_dark.json`  |
| Pastel                  | `pastel.json`           | `https://static.neshan.org/sdk/maplibre/styles/pastel.json`           |

```js
new maplibregl.Map({
  /* ... */
  style: "https://static.neshan.org/sdk/maplibre/styles/dark.json",
});
```

Projection (`mercator` vs. `globe`) is defined by the style JSON's own
`projection` field, not by a map option — to change it, edit or fork the
style rather than passing anything to `new Map(...)`.

## Browser support

Tile decoding uses the standard [`DecompressionStream`](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream)
API, so it needs Chrome 80+, Firefox 113+, or Safari 16.4+ (same floor as
`maplibre-gl` itself already requires). There is no fallback for older
browsers — tile requests will fail on them.

## Package contents

| File                              | Format                                            |
| --------------------------------- | ------------------------------------------------- |
| `dist/neshan-maplibre-sdk.js`     | ESM                                               |
| `dist/neshan-maplibre-sdk.cjs`    | CJS                                               |
| `dist/neshan-maplibre-sdk.umd.js` | UMD (global `maplibregl`)                         |
| `dist/neshan-maplibre-sdk.css`    | extracted MapLibre CSS                            |
| `dist/index.d.ts`                 | rolled-up type declarations (public surface only) |

## license

[ISC](./LICENSE)
