@tileflow/search 0.1.0-alpha.0 → 0.1.0-alpha.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 +116 -78
- package/dist/contract.d.ts +17 -17
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,23 +1,63 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @tileflow/search
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Forward and reverse geocoding, location suggestions, and selected-suggestion resolution. This is a
|
|
4
|
+
headless client: it provides no search box, map control, address validation, category discovery, or
|
|
5
|
+
batch interface.
|
|
6
|
+
|
|
7
|
+
> Related packages and guides: [documentation index](https://raw.githubusercontent.com/tileflow/tileflow-sdk/main/llms.txt).
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install @tileflow/search@alpha
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use a runtime with `fetch`, such as Node.js 22 or newer. Live requests need an enabled Tileflow
|
|
16
|
+
Geocoding service and a Team key or signed Team capability with `geocoding:read`. Installing the
|
|
17
|
+
package does not enable that service. Keep privileged credentials on your server; a browser UI
|
|
18
|
+
should call your own authorized endpoint.
|
|
19
|
+
|
|
20
|
+
## Find a place
|
|
21
|
+
|
|
22
|
+
Run this in a trusted server process with `TILEFLOW_API_KEY` set securely:
|
|
23
|
+
|
|
24
|
+
<!-- docs:check -->
|
|
4
25
|
|
|
5
26
|
```ts
|
|
6
|
-
import {geocode} from '@tileflow/search';
|
|
27
|
+
import {GeocodingError, geocode} from '@tileflow/search';
|
|
7
28
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
{apiKey: process.env.TILEFLOW_API_KEY!},
|
|
11
|
-
);
|
|
29
|
+
const apiKey = process.env.TILEFLOW_API_KEY;
|
|
30
|
+
if (!apiKey) throw new Error('Set TILEFLOW_API_KEY on the server.');
|
|
12
31
|
|
|
13
|
-
|
|
32
|
+
try {
|
|
33
|
+
const response = await geocode(
|
|
34
|
+
{query: 'Praça do Comércio, Lisboa', language: 'en', retention: 'temporary'},
|
|
35
|
+
{apiKey, signal: AbortSignal.timeout(5000)},
|
|
36
|
+
);
|
|
37
|
+
console.log(response.results);
|
|
38
|
+
console.log(response.source, response.attribution);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (!(error instanceof GeocodingError)) throw error;
|
|
41
|
+
console.error(error.code, error.status, error.requestId);
|
|
42
|
+
}
|
|
14
43
|
```
|
|
15
44
|
|
|
16
|
-
|
|
45
|
+
A successful response may have no results. Present all returned attribution entries alongside
|
|
46
|
+
results, preserving any supplied URLs. A source revision of `null` means no reliable revision is
|
|
47
|
+
available, not that provenance can be invented or omitted.
|
|
48
|
+
|
|
49
|
+
## Reverse-geocode a position
|
|
50
|
+
|
|
51
|
+
Positions use WGS84 `[longitude, latitude]`, not `[latitude, longitude]`:
|
|
52
|
+
|
|
53
|
+
<!-- docs:check -->
|
|
17
54
|
|
|
18
55
|
```ts
|
|
19
56
|
import {geocodeReverse} from '@tileflow/search';
|
|
20
57
|
|
|
58
|
+
const apiKey = process.env.TILEFLOW_API_KEY;
|
|
59
|
+
if (!apiKey) throw new Error('Set TILEFLOW_API_KEY on the server.');
|
|
60
|
+
|
|
21
61
|
const response = await geocodeReverse(
|
|
22
62
|
{
|
|
23
63
|
position: [-9.1393, 38.7223],
|
|
@@ -25,83 +65,81 @@ const response = await geocodeReverse(
|
|
|
25
65
|
language: 'en',
|
|
26
66
|
retention: 'temporary',
|
|
27
67
|
},
|
|
28
|
-
{apiKey
|
|
68
|
+
{apiKey},
|
|
29
69
|
);
|
|
70
|
+
|
|
71
|
+
console.log(response.results, response.attribution);
|
|
30
72
|
```
|
|
31
73
|
|
|
32
|
-
|
|
74
|
+
Results are nearby candidates in provider order. They do not establish containment, administrative
|
|
75
|
+
membership, parcel or entrance precision, routability, deliverability, or address validity.
|
|
76
|
+
`kinds` is an OR filter with 1–4 values from `address`, `street`, `locality`, and `place`; ordering
|
|
77
|
+
adds no priority. Reverse `limit` defaults to 1 and accepts 1–10.
|
|
78
|
+
|
|
79
|
+
## Resolve a user-selected suggestion
|
|
80
|
+
|
|
81
|
+
The server-side example returns suggestions first and exposes a separate selection handler:
|
|
82
|
+
|
|
83
|
+
<!-- docs:check -->
|
|
33
84
|
|
|
34
85
|
```ts
|
|
35
86
|
import {autocomplete, resolveSuggestion} from '@tileflow/search';
|
|
36
87
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
);
|
|
88
|
+
const apiKey = process.env.TILEFLOW_API_KEY;
|
|
89
|
+
if (!apiKey) throw new Error('Set TILEFLOW_API_KEY on the server.');
|
|
90
|
+
const options = {apiKey};
|
|
41
91
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
47
|
-
|
|
92
|
+
const response = await autocomplete({query: 'Hospital La Paz', language: 'en'}, options);
|
|
93
|
+
console.log(response.suggestions, response.attribution);
|
|
94
|
+
|
|
95
|
+
export async function resolveUserSelection(token: string) {
|
|
96
|
+
const resolved = await resolveSuggestion({token, retention: 'temporary'}, options);
|
|
97
|
+
return {result: resolved.result, source: resolved.source, attribution: resolved.attribution};
|
|
48
98
|
}
|
|
49
99
|
```
|
|
50
100
|
|
|
51
|
-
Call `resolveUserSelection` only after
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
`GEOCODING_SUGGESTION_EXPIRED` (410), `GEOCODING_UPSTREAM_THROTTLED` (429), or
|
|
97
|
-
`GEOCODING_PICK_LIMIT_EXCEEDED` (429). The client never retries automatically.
|
|
98
|
-
|
|
99
|
-
Responses include source metadata and one or more attribution entries. Applications must pass every
|
|
100
|
-
entry through to end users or documentation and preserve any supplied URL as required by its source
|
|
101
|
-
terms. A source revision may be `null` when no reliable revision is available.
|
|
102
|
-
|
|
103
|
-
The package does not provide autocomplete UI, structured address input, category discovery,
|
|
104
|
-
batches, or address validation.
|
|
105
|
-
|
|
106
|
-
Use `@tileflow/search/contract` for the request and result schemas, or
|
|
107
|
-
`@tileflow/search/client` for transport without importing the root facade.
|
|
101
|
+
Call `resolveUserSelection` only after explicit selection. Do not automatically resolve every
|
|
102
|
+
suggestion. Tokens are opaque and ephemeral; an expired token needs fresh suggestions. Suggestions
|
|
103
|
+
do not guarantee a match for every place and are not category or discovery queries.
|
|
104
|
+
|
|
105
|
+
Debounce input and cancel superseded requests, or ignore stale results. The client owns no shared
|
|
106
|
+
interaction state. Autocomplete rejects `retention`, returns no usage record, and consumes zero
|
|
107
|
+
units. Each completed resolution reports one unit; replaying it is another operation, not a retry
|
|
108
|
+
of an idempotent request.
|
|
109
|
+
|
|
110
|
+
## Request limits and retention
|
|
111
|
+
|
|
112
|
+
Forward queries contain at most 200 characters. Forward and autocomplete `limit` default to 5 and
|
|
113
|
+
accept 1–10. `bounds` and `proximity` are mutually exclusive. Bounds use
|
|
114
|
+
`[west, south, east, north]` with west less than east and south less than north; do not pass a wrapped
|
|
115
|
+
antimeridian box. Provider selection and raw provider options are not public controls.
|
|
116
|
+
|
|
117
|
+
`retention` accepts `temporary` (default) or `persistent` for forward, reverse, and resolution.
|
|
118
|
+
Temporary results are for immediate use, without a right granted by Tileflow to retain them
|
|
119
|
+
permanently. Persistent mode requests compatible storage rights; it does not request or promise
|
|
120
|
+
Tileflow storage. Only retain a resolved candidate with its source and attribution, not suggestion
|
|
121
|
+
tokens or labels.
|
|
122
|
+
|
|
123
|
+
Persistent retention is unavailable in some territories. `GEOCODING_TERRITORY_UNSUPPORTED` (422)
|
|
124
|
+
means the requested mode is unsupported, including AWS HERE-backed geocoding in Japan. It applies
|
|
125
|
+
to forward, reverse, and resolution, not autocomplete. Follow the returned source terms rather
|
|
126
|
+
than treating an SDK option as a blanket storage license.
|
|
127
|
+
|
|
128
|
+
## Handle failures and usage
|
|
129
|
+
|
|
130
|
+
Requests and normalized responses are strictly bounded. The client never retries automatically.
|
|
131
|
+
Use `signal` to cancel work and `fetch` or `apiUrl` for tests. API URLs require HTTPS except for an
|
|
132
|
+
explicit loopback HTTP origin during development.
|
|
133
|
+
|
|
134
|
+
Hosted errors throw `GeocodingError` with `status`, nullable `code`, and nullable `requestId`.
|
|
135
|
+
Invalid local inputs and malformed remote documents can throw ordinary errors. A disabled service
|
|
136
|
+
reports `GEOCODING_DISABLED`. Suggestion failures include `GEOCODING_INVALID_SUGGESTION` (400),
|
|
137
|
+
`GEOCODING_SUGGESTION_EXPIRED` (410), `GEOCODING_UPSTREAM_THROTTLED` (429), and
|
|
138
|
+
`GEOCODING_PICK_LIMIT_EXCEEDED` (429). Refresh an expired suggestion rather than replaying its token.
|
|
139
|
+
|
|
140
|
+
`GEOCODING_USAGE_UNCONFIRMED` means completion may already have been charged; do not automatically
|
|
141
|
+
repeat the request. Each completed forward or reverse request reports one unit, including an empty
|
|
142
|
+
result; completed resolution also reports one. These are usage units, not monetary prices.
|
|
143
|
+
|
|
144
|
+
Use `@tileflow/search/contract` for schemas and `@tileflow/search/client` for transport. For a
|
|
145
|
+
published release, its installed README and declarations take precedence over newer source on `main`.
|
package/dist/contract.d.ts
CHANGED
|
@@ -24,8 +24,8 @@ declare const geocodingForwardRequestSchema: z.ZodObject<{
|
|
|
24
24
|
proximity: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
|
|
25
25
|
query: z.ZodString;
|
|
26
26
|
retention: z.ZodDefault<z.ZodEnum<{
|
|
27
|
-
temporary: "temporary";
|
|
28
27
|
persistent: "persistent";
|
|
28
|
+
temporary: "temporary";
|
|
29
29
|
}>>;
|
|
30
30
|
}, z.core.$strict>;
|
|
31
31
|
declare const autocompleteRequestSchema: z.ZodObject<{
|
|
@@ -38,22 +38,22 @@ declare const autocompleteRequestSchema: z.ZodObject<{
|
|
|
38
38
|
declare const reverseGeocodingKindSchema: z.ZodEnum<{
|
|
39
39
|
address: "address";
|
|
40
40
|
locality: "locality";
|
|
41
|
-
street: "street";
|
|
42
41
|
place: "place";
|
|
42
|
+
street: "street";
|
|
43
43
|
}>;
|
|
44
44
|
declare const geocodingReverseRequestSchema: z.ZodObject<{
|
|
45
45
|
kinds: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
46
46
|
address: "address";
|
|
47
47
|
locality: "locality";
|
|
48
|
-
street: "street";
|
|
49
48
|
place: "place";
|
|
49
|
+
street: "street";
|
|
50
50
|
}>>>;
|
|
51
51
|
language: z.ZodOptional<z.ZodString>;
|
|
52
52
|
limit: z.ZodDefault<z.ZodNumber>;
|
|
53
53
|
position: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
54
54
|
retention: z.ZodDefault<z.ZodEnum<{
|
|
55
|
-
temporary: "temporary";
|
|
56
55
|
persistent: "persistent";
|
|
56
|
+
temporary: "temporary";
|
|
57
57
|
}>>;
|
|
58
58
|
}, z.core.$strict>;
|
|
59
59
|
declare const geocodingResultKinds: readonly ["address", "street", "locality", "district", "county", "region", "country", "place", "unknown"];
|
|
@@ -86,15 +86,15 @@ declare const geocodingResultSchema: z.ZodObject<{
|
|
|
86
86
|
}, z.core.$strict>;
|
|
87
87
|
bounds: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
|
|
88
88
|
kind: z.ZodEnum<{
|
|
89
|
-
unknown: "unknown";
|
|
90
89
|
address: "address";
|
|
91
90
|
country: "country";
|
|
92
91
|
county: "county";
|
|
93
92
|
district: "district";
|
|
94
93
|
locality: "locality";
|
|
94
|
+
place: "place";
|
|
95
95
|
region: "region";
|
|
96
96
|
street: "street";
|
|
97
|
-
|
|
97
|
+
unknown: "unknown";
|
|
98
98
|
}>;
|
|
99
99
|
label: z.ZodString;
|
|
100
100
|
position: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
@@ -130,15 +130,15 @@ declare const geocodingForwardResponseSchema: z.ZodObject<{
|
|
|
130
130
|
}, z.core.$strict>;
|
|
131
131
|
bounds: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
|
|
132
132
|
kind: z.ZodEnum<{
|
|
133
|
-
unknown: "unknown";
|
|
134
133
|
address: "address";
|
|
135
134
|
country: "country";
|
|
136
135
|
county: "county";
|
|
137
136
|
district: "district";
|
|
138
137
|
locality: "locality";
|
|
138
|
+
place: "place";
|
|
139
139
|
region: "region";
|
|
140
140
|
street: "street";
|
|
141
|
-
|
|
141
|
+
unknown: "unknown";
|
|
142
142
|
}>;
|
|
143
143
|
label: z.ZodString;
|
|
144
144
|
position: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
@@ -175,15 +175,15 @@ declare const geocodingReverseResponseSchema: z.ZodObject<{
|
|
|
175
175
|
}, z.core.$strict>;
|
|
176
176
|
bounds: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
|
|
177
177
|
kind: z.ZodEnum<{
|
|
178
|
-
unknown: "unknown";
|
|
179
178
|
address: "address";
|
|
180
179
|
country: "country";
|
|
181
180
|
county: "county";
|
|
182
181
|
district: "district";
|
|
183
182
|
locality: "locality";
|
|
183
|
+
place: "place";
|
|
184
184
|
region: "region";
|
|
185
185
|
street: "street";
|
|
186
|
-
|
|
186
|
+
unknown: "unknown";
|
|
187
187
|
}>;
|
|
188
188
|
label: z.ZodString;
|
|
189
189
|
position: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
|
@@ -200,15 +200,15 @@ declare const geocodingReverseResponseSchema: z.ZodObject<{
|
|
|
200
200
|
}, z.core.$strict>;
|
|
201
201
|
declare const geocodingSuggestionSchema: z.ZodObject<{
|
|
202
202
|
kind: z.ZodEnum<{
|
|
203
|
-
unknown: "unknown";
|
|
204
203
|
address: "address";
|
|
205
204
|
country: "country";
|
|
206
205
|
county: "county";
|
|
207
206
|
district: "district";
|
|
208
207
|
locality: "locality";
|
|
208
|
+
place: "place";
|
|
209
209
|
region: "region";
|
|
210
210
|
street: "street";
|
|
211
|
-
|
|
211
|
+
unknown: "unknown";
|
|
212
212
|
}>;
|
|
213
213
|
label: z.ZodString;
|
|
214
214
|
token: z.ZodString;
|
|
@@ -225,15 +225,15 @@ declare const autocompleteResponseSchema: z.ZodObject<{
|
|
|
225
225
|
}, z.core.$strict>;
|
|
226
226
|
suggestions: z.ZodArray<z.ZodObject<{
|
|
227
227
|
kind: z.ZodEnum<{
|
|
228
|
-
unknown: "unknown";
|
|
229
228
|
address: "address";
|
|
230
229
|
country: "country";
|
|
231
230
|
county: "county";
|
|
232
231
|
district: "district";
|
|
233
232
|
locality: "locality";
|
|
233
|
+
place: "place";
|
|
234
234
|
region: "region";
|
|
235
235
|
street: "street";
|
|
236
|
-
|
|
236
|
+
unknown: "unknown";
|
|
237
237
|
}>;
|
|
238
238
|
label: z.ZodString;
|
|
239
239
|
token: z.ZodString;
|
|
@@ -241,8 +241,8 @@ declare const autocompleteResponseSchema: z.ZodObject<{
|
|
|
241
241
|
}, z.core.$strict>;
|
|
242
242
|
declare const resolveSuggestionRequestSchema: z.ZodObject<{
|
|
243
243
|
retention: z.ZodDefault<z.ZodEnum<{
|
|
244
|
-
temporary: "temporary";
|
|
245
244
|
persistent: "persistent";
|
|
245
|
+
temporary: "temporary";
|
|
246
246
|
}>>;
|
|
247
247
|
token: z.ZodString;
|
|
248
248
|
}, z.core.$strict>;
|
|
@@ -267,15 +267,15 @@ declare const resolveSuggestionResponseSchema: z.ZodObject<{
|
|
|
267
267
|
}, z.core.$strict>;
|
|
268
268
|
bounds: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
|
|
269
269
|
kind: z.ZodEnum<{
|
|
270
|
-
unknown: "unknown";
|
|
271
270
|
address: "address";
|
|
272
271
|
country: "country";
|
|
273
272
|
county: "county";
|
|
274
273
|
district: "district";
|
|
275
274
|
locality: "locality";
|
|
275
|
+
place: "place";
|
|
276
276
|
region: "region";
|
|
277
277
|
street: "street";
|
|
278
|
-
|
|
278
|
+
unknown: "unknown";
|
|
279
279
|
}>;
|
|
280
280
|
label: z.ZodString;
|
|
281
281
|
position: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/search",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Headless geocoding and location selection client and wire contracts for Tileflow.",
|
|
6
6
|
"type": "module",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"zod": "^4.4.3"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
|
-
"build": "tsup src/index.ts src/contract.ts src/client.ts --format esm --dts --clean --splitting",
|
|
54
|
+
"build": "tsup src/index.ts src/contract.ts src/client.ts --format esm --dts --clean --splitting && node ../../scripts/canonicalize-zod-enums.mjs dist",
|
|
55
55
|
"verify": "pnpm run build && tsx --test test/*.test.ts",
|
|
56
56
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
57
57
|
"lint": "tsc -p tsconfig.json --noEmit"
|