@unmap/geocoding 0.0.1

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.
@@ -0,0 +1,54 @@
1
+ interface GeocoderOptions {
2
+ key: string;
3
+ gateway?: string;
4
+ /** Override the fetch implementation (tests, non-global environments). */
5
+ fetch?: typeof fetch;
6
+ }
7
+ type GeocodeLayer = "address" | "street" | "locality" | "region" | "poi";
8
+ interface GeocodeResult {
9
+ id: string;
10
+ name: string;
11
+ layer: GeocodeLayer;
12
+ lng: number;
13
+ lat: number;
14
+ score?: number;
15
+ names?: Record<string, string>;
16
+ address?: {
17
+ housenumber?: string;
18
+ street?: string;
19
+ city?: string;
20
+ region?: string;
21
+ postcode?: string;
22
+ country?: string;
23
+ };
24
+ }
25
+ interface SearchOptions {
26
+ limit?: number;
27
+ lang?: string;
28
+ /** [minLng, minLat, maxLng, maxLat] bias/filter. */
29
+ bbox?: [number, number, number, number];
30
+ signal?: AbortSignal;
31
+ }
32
+ declare class GeocoderError extends Error {
33
+ readonly status: number;
34
+ constructor(status: number, message: string);
35
+ }
36
+ /** Typed client for the unmap geocoding API (gateway `/geocode/*`). */
37
+ declare class Geocoder {
38
+ private readonly key;
39
+ private readonly base;
40
+ private readonly fetchImpl;
41
+ constructor(opts: GeocoderOptions);
42
+ /** Full-text search. */
43
+ search(q: string, opts?: SearchOptions): Promise<GeocodeResult[]>;
44
+ /** Type-ahead suggestions for partial input. */
45
+ autocomplete(q: string, opts?: SearchOptions): Promise<GeocodeResult[]>;
46
+ /** Reverse geocode a coordinate. */
47
+ reverse(lng: number, lat: number, opts?: {
48
+ lang?: string;
49
+ signal?: AbortSignal;
50
+ }): Promise<GeocodeResult[]>;
51
+ private query;
52
+ }
53
+
54
+ export { type GeocodeLayer, type GeocodeResult, Geocoder, GeocoderError, type GeocoderOptions, type SearchOptions };
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ // src/index.ts
2
+ import { DEFAULT_GATEWAY } from "@unmap/core";
3
+ var GeocoderError = class extends Error {
4
+ constructor(status, message) {
5
+ super(message);
6
+ this.status = status;
7
+ this.name = "GeocoderError";
8
+ }
9
+ status;
10
+ };
11
+ var Geocoder = class {
12
+ key;
13
+ base;
14
+ fetchImpl;
15
+ constructor(opts) {
16
+ this.key = opts.key;
17
+ this.base = (opts.gateway ?? DEFAULT_GATEWAY).replace(/\/+$/, "");
18
+ this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);
19
+ }
20
+ /** Full-text search. */
21
+ search(q, opts = {}) {
22
+ return this.query("/geocode/search", { q, ...toParams(opts) }, opts.signal);
23
+ }
24
+ /** Type-ahead suggestions for partial input. */
25
+ autocomplete(q, opts = {}) {
26
+ return this.query("/geocode/autocomplete", { q, ...toParams(opts) }, opts.signal);
27
+ }
28
+ /** Reverse geocode a coordinate. */
29
+ reverse(lng, lat, opts = {}) {
30
+ return this.query(
31
+ "/geocode/reverse",
32
+ { lon: String(lng), lat: String(lat), lang: opts.lang },
33
+ opts.signal
34
+ );
35
+ }
36
+ async query(path, params, signal) {
37
+ const q = new URLSearchParams({ key: this.key });
38
+ for (const [k, v] of Object.entries(params)) if (v != null && v !== "") q.set(k, v);
39
+ const res = await this.fetchImpl(`${this.base}${path}?${q}`, {
40
+ signal,
41
+ headers: { accept: "application/json" }
42
+ });
43
+ if (!res.ok) throw new GeocoderError(res.status, `geocode ${res.status} on ${path}`);
44
+ const body = await res.json();
45
+ return Array.isArray(body) ? body : body.results ?? [];
46
+ }
47
+ };
48
+ function toParams(o) {
49
+ return {
50
+ limit: o.limit != null ? String(o.limit) : void 0,
51
+ lang: o.lang,
52
+ bbox: o.bbox ? o.bbox.join(",") : void 0
53
+ };
54
+ }
55
+ export {
56
+ Geocoder,
57
+ GeocoderError
58
+ };
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { DEFAULT_GATEWAY } from \"@unmap/core\";\n\nexport interface GeocoderOptions {\n key: string;\n gateway?: string;\n /** Override the fetch implementation (tests, non-global environments). */\n fetch?: typeof fetch;\n}\n\nexport type GeocodeLayer = \"address\" | \"street\" | \"locality\" | \"region\" | \"poi\";\n\nexport interface GeocodeResult {\n id: string;\n name: string;\n layer: GeocodeLayer;\n lng: number;\n lat: number;\n score?: number;\n names?: Record<string, string>;\n address?: {\n housenumber?: string;\n street?: string;\n city?: string;\n region?: string;\n postcode?: string;\n country?: string;\n };\n}\n\nexport interface SearchOptions {\n limit?: number;\n lang?: string;\n /** [minLng, minLat, maxLng, maxLat] bias/filter. */\n bbox?: [number, number, number, number];\n signal?: AbortSignal;\n}\n\nexport class GeocoderError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n ) {\n super(message);\n this.name = \"GeocoderError\";\n }\n}\n\n/** Typed client for the unmap geocoding API (gateway `/geocode/*`). */\nexport class Geocoder {\n private readonly key: string;\n private readonly base: string;\n private readonly fetchImpl: typeof fetch;\n\n constructor(opts: GeocoderOptions) {\n this.key = opts.key;\n this.base = (opts.gateway ?? DEFAULT_GATEWAY).replace(/\\/+$/, \"\");\n // Bound to globalThis: stored on an instance and called as `this.fetchImpl(...)`, a bare\n // `fetch` reference is invoked with the Geocoder as its receiver, and browsers reject that\n // with \"Illegal invocation\". Node is lenient, so this only ever surfaces in the browser.\n this.fetchImpl = opts.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** Full-text search. */\n search(q: string, opts: SearchOptions = {}): Promise<GeocodeResult[]> {\n return this.query(\"/geocode/search\", { q, ...toParams(opts) }, opts.signal);\n }\n\n /** Type-ahead suggestions for partial input. */\n autocomplete(q: string, opts: SearchOptions = {}): Promise<GeocodeResult[]> {\n return this.query(\"/geocode/autocomplete\", { q, ...toParams(opts) }, opts.signal);\n }\n\n /** Reverse geocode a coordinate. */\n reverse(\n lng: number,\n lat: number,\n opts: { lang?: string; signal?: AbortSignal } = {},\n ): Promise<GeocodeResult[]> {\n return this.query(\n \"/geocode/reverse\",\n { lon: String(lng), lat: String(lat), lang: opts.lang },\n opts.signal,\n );\n }\n\n private async query(\n path: string,\n params: Record<string, string | undefined>,\n signal?: AbortSignal,\n ): Promise<GeocodeResult[]> {\n const q = new URLSearchParams({ key: this.key });\n for (const [k, v] of Object.entries(params)) if (v != null && v !== \"\") q.set(k, v);\n const res = await this.fetchImpl(`${this.base}${path}?${q}`, {\n signal,\n headers: { accept: \"application/json\" },\n });\n if (!res.ok) throw new GeocoderError(res.status, `geocode ${res.status} on ${path}`);\n const body = (await res.json()) as { results?: GeocodeResult[] } | GeocodeResult[];\n return Array.isArray(body) ? body : (body.results ?? []);\n }\n}\n\nfunction toParams(o: SearchOptions): Record<string, string | undefined> {\n return {\n limit: o.limit != null ? String(o.limit) : undefined,\n lang: o.lang,\n bbox: o.bbox ? o.bbox.join(\",\") : undefined,\n };\n}\n"],"mappings":";AAAA,SAAS,uBAAuB;AAqCzB,IAAM,gBAAN,cAA4B,MAAM;AAAA,EACvC,YACkB,QAChB,SACA;AACA,UAAM,OAAO;AAHG;AAIhB,SAAK,OAAO;AAAA,EACd;AAAA,EALkB;AAMpB;AAGO,IAAM,WAAN,MAAe;AAAA,EACH;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,MAAuB;AACjC,SAAK,MAAM,KAAK;AAChB,SAAK,QAAQ,KAAK,WAAW,iBAAiB,QAAQ,QAAQ,EAAE;AAIhE,SAAK,YAAY,KAAK,SAAS,WAAW,MAAM,KAAK,UAAU;AAAA,EACjE;AAAA;AAAA,EAGA,OAAO,GAAW,OAAsB,CAAC,GAA6B;AACpE,WAAO,KAAK,MAAM,mBAAmB,EAAE,GAAG,GAAG,SAAS,IAAI,EAAE,GAAG,KAAK,MAAM;AAAA,EAC5E;AAAA;AAAA,EAGA,aAAa,GAAW,OAAsB,CAAC,GAA6B;AAC1E,WAAO,KAAK,MAAM,yBAAyB,EAAE,GAAG,GAAG,SAAS,IAAI,EAAE,GAAG,KAAK,MAAM;AAAA,EAClF;AAAA;AAAA,EAGA,QACE,KACA,KACA,OAAgD,CAAC,GACvB;AAC1B,WAAO,KAAK;AAAA,MACV;AAAA,MACA,EAAE,KAAK,OAAO,GAAG,GAAG,KAAK,OAAO,GAAG,GAAG,MAAM,KAAK,KAAK;AAAA,MACtD,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEA,MAAc,MACZ,MACA,QACA,QAC0B;AAC1B,UAAM,IAAI,IAAI,gBAAgB,EAAE,KAAK,KAAK,IAAI,CAAC;AAC/C,eAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,EAAG,KAAI,KAAK,QAAQ,MAAM,GAAI,GAAE,IAAI,GAAG,CAAC;AAClF,UAAM,MAAM,MAAM,KAAK,UAAU,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI;AAAA,MAC3D;AAAA,MACA,SAAS,EAAE,QAAQ,mBAAmB;AAAA,IACxC,CAAC;AACD,QAAI,CAAC,IAAI,GAAI,OAAM,IAAI,cAAc,IAAI,QAAQ,WAAW,IAAI,MAAM,OAAO,IAAI,EAAE;AACnF,UAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,WAAO,MAAM,QAAQ,IAAI,IAAI,OAAQ,KAAK,WAAW,CAAC;AAAA,EACxD;AACF;AAEA,SAAS,SAAS,GAAsD;AACtE,SAAO;AAAA,IACL,OAAO,EAAE,SAAS,OAAO,OAAO,EAAE,KAAK,IAAI;AAAA,IAC3C,MAAM,EAAE;AAAA,IACR,MAAM,EAAE,OAAO,EAAE,KAAK,KAAK,GAAG,IAAI;AAAA,EACpC;AACF;","names":[]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@unmap/geocoding",
3
+ "version": "0.0.1",
4
+ "description": "Typed client for the unmap geocoding API",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "dependencies": {
23
+ "@unmap/core": "0.0.1"
24
+ },
25
+ "devDependencies": {
26
+ "tsup": "^8.3.0",
27
+ "typescript": "^5.6.0",
28
+ "vitest": "^2.1.0"
29
+ },
30
+ "scripts": {
31
+ "build": "tsup",
32
+ "test": "vitest run",
33
+ "typecheck": "tsc --noEmit"
34
+ }
35
+ }