osmfeatures 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -17
- package/dist/index.d.ts +4 -2
- package/dist/index.js +10 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OSM Features API client
|
|
2
2
|
|
|
3
|
-
Official
|
|
3
|
+
Official client for the [MapLark OSM Features API](https://maplark.com) to get GeoJSON, FlatGeobuf, GeoParquet, or CSV from OpenStreetMap. The API gets data from dedicated postgis OSM servers separate from public Overpass.
|
|
4
4
|
|
|
5
|
-
Query OpenStreetMap features such as buildings, streets, and POIs easily. Search for OSM features by bounding box, tags, and geometry shape and get GeoJSON back within less than 250ms (dependent on query size). No converting between formats manually. The API keeps
|
|
5
|
+
Query OpenStreetMap features such as buildings, streets, and POIs easily. Search for OSM features by bounding box, tags, and geometry shape and get GeoJSON back within less than 250ms (dependent on query size). No converting between formats manually. The API keeps OSM semantics intact, like tags and ways, and returns OSM features you can feed straight into Leaflet, MapLibre, OpenLayers, or any geospatial toolchain. It is backed by postgis with tiered API keys and rate limiting to keep noisy neighbours out to give you low, predictable latency for real traffic. It also has self-host path for those willing to host complex infrastructure themselves.
|
|
6
6
|
|
|
7
7
|
The translation layer is very simple:
|
|
8
8
|
|
|
@@ -24,16 +24,10 @@ For example, to get all buildings in an area:
|
|
|
24
24
|
|
|
25
25
|
This is the equivalent of the Overpass query `way[building]`.
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
# How to use it
|
|
27
|
+
# Quick start
|
|
30
28
|
|
|
31
29
|
```bash
|
|
32
|
-
# From npm (when published):
|
|
33
30
|
npm install osmfeatures
|
|
34
|
-
|
|
35
|
-
# Until then, from git:
|
|
36
|
-
npm install git+https://github.com/MapLark/osmfeatures-ts.git
|
|
37
31
|
```
|
|
38
32
|
|
|
39
33
|
```ts
|
|
@@ -45,23 +39,164 @@ const page = await client.query({
|
|
|
45
39
|
tags: ['building'],
|
|
46
40
|
});
|
|
47
41
|
|
|
48
|
-
//
|
|
49
|
-
map.getSource('buildings').setData(page.data);
|
|
42
|
+
// Get GeoJSON FeatureCollection
|
|
50
43
|
console.log(page.data.features.length);
|
|
51
44
|
|
|
52
|
-
// Header
|
|
45
|
+
// Header meta for paging + usage
|
|
53
46
|
console.log(page.meta.has_more, page.meta.next_cursor, page.meta.units_charged);
|
|
54
47
|
|
|
55
|
-
// Binary / table encodings via Accept
|
|
48
|
+
// Binary / table encodings via Accept param
|
|
56
49
|
const fgb = await client.query({
|
|
57
50
|
bbox: '18.06,59.32,18.09,59.34',
|
|
58
51
|
tags: ['building'],
|
|
59
52
|
accept: 'application/flatgeobuf',
|
|
60
53
|
});
|
|
61
|
-
console.log(fgb.data
|
|
54
|
+
console.log(fgb.data);
|
|
55
|
+
console.log(fgb.meta.has_more, fgb.meta.next_cursor);
|
|
62
56
|
```
|
|
63
57
|
|
|
64
58
|
Talks to `https://api.maplark.com` by default.
|
|
65
59
|
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
# Functions and Parameters
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## `query()`
|
|
65
|
+
|
|
66
|
+
Fetches a single page from the API. Returns `{ data, meta }` where `data` is a GeoJSON FeatureCollection (default) or an `ArrayBuffer` for binary encodings.
|
|
67
|
+
|
|
68
|
+
#### Spatial anchors (required)
|
|
69
|
+
|
|
70
|
+
The geographical area for the request in terms of GPS coordinates or specific OSM ids.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
| Param | Type | Description |
|
|
74
|
+
| -------- | -------- | -------------------------------------------------- |
|
|
75
|
+
| `bbox` | `string` | Bounding box as `min_lon,min_lat,max_lon,max_lat`. |
|
|
76
|
+
| `around` | `string` | Circle filter as `lon,lat,radius_m`. |
|
|
77
|
+
| `osmIds` | `string` | Comma-separated OSM IDs to fetch by id. |
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
#### Tags
|
|
83
|
+
|
|
84
|
+
The feature tags to filter on.
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
| Param | Type | Description |
|
|
88
|
+
| --------- | ---------- | -------------------------------------------------------------------------------- |
|
|
89
|
+
| `tags` | `string[]` | Tag filters that must all match (AND). Values like `building` or `amenity=cafe`. |
|
|
90
|
+
| `orTags` | `string[]` | Tag filters where any may match (OR). |
|
|
91
|
+
| `notTags` | `string[]` | Tag filters to exclude. |
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
#### Geometry
|
|
97
|
+
|
|
98
|
+
Geometric filters such specific OSM element type, min length, or including centroid.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
| Param | Type | Default | Description |
|
|
102
|
+
| ------------ | ---------------------- | ------- | --------------------------------------------------------------------------------------- |
|
|
103
|
+
| `type` | `string` | all | OSM element types, e.g. `node`, `way`, `relation`, or comma-separated (`way,relation`). |
|
|
104
|
+
| `shape` | `line | polygon | all` | `all` | Geometry shape filter for ways and relations. |
|
|
105
|
+
| `centroid` | `boolean` | `false` | When `true`, include a centroid on non-point features. |
|
|
106
|
+
| `clipGeometry` | `boolean` | `true` | When `true`, clip returned geometry to the requested `bbox`. Set `false` for full geometry. |
|
|
107
|
+
| `minLengthM` | `number` | | Minimum length in metres (lines). |
|
|
108
|
+
| `maxLengthM` | `number` | | Maximum length in metres (lines). |
|
|
109
|
+
| `minAreaM2` | `number` | | Minimum area in square metres (polygons). |
|
|
110
|
+
| `maxAreaM2` | `number` | | Maximum area in square metres (polygons). |
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
#### Other
|
|
116
|
+
|
|
117
|
+
Extra filters to for pagination, output format (accept),
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
| Param | Type | Default | Description |
|
|
121
|
+
| ---------------------- | --------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
122
|
+
| `accept` | `string` | `application/geo+json` | Response media type in header. Options - `application/geo+json`, `text/csv`, `text/tab-separated-values`, `application/flatgeobuf`, and `application/vnd.apache.parquet`. |
|
|
123
|
+
| `limit` | `number` | `1000` | Page size. Max `6000`. |
|
|
124
|
+
| `cursor` | `string` | | Pagination cursor from a previous `meta.next_cursor`. |
|
|
125
|
+
| `disableBudgetWarning` | `boolean` | `false` | Ignore warnings for large queries that consume budget quotas. |
|
|
126
|
+
| `zoom` | `number` | | Map zoom hint (used by presets / server-side simplification policies). |
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
### Meta
|
|
132
|
+
|
|
133
|
+
Fields for pagination and usage.
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
| Field | Description |
|
|
137
|
+
| --------------- | --------------------------------------------------------------------- |
|
|
138
|
+
| `returned` | Features in this page. |
|
|
139
|
+
| `has_more` | Whether more pages exist. |
|
|
140
|
+
| `next_cursor` | Pass as `cursor` on the next `query` call, or `null` when done. |
|
|
141
|
+
| `units_charged` | Usage for this request when present in terms of cpu and ram consumed. |
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
## `query_all`
|
|
147
|
+
|
|
148
|
+
Auto-paginates (and optionally tiles the bbox) until the result is complete or a client-side cap is hit. GeoJSON only — for FlatGeobuf / other encodings, use `query` with `accept`.
|
|
149
|
+
|
|
150
|
+
Does not take `limit` or `cursor`; paging is handled internally.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const all = await client.query_all({
|
|
154
|
+
bbox: '18.06,59.32,18.09,59.34',
|
|
155
|
+
tags: ['building'],
|
|
156
|
+
limitPerPage: 1000,
|
|
157
|
+
bboxTiles: 2,
|
|
158
|
+
maxPages: 15,
|
|
159
|
+
maxFeatures: 55_000,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log(all.data.features.length);
|
|
163
|
+
console.log(all.meta.page_count, all.meta.has_more, all.meta.units_charged);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
### Params
|
|
169
|
+
|
|
170
|
+
Same filter params as `query` (`bbox`, `tags`, `orTags`, `notTags`, `type`, `shape`, `zoom`, `around`, `osmIds`, `minLengthM`, `maxLengthM`, `minAreaM2`, `maxAreaM2`, `centroid`, `clipGeometry`, `disableBudgetWarning`), plus:
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
| Param | Type | Default | Description |
|
|
174
|
+
| -------------- | --------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
175
|
+
| `limitPerPage` | `number` | `1000` | Upstream `limit` per HTTP request (page size). |
|
|
176
|
+
| `bboxTiles` | `number` | `2` | Split `bbox` into this many tiles (must be a power of 2: `1`, `2`, `4`, `8`, …). Each tile is paginated separately, then features are merged and deduped. |
|
|
177
|
+
| `maxPages` | `number` | `15` | Max pages fetched **per tile**. |
|
|
178
|
+
| `maxFeatures` | `number | null` | `55000` | Cap on merged features after dedupe. Pass `null` for no cap. |
|
|
179
|
+
| `accept` | `string` | `application/geo+json` | Must be GeoJSON (or omitted). Non-GeoJSON throws. |
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
### Meta
|
|
185
|
+
|
|
186
|
+
Same fields as `query`, plus:
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
| Field | Description |
|
|
190
|
+
| ---------------------- | ------------------------------------------------------------------------------------ |
|
|
191
|
+
| `page_count` | Total upstream pages fetched. |
|
|
192
|
+
| `has_more` | `true` if stopped early (caps), or upstream still had more, or a partial relay stop. |
|
|
193
|
+
| `next_cursor` | Last cursor when incomplete; otherwise the final page cursor. |
|
|
194
|
+
| `units_charged` | Sum of units charged across pages when present. |
|
|
195
|
+
| `relay_partial` | `true` if paging stopped after a mid-stream 400/429 (partial result kept). |
|
|
196
|
+
| `relay_partial_reason` | e.g. `upstream_rejected_cursor` or `upstream_rate_limited_after_retries`. |
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
Also exports layer presets (`resolveLayerFromQuery`, `OSM_FEATURES_LAYER_PRESETS`, ...)
|
|
200
|
+
and GeoJSON payload helpers (`featureCentroid`, `geometryBounds`, `parseFeatureId`, ...).
|
|
201
|
+
|
|
202
|
+
Read the full API reference here [https://maplark.com/developer](https://maplark.com/developer) such as the OpenAPI 2.0 HTTP docs.
|
package/dist/index.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export type OSMFeaturesParams = OSMFeaturesLayer & {
|
|
|
47
47
|
maxAreaM2?: number;
|
|
48
48
|
disableBudgetWarning?: boolean;
|
|
49
49
|
centroid?: boolean;
|
|
50
|
+
/** When true (default), clip returned geometry to the requested bbox. */
|
|
51
|
+
clipGeometry?: boolean;
|
|
50
52
|
/** Accept media type. Default application/geo+json; other types put bytes in ``data``. */
|
|
51
53
|
accept?: string;
|
|
52
54
|
};
|
|
@@ -81,9 +83,9 @@ export declare class OSMFeatures {
|
|
|
81
83
|
/** Single HTTP request with retry. Throws on non-OK (same role as Python `_raw_query`). */
|
|
82
84
|
private _rawQuery;
|
|
83
85
|
/** Single upstream page. Params map 1:1 to server query string (no tiling). */
|
|
84
|
-
query({ bbox, tags, orTags, notTags, type, shape, limit, cursor, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, accept, }: OSMFeaturesParams, dependencies?: OSMFeaturesDependencies): Promise<OSMFeaturesResult>;
|
|
86
|
+
query({ bbox, tags, orTags, notTags, type, shape, limit, cursor, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, }: OSMFeaturesParams, dependencies?: OSMFeaturesDependencies): Promise<OSMFeaturesResult>;
|
|
85
87
|
/** Auto-paginate (and optionally tile) until complete. Each page uses `_rawQuery`. */
|
|
86
|
-
query_all({ bbox, tags, orTags, notTags, type, shape, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, accept, limitPerPage, bboxTiles, maxPages, maxFeatures, }: Omit<OSMFeaturesParams, 'limit' | 'cursor'> & {
|
|
88
|
+
query_all({ bbox, tags, orTags, notTags, type, shape, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, limitPerPage, bboxTiles, maxPages, maxFeatures, }: Omit<OSMFeaturesParams, 'limit' | 'cursor'> & {
|
|
87
89
|
/** Upstream `limit` per HTTP request (page size). */
|
|
88
90
|
limitPerPage?: number;
|
|
89
91
|
bboxTiles?: number;
|
package/dist/index.js
CHANGED
|
@@ -177,6 +177,9 @@ function buildFeaturesQuery(params) {
|
|
|
177
177
|
if (params.centroid != null) {
|
|
178
178
|
query.set('centroid', String(params.centroid));
|
|
179
179
|
}
|
|
180
|
+
if (params.clipGeometry != null) {
|
|
181
|
+
query.set('clipGeometry', String(params.clipGeometry));
|
|
182
|
+
}
|
|
180
183
|
if (params.type) {
|
|
181
184
|
query.set('type', params.type);
|
|
182
185
|
}
|
|
@@ -270,6 +273,7 @@ export class OSMFeatures {
|
|
|
270
273
|
maxAreaM2: optionalNumber(query, 'max_area_m2'),
|
|
271
274
|
disableBudgetWarning: optionalBoolean(query, 'disable_budget_warning'),
|
|
272
275
|
centroid: optionalBoolean(query, 'centroid'),
|
|
276
|
+
clipGeometry: optionalBoolean(query, 'clipGeometry'),
|
|
273
277
|
};
|
|
274
278
|
}
|
|
275
279
|
async throwUpstreamError(upstream) {
|
|
@@ -335,6 +339,8 @@ export class OSMFeatures {
|
|
|
335
339
|
}
|
|
336
340
|
}
|
|
337
341
|
}
|
|
342
|
+
// ponytail: simple stderr-visible warning for 429 retries; upgrade to injected logger if consumers need structured logs.
|
|
343
|
+
console.warn(`[osmfeatures] Upstream returned 429; retry ${retryAttempt}/${this.retryAttempts} in ${Math.round(waitMs)}ms.`);
|
|
338
344
|
await sleepFn(waitMs);
|
|
339
345
|
continue;
|
|
340
346
|
}
|
|
@@ -352,7 +358,7 @@ export class OSMFeatures {
|
|
|
352
358
|
};
|
|
353
359
|
}
|
|
354
360
|
/** Single upstream page. Params map 1:1 to server query string (no tiling). */
|
|
355
|
-
async query({ bbox, tags, orTags, notTags, type, shape, limit = DEFAULT_LIMIT, cursor, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, accept, }, dependencies = {}) {
|
|
361
|
+
async query({ bbox, tags, orTags, notTags, type, shape, limit = DEFAULT_LIMIT, cursor, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, }, dependencies = {}) {
|
|
356
362
|
const payload = await this._rawQuery({
|
|
357
363
|
bbox,
|
|
358
364
|
tags,
|
|
@@ -371,12 +377,13 @@ export class OSMFeatures {
|
|
|
371
377
|
maxAreaM2,
|
|
372
378
|
disableBudgetWarning,
|
|
373
379
|
centroid,
|
|
380
|
+
clipGeometry,
|
|
374
381
|
accept,
|
|
375
382
|
}, dependencies.fetchFn ?? fetch, dependencies.sleepFn ?? sleep, dependencies.nowFn ?? Date.now);
|
|
376
383
|
return payload;
|
|
377
384
|
}
|
|
378
385
|
/** Auto-paginate (and optionally tile) until complete. Each page uses `_rawQuery`. */
|
|
379
|
-
async query_all({ bbox, tags, orTags, notTags, type, shape, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, accept, limitPerPage = DEFAULT_LIMIT, bboxTiles = 2, maxPages = 15, maxFeatures = 55_000, }, dependencies = {}) {
|
|
386
|
+
async query_all({ bbox, tags, orTags, notTags, type, shape, zoom, around, osmIds, minLengthM, maxLengthM, minAreaM2, maxAreaM2, disableBudgetWarning, centroid, clipGeometry, accept, limitPerPage = DEFAULT_LIMIT, bboxTiles = 2, maxPages = 15, maxFeatures = 55_000, }, dependencies = {}) {
|
|
380
387
|
if (!isGeojsonAccept(accept)) {
|
|
381
388
|
throw appError(400, 'invalid_accept', 'query_all only supports GeoJSON; use query({ accept }) for binary encodings.');
|
|
382
389
|
}
|
|
@@ -413,6 +420,7 @@ export class OSMFeatures {
|
|
|
413
420
|
maxAreaM2,
|
|
414
421
|
disableBudgetWarning,
|
|
415
422
|
centroid,
|
|
423
|
+
clipGeometry,
|
|
416
424
|
};
|
|
417
425
|
for (const tileBbox of tileBboxes) {
|
|
418
426
|
if (allFeatures.length >= featureCap) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osmfeatures",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Get OpenStreetMap features such as buildings, roads, or points of interest from dedicated servers with a single API call in GeoJSON, FlatGeobuf, Geoparquet, and CSV formats.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|