@seta-labs/geo 0.1.0 → 0.3.0
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/CHANGELOG.md +17 -0
- package/README.md +13 -2
- package/dist/index.d.ts +158 -9
- package/dist/index.js +19 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @seta-labs/geo
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
- `geocode`, `geocodeBatch`, `reverseGeocode` and `cadastreParcel` take
|
|
6
|
+
`cache: { refresh, noStore, maxAge, onlyIfCached }`, sent as
|
|
7
|
+
`Cache-Control` (`no-cache`, `no-store`, `max-age`, `only-if-cached`).
|
|
8
|
+
Without it nothing changes. New types `LookupCache` and `LookupOptions`.
|
|
9
|
+
- A lookup refused by `onlyIfCached` rejects with `ApiError` 504
|
|
10
|
+
(`code: 'NOT_CACHED'`); a batch item has `status: 'NOT_CACHED'`.
|
|
11
|
+
|
|
12
|
+
## 0.2.0
|
|
13
|
+
|
|
14
|
+
- New `cadastreParcel({ lat, lng })` on `POST /cadastre/parcel`: what the AdE
|
|
15
|
+
cadastral map finds under a point (`tipologia`, the cadastral fields with
|
|
16
|
+
blanks cleared, the `raw` answer), served from the shared store when known.
|
|
17
|
+
A `503` with `code: 'CADASTRE_BLOCKED'` carries `Retry-After`.
|
|
18
|
+
- New type aliases `CadastreParcelRequest` and `CadastreParcelResult`.
|
|
19
|
+
|
|
3
20
|
## 0.1.0
|
|
4
21
|
|
|
5
22
|
- Promote the SDK from `0.1.0-next.1` to the ordinary `latest` npm channel.
|
package/README.md
CHANGED
|
@@ -49,6 +49,7 @@ retain their own concurrency and retry policy.
|
|
|
49
49
|
| `geocode` | `GeocodeRequest` |
|
|
50
50
|
| `geocodeBatch` | `GeocodeBatchRequest` |
|
|
51
51
|
| `reverseGeocode` | `ReverseGeocodeRequest` |
|
|
52
|
+
| `cadastreParcel` | `CadastreParcelRequest` |
|
|
52
53
|
| `territory.status`, `territory.datasets` | options only |
|
|
53
54
|
| `territory.comuni` | optional `TerritoryComuniQuery` |
|
|
54
55
|
| `territory.quotazioni` | optional `TerritoryQuotazioniQuery` |
|
|
@@ -57,14 +58,24 @@ retain their own concurrency and retry policy.
|
|
|
57
58
|
| `territory.resolve` | `TerritoryResolveRequest` |
|
|
58
59
|
|
|
59
60
|
The package exports `createGeoClient`, `ApiError`, client/options interfaces,
|
|
60
|
-
query types and the generated geocode/territory request and response aliases.
|
|
61
|
+
query types and the generated geocode/cadastre/territory request and response aliases.
|
|
61
62
|
The three service health routes are intentionally outside this SDK surface.
|
|
62
63
|
OpenAPI remains authoritative: TypeScript provides static types, not runtime
|
|
63
64
|
validation of received data. `include` may be omitted and defaults to `best`
|
|
64
65
|
on the service.
|
|
65
66
|
|
|
67
|
+
The four lookups (`geocode`, `geocodeBatch`, `reverseGeocode`,
|
|
68
|
+
`cadastreParcel`) take `cache` in their options, sent as `Cache-Control`:
|
|
69
|
+
`{ refresh: true }` asks the provider again and stores the new answer,
|
|
70
|
+
`{ refresh: true, noStore: true }` bypasses the store entirely, `{ maxAge }`
|
|
71
|
+
asks again past that many seconds, `{ onlyIfCached: true }` never asks the
|
|
72
|
+
provider (504 `NOT_CACHED`, or `status: 'NOT_CACHED'` for a batch item).
|
|
73
|
+
|
|
66
74
|
HTTP errors are `ApiError`; their body is JSON when parseable, otherwise text,
|
|
67
|
-
or `undefined` for an empty response.
|
|
75
|
+
or `undefined` for an empty response. A `503` from `cadastreParcel` with
|
|
76
|
+
`code: 'CADASTRE_BLOCKED'` means the cadastral map is refusing calls: its
|
|
77
|
+
`Retry-After` header (and `retryAfterSeconds` in the body) says when to ask
|
|
78
|
+
again. Network failures, aborts and JSON parsing
|
|
68
79
|
errors retain their native types. Every Geo success operation requires a JSON
|
|
69
80
|
result: an unexpected empty/204 success raises `SyntaxError`. The SDK logs no
|
|
70
81
|
body, URL or credential automatically.
|
package/dist/index.d.ts
CHANGED
|
@@ -111,6 +111,22 @@ interface paths {
|
|
|
111
111
|
patch?: never;
|
|
112
112
|
trace?: never;
|
|
113
113
|
};
|
|
114
|
+
'/cadastre/parcel': {
|
|
115
|
+
parameters: {
|
|
116
|
+
query?: never;
|
|
117
|
+
header?: never;
|
|
118
|
+
path?: never;
|
|
119
|
+
cookie?: never;
|
|
120
|
+
};
|
|
121
|
+
get?: never;
|
|
122
|
+
put?: never;
|
|
123
|
+
post: operations['CadastreController_parcel'];
|
|
124
|
+
delete?: never;
|
|
125
|
+
options?: never;
|
|
126
|
+
head?: never;
|
|
127
|
+
patch?: never;
|
|
128
|
+
trace?: never;
|
|
129
|
+
};
|
|
114
130
|
'/territory/status': {
|
|
115
131
|
parameters: {
|
|
116
132
|
query?: never;
|
|
@@ -339,8 +355,11 @@ interface components {
|
|
|
339
355
|
include?: 'best' | 'full';
|
|
340
356
|
};
|
|
341
357
|
GeocodeResultDto: {
|
|
342
|
-
/**
|
|
343
|
-
|
|
358
|
+
/**
|
|
359
|
+
* @description NOT_CACHED: a batch item refused by Cache-Control only-if-cached.
|
|
360
|
+
* @enum {string}
|
|
361
|
+
*/
|
|
362
|
+
status: 'OK' | 'NO_RESULT' | 'INVALID_QUERY' | 'NOT_CACHED';
|
|
344
363
|
/** @description The normalized query actually used as cache key and provider input. */
|
|
345
364
|
query: string | null;
|
|
346
365
|
lat: number | null;
|
|
@@ -390,6 +409,36 @@ interface components {
|
|
|
390
409
|
[key: string]: unknown;
|
|
391
410
|
}[] | null;
|
|
392
411
|
};
|
|
412
|
+
CadastreParcelRequestDto: {
|
|
413
|
+
lat: number;
|
|
414
|
+
lng: number;
|
|
415
|
+
};
|
|
416
|
+
CadastreParcelResultDto: {
|
|
417
|
+
/** @description Canonical cache key: "lat,lng" rounded to 5 decimals (~1 m). */
|
|
418
|
+
query: string;
|
|
419
|
+
/**
|
|
420
|
+
* @description What lies under the point, verbatim from the map: PARTICELLA, STRADA, …
|
|
421
|
+
* @example PARTICELLA
|
|
422
|
+
*/
|
|
423
|
+
tipologia: string;
|
|
424
|
+
/** @example B885 */
|
|
425
|
+
codComune: string | null;
|
|
426
|
+
/** @description Null when the map gives none: blanks and "null" strings are cleared. */
|
|
427
|
+
sezione: string | null;
|
|
428
|
+
/** @example 36 */
|
|
429
|
+
foglio: string | null;
|
|
430
|
+
/** @example G */
|
|
431
|
+
allegato: string | null;
|
|
432
|
+
sviluppo: string | null;
|
|
433
|
+
/** @example 5101 */
|
|
434
|
+
particella: string | null;
|
|
435
|
+
/** @description The map answer exactly as returned (blank SEZIONE and "null" strings included). */
|
|
436
|
+
raw: {
|
|
437
|
+
[key: string]: unknown;
|
|
438
|
+
};
|
|
439
|
+
/** @description True when the answer came from the cache, no map call. */
|
|
440
|
+
cached: boolean;
|
|
441
|
+
};
|
|
393
442
|
TerritoryStatusDto: {
|
|
394
443
|
/** @description Latest OMI publication loaded (`YYYY-S`), null while no supply is loaded. */
|
|
395
444
|
semestre: string | null;
|
|
@@ -606,7 +655,10 @@ interface operations {
|
|
|
606
655
|
GeocodeController_geocode: {
|
|
607
656
|
parameters: {
|
|
608
657
|
query?: never;
|
|
609
|
-
header?:
|
|
658
|
+
header?: {
|
|
659
|
+
/** @description no-cache: ask the provider and store its answer; no-store: never write the store; max-age=N: a stored answer older than N seconds is asked again; only-if-cached: never ask the provider. The response says what happened in Cache-Status (hit, fwd=miss|request|stale, stored) and, on a hit, Age. */
|
|
660
|
+
'Cache-Control'?: string;
|
|
661
|
+
};
|
|
610
662
|
path?: never;
|
|
611
663
|
cookie?: never;
|
|
612
664
|
};
|
|
@@ -638,12 +690,22 @@ interface operations {
|
|
|
638
690
|
};
|
|
639
691
|
content?: never;
|
|
640
692
|
};
|
|
693
|
+
/** @description NOT_CACHED: only-if-cached and no usable stored answer. */
|
|
694
|
+
504: {
|
|
695
|
+
headers: {
|
|
696
|
+
[name: string]: unknown;
|
|
697
|
+
};
|
|
698
|
+
content?: never;
|
|
699
|
+
};
|
|
641
700
|
};
|
|
642
701
|
};
|
|
643
702
|
GeocodeController_geocodeBatch: {
|
|
644
703
|
parameters: {
|
|
645
704
|
query?: never;
|
|
646
|
-
header?:
|
|
705
|
+
header?: {
|
|
706
|
+
/** @description Applies to every item: no-cache, no-store, max-age=N, only-if-cached. An item only-if-cached refuses has status NOT_CACHED; the batch still answers 200. */
|
|
707
|
+
'Cache-Control'?: string;
|
|
708
|
+
};
|
|
647
709
|
path?: never;
|
|
648
710
|
cookie?: never;
|
|
649
711
|
};
|
|
@@ -680,7 +742,10 @@ interface operations {
|
|
|
680
742
|
GeocodeController_reverseGeocode: {
|
|
681
743
|
parameters: {
|
|
682
744
|
query?: never;
|
|
683
|
-
header?:
|
|
745
|
+
header?: {
|
|
746
|
+
/** @description no-cache: ask the provider and store its answer; no-store: never write the store; max-age=N: a stored answer older than N seconds is asked again; only-if-cached: never ask the provider. The response says what happened in Cache-Status (hit, fwd=miss|request|stale, stored) and, on a hit, Age. */
|
|
747
|
+
'Cache-Control'?: string;
|
|
748
|
+
};
|
|
684
749
|
path?: never;
|
|
685
750
|
cookie?: never;
|
|
686
751
|
};
|
|
@@ -712,6 +777,68 @@ interface operations {
|
|
|
712
777
|
};
|
|
713
778
|
content?: never;
|
|
714
779
|
};
|
|
780
|
+
/** @description NOT_CACHED: only-if-cached and no usable stored answer. */
|
|
781
|
+
504: {
|
|
782
|
+
headers: {
|
|
783
|
+
[name: string]: unknown;
|
|
784
|
+
};
|
|
785
|
+
content?: never;
|
|
786
|
+
};
|
|
787
|
+
};
|
|
788
|
+
};
|
|
789
|
+
CadastreController_parcel: {
|
|
790
|
+
parameters: {
|
|
791
|
+
query?: never;
|
|
792
|
+
header?: {
|
|
793
|
+
/** @description no-cache: ask the provider and store its answer; no-store: never write the store; max-age=N: a stored answer older than N seconds is asked again; only-if-cached: never ask the provider. The response says what happened in Cache-Status (hit, fwd=miss|request|stale, stored) and, on a hit, Age. */
|
|
794
|
+
'Cache-Control'?: string;
|
|
795
|
+
};
|
|
796
|
+
path?: never;
|
|
797
|
+
cookie?: never;
|
|
798
|
+
};
|
|
799
|
+
requestBody: {
|
|
800
|
+
content: {
|
|
801
|
+
'application/json': components['schemas']['CadastreParcelRequestDto'];
|
|
802
|
+
};
|
|
803
|
+
};
|
|
804
|
+
responses: {
|
|
805
|
+
/** @description What the AdE cadastral map finds under the point: a parcel, a street, … */
|
|
806
|
+
200: {
|
|
807
|
+
headers: {
|
|
808
|
+
[name: string]: unknown;
|
|
809
|
+
};
|
|
810
|
+
content: {
|
|
811
|
+
'application/json': components['schemas']['CadastreParcelResultDto'];
|
|
812
|
+
};
|
|
813
|
+
};
|
|
814
|
+
/** @description Missing or invalid API key. */
|
|
815
|
+
401: {
|
|
816
|
+
headers: {
|
|
817
|
+
[name: string]: unknown;
|
|
818
|
+
};
|
|
819
|
+
content?: never;
|
|
820
|
+
};
|
|
821
|
+
/** @description CADASTRE_UNAVAILABLE or CADASTRE_INVALID_REPLY: the map gave no answer. */
|
|
822
|
+
502: {
|
|
823
|
+
headers: {
|
|
824
|
+
[name: string]: unknown;
|
|
825
|
+
};
|
|
826
|
+
content?: never;
|
|
827
|
+
};
|
|
828
|
+
/** @description CADASTRE_BLOCKED: the map is refusing calls; Retry-After says when to try again. */
|
|
829
|
+
503: {
|
|
830
|
+
headers: {
|
|
831
|
+
[name: string]: unknown;
|
|
832
|
+
};
|
|
833
|
+
content?: never;
|
|
834
|
+
};
|
|
835
|
+
/** @description NOT_CACHED: only-if-cached and no usable stored answer. */
|
|
836
|
+
504: {
|
|
837
|
+
headers: {
|
|
838
|
+
[name: string]: unknown;
|
|
839
|
+
};
|
|
840
|
+
content?: never;
|
|
841
|
+
};
|
|
715
842
|
};
|
|
716
843
|
};
|
|
717
844
|
TerritoryController_status: {
|
|
@@ -951,6 +1078,8 @@ type GeocodeResult = ApiSchemas['GeocodeResultDto'];
|
|
|
951
1078
|
type GeocodeBatchResponse = ApiSchemas['GeocodeBatchResponseDto'];
|
|
952
1079
|
type ReverseGeocodeRequest = ApiSchemas['ReverseGeocodeRequestDto'];
|
|
953
1080
|
type ReverseGeocodeResult = ApiSchemas['ReverseGeocodeResultDto'];
|
|
1081
|
+
type CadastreParcelRequest = ApiSchemas['CadastreParcelRequestDto'];
|
|
1082
|
+
type CadastreParcelResult = ApiSchemas['CadastreParcelResultDto'];
|
|
954
1083
|
type TerritoryStatus = ApiSchemas['TerritoryStatusDto'];
|
|
955
1084
|
type TerritoryResolveRequest = ApiSchemas['TerritoryResolveRequestDto'];
|
|
956
1085
|
type TerritoryResolveResponse = ApiSchemas['TerritoryResolveResponseDto'];
|
|
@@ -972,6 +1101,23 @@ type TerritoryCompravenditeQuery = NonNullable<ApiPaths['/territory/compravendit
|
|
|
972
1101
|
interface RequestOptions {
|
|
973
1102
|
signal?: AbortSignal;
|
|
974
1103
|
}
|
|
1104
|
+
/**
|
|
1105
|
+
* How a lookup may use seta-geo's store, sent as `Cache-Control` (RFC 9111).
|
|
1106
|
+
* Without it the store answers when it can and the provider otherwise.
|
|
1107
|
+
*/
|
|
1108
|
+
interface LookupCache {
|
|
1109
|
+
/** `no-cache`: ask the provider even with a stored answer, and store the new one. */
|
|
1110
|
+
refresh?: boolean;
|
|
1111
|
+
/** `no-store`: never write the provider's answer (with `refresh`: a pure bypass). */
|
|
1112
|
+
noStore?: boolean;
|
|
1113
|
+
/** `max-age`: a stored answer older than this many seconds is asked again. */
|
|
1114
|
+
maxAge?: number;
|
|
1115
|
+
/** `only-if-cached`: never ask the provider; 504 `NOT_CACHED` without a stored answer. */
|
|
1116
|
+
onlyIfCached?: boolean;
|
|
1117
|
+
}
|
|
1118
|
+
interface LookupOptions extends RequestOptions {
|
|
1119
|
+
cache?: LookupCache;
|
|
1120
|
+
}
|
|
975
1121
|
interface GeoClientOptions {
|
|
976
1122
|
/** Complete API root, including /api. Relative roots are supported in browsers. */
|
|
977
1123
|
baseUrl: string;
|
|
@@ -990,13 +1136,16 @@ interface TerritoryClient {
|
|
|
990
1136
|
resolve(input: TerritoryResolveRequest, options?: RequestOptions): Promise<TerritoryResolveResponse>;
|
|
991
1137
|
}
|
|
992
1138
|
interface GeoClient {
|
|
993
|
-
geocode(input: GeocodeRequest, options?:
|
|
994
|
-
|
|
995
|
-
|
|
1139
|
+
geocode(input: GeocodeRequest, options?: LookupOptions): Promise<GeocodeResult>;
|
|
1140
|
+
/** `cache` applies to every item; an item only-if-cached refuses has status NOT_CACHED. */
|
|
1141
|
+
geocodeBatch(input: GeocodeBatchRequest, options?: LookupOptions): Promise<GeocodeBatchResponse>;
|
|
1142
|
+
reverseGeocode(input: ReverseGeocodeRequest, options?: LookupOptions): Promise<ReverseGeocodeResult>;
|
|
1143
|
+
/** What the AdE cadastral map finds under a point; 503 `CADASTRE_BLOCKED` carries Retry-After. */
|
|
1144
|
+
cadastreParcel(input: CadastreParcelRequest, options?: LookupOptions): Promise<CadastreParcelResult>;
|
|
996
1145
|
territory: TerritoryClient;
|
|
997
1146
|
}
|
|
998
1147
|
|
|
999
1148
|
declare function createGeoClient(options: GeoClientOptions): GeoClient;
|
|
1000
1149
|
|
|
1001
1150
|
export { ApiError, createGeoClient };
|
|
1002
|
-
export type { GeoClient, GeoClientOptions, GeocodeBatchRequest, GeocodeBatchResponse, GeocodeRequest, GeocodeResult, RequestOptions, ReverseGeocodeRequest, ReverseGeocodeResult, TerritoryClient, TerritoryCompravendita, TerritoryCompravenditePage, TerritoryCompravenditeQuery, TerritoryComune, TerritoryComuneDetail, TerritoryComuneRiga, TerritoryComuniPage, TerritoryComuniQuery, TerritoryDatasets, TerritoryOmi, TerritoryPointResult, TerritoryQuotazione, TerritoryQuotazioniPage, TerritoryQuotazioniQuery, TerritoryResolveRequest, TerritoryResolveResponse, TerritoryStatus };
|
|
1151
|
+
export type { CadastreParcelRequest, CadastreParcelResult, GeoClient, GeoClientOptions, GeocodeBatchRequest, GeocodeBatchResponse, GeocodeRequest, GeocodeResult, LookupCache, LookupOptions, RequestOptions, ReverseGeocodeRequest, ReverseGeocodeResult, TerritoryClient, TerritoryCompravendita, TerritoryCompravenditePage, TerritoryCompravenditeQuery, TerritoryComune, TerritoryComuneDetail, TerritoryComuneRiga, TerritoryComuniPage, TerritoryComuniQuery, TerritoryDatasets, TerritoryOmi, TerritoryPointResult, TerritoryQuotazione, TerritoryQuotazioniPage, TerritoryQuotazioniQuery, TerritoryResolveRequest, TerritoryResolveResponse, TerritoryStatus };
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,21 @@ async function data(request) {
|
|
|
39
39
|
if (result.data === void 0) throw new SyntaxError("Geo API returned an empty JSON response");
|
|
40
40
|
return result.data;
|
|
41
41
|
}
|
|
42
|
+
function cacheControl(cache) {
|
|
43
|
+
if (!cache) return void 0;
|
|
44
|
+
const directives = [
|
|
45
|
+
cache.refresh ? "no-cache" : void 0,
|
|
46
|
+
cache.noStore ? "no-store" : void 0,
|
|
47
|
+
cache.maxAge === void 0 ? void 0 : `max-age=${Math.max(0, Math.floor(cache.maxAge))}`,
|
|
48
|
+
cache.onlyIfCached ? "only-if-cached" : void 0
|
|
49
|
+
].filter((directive) => directive !== void 0);
|
|
50
|
+
return directives.length > 0 ? directives.join(", ") : void 0;
|
|
51
|
+
}
|
|
52
|
+
function lookupInit(options) {
|
|
53
|
+
const { cache, ...request } = options ?? {};
|
|
54
|
+
const header = cacheControl(cache);
|
|
55
|
+
return header ? { ...request, headers: { "cache-control": header } } : request;
|
|
56
|
+
}
|
|
42
57
|
function territory(client) {
|
|
43
58
|
return {
|
|
44
59
|
status: (options) => data(client.GET("/territory/status", { ...options })),
|
|
@@ -67,9 +82,10 @@ function createGeoClient(options) {
|
|
|
67
82
|
}
|
|
68
83
|
});
|
|
69
84
|
return {
|
|
70
|
-
geocode: (input, request) => data(client.POST("/geocode", { ...request, body: input })),
|
|
71
|
-
geocodeBatch: (input, request) => data(client.POST("/geocode/batch", { ...request, body: input })),
|
|
72
|
-
reverseGeocode: (input, request) => data(client.POST("/geocode/reverse", { ...request, body: input })),
|
|
85
|
+
geocode: (input, request) => data(client.POST("/geocode", { ...lookupInit(request), body: input })),
|
|
86
|
+
geocodeBatch: (input, request) => data(client.POST("/geocode/batch", { ...lookupInit(request), body: input })),
|
|
87
|
+
reverseGeocode: (input, request) => data(client.POST("/geocode/reverse", { ...lookupInit(request), body: input })),
|
|
88
|
+
cadastreParcel: (input, request) => data(client.POST("/cadastre/parcel", { ...lookupInit(request), body: input })),
|
|
73
89
|
territory: territory(client)
|
|
74
90
|
};
|
|
75
91
|
}
|