@latlng/sdk 0.1.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/LICENSE +21 -0
- package/README.md +343 -0
- package/dist/auth/token.d.ts +2 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/client.d.ts +385 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/errors/index.d.ts +66 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/http/routes.d.ts +41 -0
- package/dist/http/routes.d.ts.map +1 -0
- package/dist/http/transport.d.ts +26 -0
- package/dist/http/transport.d.ts.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1455 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/assert.d.ts +6 -0
- package/dist/internal/assert.d.ts.map +1 -0
- package/dist/internal/json.d.ts +3 -0
- package/dist/internal/json.d.ts.map +1 -0
- package/dist/internal/response-parsers.d.ts +26 -0
- package/dist/internal/response-parsers.d.ts.map +1 -0
- package/dist/routing/read-preference.d.ts +7 -0
- package/dist/routing/read-preference.d.ts.map +1 -0
- package/dist/routing/replicas.d.ts +22 -0
- package/dist/routing/replicas.d.ts.map +1 -0
- package/dist/types/events.d.ts +122 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/json.d.ts +7 -0
- package/dist/types/json.d.ts.map +1 -0
- package/dist/types/models.d.ts +408 -0
- package/dist/types/models.d.ts.map +1 -0
- package/dist/types/requests.d.ts +96 -0
- package/dist/types/requests.d.ts.map +1 -0
- package/dist/types/responses.d.ts +108 -0
- package/dist/types/responses.d.ts.map +1 -0
- package/dist/ws/socket.d.ts +66 -0
- package/dist/ws/socket.d.ts.map +1 -0
- package/dist/ws/subscriptions.d.ts +46 -0
- package/dist/ws/subscriptions.d.ts.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TobiLG <github@tobilg.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# latlng TypeScript SDK
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the `latlng` server.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
This package targets the current operational `latlng` HTTP and WebSocket surfaces.
|
|
8
|
+
|
|
9
|
+
Current scope:
|
|
10
|
+
|
|
11
|
+
- typed HTTP client for CRUD, search, admin/info, hooks, and channels
|
|
12
|
+
- typed WebSocket client for `auth`, `subscribe`, `psubscribe`, `ping`, and `quit`
|
|
13
|
+
- optional configuration-driven read routing across leader and follower URLs
|
|
14
|
+
- browser and Node support
|
|
15
|
+
|
|
16
|
+
Explicit non-goals:
|
|
17
|
+
|
|
18
|
+
- no Cap'n Proto client
|
|
19
|
+
- no server-side replication management
|
|
20
|
+
- no Worker-specific runtime bundle
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npm install @latlng/sdk
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quickstart
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { LatLngClient, point } from "@latlng/sdk";
|
|
32
|
+
|
|
33
|
+
const client = new LatLngClient({
|
|
34
|
+
leaderUrl: "http://127.0.0.1:7421",
|
|
35
|
+
token: "dev-token",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await client.setObject("fleet", "truck-1", point(52.52, 13.405));
|
|
39
|
+
const object = await client.get("fleet", "truck-1");
|
|
40
|
+
const nearby = await client.nearby("fleet", {
|
|
41
|
+
lat: 52.52,
|
|
42
|
+
lon: 13.405,
|
|
43
|
+
meters: 500,
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Collections can also be created explicitly and remain present even when empty until they are dropped:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
await client.createCollection("fleet");
|
|
51
|
+
const collection = await client.getCollection("fleet");
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Client Configuration
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const client = new LatLngClient({
|
|
58
|
+
leaderUrl: "http://127.0.0.1:7421",
|
|
59
|
+
token: "dev-token",
|
|
60
|
+
timeoutMs: 5_000,
|
|
61
|
+
headers: { "x-client": "worker-a" },
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Supported options:
|
|
66
|
+
|
|
67
|
+
| Option | Purpose |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `leaderUrl` | Base HTTP URL for the leader server. |
|
|
70
|
+
| `token` | Bearer token or JWT sent to HTTP and WebSocket requests. |
|
|
71
|
+
| `timeoutMs` | Per-request HTTP timeout. |
|
|
72
|
+
| `headers` | Extra headers merged into every HTTP request. |
|
|
73
|
+
| `fetch` | Custom fetch implementation for tests or custom runtimes. |
|
|
74
|
+
| `webSocketFactory` | Custom WebSocket factory for Node or tests. |
|
|
75
|
+
| `readReplicas` | Optional follower URLs used for eligible reads. |
|
|
76
|
+
| `readPreference` | One of `leader`, `leaderPreferred`, `followerPreferred`, or `roundRobinFollowers`. |
|
|
77
|
+
| `replicaStatusTtlMs` | Cache TTL for follower health/status probes. |
|
|
78
|
+
|
|
79
|
+
## API Surface
|
|
80
|
+
|
|
81
|
+
The SDK exposes the native HTTP API as typed methods on `LatLngClient`.
|
|
82
|
+
|
|
83
|
+
Connection and server status:
|
|
84
|
+
|
|
85
|
+
| Method | Description |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `ping()` | Check that the leader is reachable and authenticated. |
|
|
88
|
+
| `healthz()` | Read the health endpoint. |
|
|
89
|
+
| `server()` | Read server status, replication role, sequence, and version metadata. |
|
|
90
|
+
| `info(section?)` | Read the broader server info response. |
|
|
91
|
+
| `metrics()` | Read Prometheus text exposition metrics. |
|
|
92
|
+
|
|
93
|
+
Collections:
|
|
94
|
+
|
|
95
|
+
| Method | Description |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `collections(matchPattern?)` | List visible collections. |
|
|
98
|
+
| `createCollection(collection)` | Create an empty collection. |
|
|
99
|
+
| `getCollection(collection)` | Read collection metadata or `null`. |
|
|
100
|
+
| `rename(collection, newName, options?)` | Rename a collection, optionally with `nx`. |
|
|
101
|
+
| `dropCollection(collection)` | Drop a collection explicitly. |
|
|
102
|
+
| `bounds(collection)` | Read collection bounds. |
|
|
103
|
+
| `stats(collection)` | Read collection statistics. |
|
|
104
|
+
|
|
105
|
+
Objects, fields, TTLs, and JSON paths:
|
|
106
|
+
|
|
107
|
+
| Method | Description |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `setObject(collection, id, object, options?)` | Store point, bounds, geohash, GeoJSON, or string objects. |
|
|
110
|
+
| `setPoint(collection, id, coordinates, options?)` | Convenience wrapper for point writes. |
|
|
111
|
+
| `get(collection, id, options?)` | Read an object or `null`; can include fields and alternate output formats. |
|
|
112
|
+
| `delete(collection, id)` | Delete one object. |
|
|
113
|
+
| `deleteMatching(collection, options?)` | Delete objects matching an ID pattern. |
|
|
114
|
+
| `setFields(collection, id, fields, options?)` | Update one or more fields. |
|
|
115
|
+
| `getField(collection, id, field)` | Read one field value. |
|
|
116
|
+
| `expire(collection, id, seconds)` | Set or replace an object TTL. |
|
|
117
|
+
| `persist(collection, id)` | Remove an object TTL. |
|
|
118
|
+
| `ttl(collection, id)` | Read remaining TTL seconds or `null`. |
|
|
119
|
+
| `setJson(collection, id, path, value, options?)` | Set a JSON path value. |
|
|
120
|
+
| `getJson(collection, id, path)` | Read a JSON path value. |
|
|
121
|
+
| `deleteJson(collection, id, path)` | Delete a JSON path value. |
|
|
122
|
+
|
|
123
|
+
Search:
|
|
124
|
+
|
|
125
|
+
| Method | Description |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `nearby(collection, query)` | Search around a point/radius. |
|
|
128
|
+
| `within(collection, request)` | Search objects contained by an area. |
|
|
129
|
+
| `intersects(collection, request)` | Search objects intersecting an area. |
|
|
130
|
+
| `scan(collection, options?)` | Scan IDs/objects with match and field filters. |
|
|
131
|
+
| `search(collection, options?)` | Text/string search with match and field filters. |
|
|
132
|
+
|
|
133
|
+
Search options include `cursor`, `limit`, `nofields`, `matchPattern`, `sort`,
|
|
134
|
+
`whereFilters`, `whereInFilters`, `whereExprFilters`, `clip`, and output formats
|
|
135
|
+
such as `objects`, `points`, `bounds`, `ids`, `count`, or geohashes.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const trucks = await client.scan("fleet", {
|
|
139
|
+
limit: 100,
|
|
140
|
+
nofields: true,
|
|
141
|
+
whereFilters: [
|
|
142
|
+
{ field: "speed", comparison: { type: "range", min: 10, max: 80 } },
|
|
143
|
+
],
|
|
144
|
+
output: "ids",
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Channels, hooks, and geofence events:
|
|
149
|
+
|
|
150
|
+
| Method | Description |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| `setChannel(request)` | Create or replace an in-server geofence channel. |
|
|
153
|
+
| `channels(matchPattern?)` | List channel names. |
|
|
154
|
+
| `getChannel(name)` | Read a full channel definition or `null`. |
|
|
155
|
+
| `deleteChannel(name)` | Delete a channel. |
|
|
156
|
+
| `setHook(request)` | Create or replace a webhook hook. |
|
|
157
|
+
| `hooks(matchPattern?)` | List hook summaries. |
|
|
158
|
+
| `getHook(name)` | Read a full hook definition or `null`. |
|
|
159
|
+
| `deleteHook(name)` | Delete a hook. |
|
|
160
|
+
| `webhookQueue()` | Read durable webhook queue stats. |
|
|
161
|
+
| `connectWebSocket(options?)` | Connect to the leader WebSocket endpoint for channel subscriptions. |
|
|
162
|
+
|
|
163
|
+
Admin and runtime operations:
|
|
164
|
+
|
|
165
|
+
| Method | Description |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| `configGet(name)` | Read a runtime config value. |
|
|
168
|
+
| `configSet(name, value)` | Update a runtime config value. |
|
|
169
|
+
| `configRewrite()` | Persist current runtime config to disk. |
|
|
170
|
+
| `readonly(enabled)` | Toggle server read-only mode. |
|
|
171
|
+
| `timeout(request)` | Configure per-command server timeouts. |
|
|
172
|
+
| `aofshrink()` | Compact AOF persistence and return before/after stats. |
|
|
173
|
+
| `gc()` | Trigger server maintenance. |
|
|
174
|
+
| `flushdb()` | Delete all data. |
|
|
175
|
+
|
|
176
|
+
## Value Helpers
|
|
177
|
+
|
|
178
|
+
The package exports constructors for common wire shapes:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import {
|
|
182
|
+
bounds,
|
|
183
|
+
fieldEntries,
|
|
184
|
+
geojson,
|
|
185
|
+
hash,
|
|
186
|
+
jsonField,
|
|
187
|
+
numberField,
|
|
188
|
+
point,
|
|
189
|
+
stringObject,
|
|
190
|
+
textField,
|
|
191
|
+
} from "@latlng/sdk";
|
|
192
|
+
|
|
193
|
+
await client.setObject("fleet", "truck-1", point(52.52, 13.405), {
|
|
194
|
+
fields: {
|
|
195
|
+
speed: numberField(42),
|
|
196
|
+
status: textField("moving"),
|
|
197
|
+
payload: jsonField(JSON.stringify({ driver: "a" })),
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
await client.setObject("zones", "berlin", bounds({
|
|
202
|
+
min_lat: 52.3,
|
|
203
|
+
min_lon: 13.0,
|
|
204
|
+
max_lat: 52.7,
|
|
205
|
+
max_lon: 13.8,
|
|
206
|
+
}));
|
|
207
|
+
|
|
208
|
+
const fields = fieldEntries({ status: textField("ready") });
|
|
209
|
+
await client.setFields("fleet", "truck-1", fields);
|
|
210
|
+
|
|
211
|
+
await client.setObject("messages", "msg-1", stringObject("dispatch ready"));
|
|
212
|
+
await client.setObject(
|
|
213
|
+
"areas",
|
|
214
|
+
"geojson-1",
|
|
215
|
+
geojson({ type: "Point", coordinates: [13.405, 52.52] }),
|
|
216
|
+
);
|
|
217
|
+
await client.setObject("cells", "u33dc", hash("u33dc"));
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## WebSocket Example
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const ws = await client.connectWebSocket();
|
|
224
|
+
const subscription = await ws.psubscribe(["fleet*"]);
|
|
225
|
+
|
|
226
|
+
subscription.on("event", (event) => {
|
|
227
|
+
console.log(event.detect, event.id);
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Subscriptions are also async iterables:
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
for await (const event of subscription) {
|
|
235
|
+
console.log(event.channel, event.detect, event.id);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`LatLngWebSocketClient` exposes `ping()`, `subscribe(channels)`,
|
|
240
|
+
`psubscribe(patterns)`, `quit()`, and `close()`. The helper
|
|
241
|
+
`parseGeofenceEvent()` is exported for callers that need to parse event payloads
|
|
242
|
+
outside the WebSocket client.
|
|
243
|
+
|
|
244
|
+
## Read Replica Routing
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
const client = new LatLngClient({
|
|
248
|
+
leaderUrl: "http://leader:7421",
|
|
249
|
+
readReplicas: [
|
|
250
|
+
"http://follower-1:7421",
|
|
251
|
+
"http://follower-2:7421",
|
|
252
|
+
],
|
|
253
|
+
readPreference: "followerPreferred",
|
|
254
|
+
token: "dev-token",
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Followers are only used for reads when they report:
|
|
259
|
+
|
|
260
|
+
- `leader === false`
|
|
261
|
+
- `caught_up_once === true`
|
|
262
|
+
|
|
263
|
+
Writes and admin calls always target the configured leader URL.
|
|
264
|
+
|
|
265
|
+
Read routing only applies to normal read methods. Leader-only status/admin calls,
|
|
266
|
+
WebSocket connections, writes, config updates, compaction, and webhook queue
|
|
267
|
+
inspection target the leader.
|
|
268
|
+
|
|
269
|
+
## Authentication
|
|
270
|
+
|
|
271
|
+
The SDK transports bearer tokens. It does not mint, refresh, or introspect tokens.
|
|
272
|
+
|
|
273
|
+
In practice:
|
|
274
|
+
|
|
275
|
+
- local/dev commonly uses the static bearer token
|
|
276
|
+
- production deployments typically use JWTs issued by an external service or IdP
|
|
277
|
+
- claims-based authorization is enforced by the server, not by the SDK
|
|
278
|
+
|
|
279
|
+
The current auth/authz model, claim schema, and config reference are documented in [docs/auth.md](https://github.com/tobilg/latlng/blob/main/docs/auth.md).
|
|
280
|
+
|
|
281
|
+
## Errors
|
|
282
|
+
|
|
283
|
+
The SDK exports typed error classes:
|
|
284
|
+
|
|
285
|
+
| Error | Meaning |
|
|
286
|
+
| --- | --- |
|
|
287
|
+
| `LatLngError` | Base SDK error. |
|
|
288
|
+
| `TimeoutError` | Request exceeded `timeoutMs`. |
|
|
289
|
+
| `HttpError` | Non-success HTTP response with status and payload context. |
|
|
290
|
+
| `AuthError` | Authentication or authorization failure. |
|
|
291
|
+
| `ServerUnavailableError` | Server unavailable response. |
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
import { AuthError, LatLngClient } from "@latlng/sdk";
|
|
295
|
+
|
|
296
|
+
const client = new LatLngClient({
|
|
297
|
+
leaderUrl: "http://127.0.0.1:7421",
|
|
298
|
+
token: "dev-token",
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
await client.ping();
|
|
303
|
+
} catch (error) {
|
|
304
|
+
if (error instanceof AuthError) {
|
|
305
|
+
console.error("invalid token");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## API Reference
|
|
311
|
+
|
|
312
|
+
Run `npm run docs:api` to generate TypeDoc reference pages for all exported
|
|
313
|
+
classes, helpers, request types, response types, search models, geofence event
|
|
314
|
+
models, and error classes.
|
|
315
|
+
|
|
316
|
+
## Development
|
|
317
|
+
|
|
318
|
+
```sh
|
|
319
|
+
npm ci
|
|
320
|
+
npm run build
|
|
321
|
+
npm run docs:api
|
|
322
|
+
npm run test:unit
|
|
323
|
+
npm run test:integration
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The integration suite starts local `latlng-server` processes and exercises the SDK against the real HTTP, WebSocket, and leader/follower surfaces.
|
|
327
|
+
|
|
328
|
+
## Release Notes
|
|
329
|
+
|
|
330
|
+
Current package toolchain:
|
|
331
|
+
|
|
332
|
+
- `typescript@6.0.3`
|
|
333
|
+
- `vite@8.0.11`
|
|
334
|
+
- `vitest@4.1.5`
|
|
335
|
+
|
|
336
|
+
Subdirectory publish flow:
|
|
337
|
+
|
|
338
|
+
```sh
|
|
339
|
+
npm ci
|
|
340
|
+
npm run test
|
|
341
|
+
npm run docs:api
|
|
342
|
+
npm publish --access public
|
|
343
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/auth/token.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,IAAI,CAIN"}
|