rendezvous-kit 1.21.4 → 1.21.6
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 +1 -1
- package/README.md +169 -11
- package/llms-full.txt +86 -7
- package/llms.txt +7 -4
- package/package.json +2 -2
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# rendezvous-kit
|
|
2
2
|
|
|
3
|
+
**Nostr:** [`npub1mgvlrnf5hm9yf0n5mf9nqmvarhvxkc6remu5ec3vf8r0txqkuk7su0e7q2`](https://njump.me/npub1mgvlrnf5hm9yf0n5mf9nqmvarhvxkc6remu5ec3vf8r0txqkuk7su0e7q2)
|
|
4
|
+
|
|
3
5
|
**Find fair meeting points for N people — isochrone intersection, venue search, and fairness scoring.**
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/rendezvous-kit)
|
|
@@ -92,12 +94,12 @@ for (const s of suggestions) {
|
|
|
92
94
|
|
|
93
95
|
## Engine Support
|
|
94
96
|
|
|
95
|
-
| Engine | Isochrone | Route Matrix | Auth |
|
|
96
|
-
|
|
97
|
-
| Valhalla | Yes | Yes | None (self-hosted) |
|
|
98
|
-
| OpenRouteService | Yes | Yes | API key |
|
|
99
|
-
| GraphHopper | Yes | Yes | API key (optional) |
|
|
100
|
-
| OSRM | No | Yes | None (self-hosted) |
|
|
97
|
+
| Engine | Isochrone | Route Matrix | Route | Auth |
|
|
98
|
+
|--------|:---------:|:------------:|:-----:|------|
|
|
99
|
+
| Valhalla | Yes | Yes | Yes | None (self-hosted) |
|
|
100
|
+
| OpenRouteService | Yes | Yes | No | API key |
|
|
101
|
+
| GraphHopper | Yes | Yes | No | API key (optional) |
|
|
102
|
+
| OSRM | No | Yes | No | None (self-hosted) |
|
|
101
103
|
|
|
102
104
|
OSRM does not support isochrone computation — use it only when you need a fast route matrix and are supplying your own intersection polygon.
|
|
103
105
|
|
|
@@ -152,14 +154,17 @@ OSRM does not support isochrone computation — use it only when you need a fast
|
|
|
152
154
|
| `GeoJSONPolygon` | Standard GeoJSON polygon geometry |
|
|
153
155
|
| `TransportMode` | `'drive' \| 'cycle' \| 'walk' \| 'public_transit'` |
|
|
154
156
|
| `FairnessStrategy` | `'min_max' \| 'min_total' \| 'min_variance'` |
|
|
155
|
-
| `VenueType` | `'park' \| 'cafe' \| 'restaurant' \| 'service_station' \| 'library' \| 'pub' \| 'playground' \| 'community_centre' \| string` |
|
|
156
|
-
| `RoutingEngine` | Interface — `computeIsochrone` + `computeRouteMatrix` |
|
|
157
|
+
| `VenueType` | `'park' \| 'cafe' \| 'restaurant' \| 'service_station' \| 'library' \| 'pub' \| 'playground' \| 'community_centre' \| 'bar' \| 'fast_food' \| 'garden' \| 'theatre' \| 'arts_centre' \| 'fitness_centre' \| 'sports_centre' \| 'escape_game' \| 'swimming_pool' \| string` |
|
|
158
|
+
| `RoutingEngine` | Interface — `computeIsochrone` + `computeRouteMatrix` + `computeRoute` |
|
|
157
159
|
| `Isochrone` | `{ origin, mode, timeMinutes, polygon }` |
|
|
158
160
|
| `MatrixEntry` | `{ originIndex, destinationIndex, durationMinutes, distanceKm }` |
|
|
159
161
|
| `RouteMatrix` | `{ origins, destinations, entries }` |
|
|
160
162
|
| `Venue` | `{ name, lat, lon, venueType, osmId? }` |
|
|
161
|
-
| `RendezvousOptions` | `{ participants, mode, maxTimeMinutes, venueTypes, fairness?, limit? }` |
|
|
162
|
-
| `RendezvousSuggestion` | `{ venue, travelTimes, fairnessScore }` |
|
|
163
|
+
| `RendezvousOptions` | `{ participants, mode, maxTimeMinutes, venueTypes, fairness?, limit?, strategy? }` |
|
|
164
|
+
| `RendezvousSuggestion` | `{ venue, travelTimes, fairnessScore, metadata? }` |
|
|
165
|
+
| `RouteGeometry` | `{ origin, destination, mode, durationMinutes, distanceKm, geometry, legs? }` |
|
|
166
|
+
| `RouteLeg` | `{ instruction, distanceKm, durationMinutes, type?, streetNames?, ... }` |
|
|
167
|
+
| `GeoJSONLineString` | `{ type: 'LineString', coordinates: number[][] }` |
|
|
163
168
|
| `BBox` | `{ minLon, minLat, maxLon, maxLat }` |
|
|
164
169
|
| `Coordinate` | `{ lat, lon }` |
|
|
165
170
|
|
|
@@ -194,7 +199,7 @@ If the isochrones do not overlap, `findRendezvous` returns an empty array. If no
|
|
|
194
199
|
## Implementing a Custom Engine
|
|
195
200
|
|
|
196
201
|
```typescript
|
|
197
|
-
import type { RoutingEngine, LatLon, TransportMode, Isochrone, RouteMatrix } from 'rendezvous-kit'
|
|
202
|
+
import type { RoutingEngine, LatLon, TransportMode, Isochrone, RouteMatrix, RouteGeometry } from 'rendezvous-kit'
|
|
198
203
|
|
|
199
204
|
class MyEngine implements RoutingEngine {
|
|
200
205
|
readonly name = 'MyEngine'
|
|
@@ -206,6 +211,10 @@ class MyEngine implements RoutingEngine {
|
|
|
206
211
|
async computeRouteMatrix(origins: LatLon[], destinations: LatLon[], mode: TransportMode): Promise<RouteMatrix> {
|
|
207
212
|
// call your API and return a RouteMatrix
|
|
208
213
|
}
|
|
214
|
+
|
|
215
|
+
async computeRoute(origin: LatLon, destination: LatLon, mode: TransportMode): Promise<RouteGeometry> {
|
|
216
|
+
// call your API and return a RouteGeometry with optional turn-by-turn legs
|
|
217
|
+
}
|
|
209
218
|
}
|
|
210
219
|
```
|
|
211
220
|
|
|
@@ -235,6 +244,138 @@ Run any example with `npx tsx examples/<name>.ts`.
|
|
|
235
244
|
|
|
236
245
|
See [llms.txt](./llms.txt) for a concise API summary, or [llms-full.txt](./llms-full.txt) for the complete reference with examples.
|
|
237
246
|
|
|
247
|
+
## How the Pipeline Works
|
|
248
|
+
|
|
249
|
+
### Step 1: Parallel isochrone computation
|
|
250
|
+
|
|
251
|
+
`findRendezvous` computes a reachability polygon for each participant in parallel.
|
|
252
|
+
Every participant gets their own isochrone — a polygon representing everywhere they
|
|
253
|
+
can reach within `maxTimeMinutes` using the specified transport mode:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Internally, all N isochrones are fetched concurrently:
|
|
257
|
+
const isochrones = await Promise.all(
|
|
258
|
+
participants.map(p => engine.computeIsochrone(p, mode, maxTimeMinutes))
|
|
259
|
+
)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
This works identically for 2, 5, or 20 participants — each gets their own polygon.
|
|
263
|
+
The engine does the heavy lifting; rendezvous-kit just orchestrates the parallel calls.
|
|
264
|
+
|
|
265
|
+
### Step 2: N-polygon intersection
|
|
266
|
+
|
|
267
|
+
All isochrone polygons are intersected left-to-right using Sutherland–Hodgman clipping.
|
|
268
|
+
The result is the geographic area reachable by **every** participant within the time budget:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { intersectPolygonsAll } from 'rendezvous-kit/geo'
|
|
272
|
+
|
|
273
|
+
// Folds left-to-right: clip polygon 2 against 1, then clip 3 against that result, etc.
|
|
274
|
+
// Preserves disconnected components (e.g. two separate road corridors)
|
|
275
|
+
const components = intersectPolygonsAll(isochrones.map(iso => iso.polygon))
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
If the intersection is empty (participants too far apart), `findRendezvous` returns `[]`.
|
|
279
|
+
|
|
280
|
+
### Step 3: Venue search and scoring
|
|
281
|
+
|
|
282
|
+
Venues are searched within the intersection zone via Overpass API, then each venue is
|
|
283
|
+
scored using the chosen fairness strategy:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
const suggestions = await findRendezvous(engine, {
|
|
287
|
+
participants: [alice, bob, carol],
|
|
288
|
+
mode: 'drive',
|
|
289
|
+
maxTimeMinutes: 90,
|
|
290
|
+
venueTypes: ['cafe', 'restaurant'],
|
|
291
|
+
fairness: 'min_max', // minimise the worst individual travel time
|
|
292
|
+
limit: 5,
|
|
293
|
+
})
|
|
294
|
+
// Each suggestion has: venue, travelTimes (per participant), fairnessScore
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### When isochrones don't overlap
|
|
298
|
+
|
|
299
|
+
If the isochrones don't intersect, `findRendezvous` returns an empty array. Options:
|
|
300
|
+
|
|
301
|
+
1. **Increase `maxTimeMinutes`** — expand the reachability polygons
|
|
302
|
+
2. **Switch transport mode** — `'drive'` covers more ground than `'walk'`
|
|
303
|
+
3. **Use the `hull` strategy** — for nearby participants, the library automatically uses
|
|
304
|
+
a convex hull of participant positions as the search region instead of isochrones.
|
|
305
|
+
This always produces results because it searches the area *between* participants.
|
|
306
|
+
|
|
307
|
+
If the intersection exists but contains no matching venues, the library falls back to
|
|
308
|
+
a synthetic "Meeting point" at the area-weighted centroid of the intersection.
|
|
309
|
+
|
|
310
|
+
## Switching Routing Engines
|
|
311
|
+
|
|
312
|
+
OSRM does not support isochrone computation. If you're using OSRM and need the full
|
|
313
|
+
pipeline, swap to an isochrone-capable engine:
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
// Before: OSRM (route matrix only — no isochrones)
|
|
317
|
+
import { OsrmEngine } from 'rendezvous-kit/engines/osrm'
|
|
318
|
+
const engine = new OsrmEngine({ baseUrl: 'http://localhost:5000' })
|
|
319
|
+
|
|
320
|
+
// After: Valhalla (self-hosted, free, full isochrone support)
|
|
321
|
+
import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla'
|
|
322
|
+
const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' })
|
|
323
|
+
|
|
324
|
+
// Or: OpenRouteService (hosted API, requires free API key)
|
|
325
|
+
import { OpenRouteServiceEngine } from 'rendezvous-kit/engines/openrouteservice'
|
|
326
|
+
const engine = new OpenRouteServiceEngine({
|
|
327
|
+
apiKey: process.env.ORS_API_KEY!,
|
|
328
|
+
baseUrl: 'https://api.openrouteservice.org', // default
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
// Or: GraphHopper (self-hosted or hosted, API key optional for self-hosted)
|
|
332
|
+
import { GraphHopperEngine } from 'rendezvous-kit/engines/graphhopper'
|
|
333
|
+
const engine = new GraphHopperEngine({
|
|
334
|
+
baseUrl: 'http://localhost:8989',
|
|
335
|
+
apiKey: process.env.GRAPHHOPPER_KEY, // optional for self-hosted
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
// All engines implement the same RoutingEngine interface.
|
|
339
|
+
// The rest of your code stays identical:
|
|
340
|
+
const suggestions = await findRendezvous(engine, { participants, mode, ... })
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
For self-hosting guides (Docker one-liners for Valhalla, OSRM, GraphHopper), see
|
|
344
|
+
[Self-Hosting a Routing Engine](./docs/self-hosting-a-routing-engine.md).
|
|
345
|
+
|
|
346
|
+
## Architecture
|
|
347
|
+
|
|
348
|
+
rendezvous-kit's pipeline combines two kinds of spatial operations:
|
|
349
|
+
|
|
350
|
+
**Routing engine operations** (external): isochrone computation, route matrix, and
|
|
351
|
+
route geometry. These call your chosen engine's HTTP API for real road-network
|
|
352
|
+
calculations.
|
|
353
|
+
|
|
354
|
+
**Local geometry operations** (pure TypeScript, no dependencies): polygon intersection
|
|
355
|
+
(Sutherland–Hodgman), area calculation (shoelace), centroid computation, bounding boxes,
|
|
356
|
+
and convex hull (via `geohash-kit/coverage`). These run entirely in-process with no
|
|
357
|
+
network calls.
|
|
358
|
+
|
|
359
|
+
The only external dependency is `geohash-kit`, which provides the `convexHull` function
|
|
360
|
+
used by the hull-strategy fast path for nearby participants. All other polygon operations
|
|
361
|
+
(intersection, clipping, triangulation, area) are implemented in `rendezvous-kit/geo`.
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
Participants ──→ Engine.computeIsochrone() ──→ Polygon[]
|
|
365
|
+
│
|
|
366
|
+
intersectPolygonsAll() ← local geometry
|
|
367
|
+
│
|
|
368
|
+
Intersection zone
|
|
369
|
+
│
|
|
370
|
+
searchVenues() via Overpass API
|
|
371
|
+
│
|
|
372
|
+
Engine.computeRouteMatrix() ──→ travel times
|
|
373
|
+
│
|
|
374
|
+
scoreVenues() ← local fairness calc
|
|
375
|
+
│
|
|
376
|
+
Ranked suggestions
|
|
377
|
+
```
|
|
378
|
+
|
|
238
379
|
## Troubleshooting
|
|
239
380
|
|
|
240
381
|
**`findRendezvous` returns an empty array**
|
|
@@ -252,6 +393,23 @@ Check that your engine base URL is correct and the service is running. For ORS,
|
|
|
252
393
|
**OSRM: `Error: OSRM does not support isochrone computation`**
|
|
253
394
|
OSRM cannot generate isochrones. Use Valhalla, OpenRouteService, or GraphHopper instead. OSRM is supported only for route matrix computation.
|
|
254
395
|
|
|
396
|
+
## Part of the ForgeSworn Toolkit
|
|
397
|
+
|
|
398
|
+
[ForgeSworn](https://forgesworn.dev) builds open-source cryptographic identity, payments, and coordination tools for Nostr.
|
|
399
|
+
|
|
400
|
+
| Library | What it does |
|
|
401
|
+
|---------|-------------|
|
|
402
|
+
| [nsec-tree](https://github.com/forgesworn/nsec-tree) | Deterministic sub-identity derivation |
|
|
403
|
+
| [ring-sig](https://github.com/forgesworn/ring-sig) | SAG/LSAG ring signatures on secp256k1 |
|
|
404
|
+
| [range-proof](https://github.com/forgesworn/range-proof) | Pedersen commitment range proofs |
|
|
405
|
+
| [canary-kit](https://github.com/forgesworn/canary-kit) | Coercion-resistant spoken verification |
|
|
406
|
+
| [spoken-token](https://github.com/forgesworn/spoken-token) | Human-speakable verification tokens |
|
|
407
|
+
| [toll-booth](https://github.com/forgesworn/toll-booth) | L402 payment middleware |
|
|
408
|
+
| [geohash-kit](https://github.com/forgesworn/geohash-kit) | Geohash toolkit with polygon coverage |
|
|
409
|
+
| [nostr-attestations](https://github.com/forgesworn/nostr-attestations) | NIP-VA verifiable attestations |
|
|
410
|
+
| [dominion](https://github.com/forgesworn/dominion) | Epoch-based encrypted access control |
|
|
411
|
+
| [nostr-veil](https://github.com/forgesworn/nostr-veil) | Privacy-preserving Web of Trust |
|
|
412
|
+
|
|
255
413
|
## Licence
|
|
256
414
|
|
|
257
415
|
[MIT](https://github.com/forgesworn/rendezvous-kit/blob/main/LICENSE)
|
package/llms-full.txt
CHANGED
|
@@ -63,6 +63,15 @@ type VenueType =
|
|
|
63
63
|
| 'pub'
|
|
64
64
|
| 'playground'
|
|
65
65
|
| 'community_centre'
|
|
66
|
+
| 'bar'
|
|
67
|
+
| 'fast_food'
|
|
68
|
+
| 'garden'
|
|
69
|
+
| 'theatre'
|
|
70
|
+
| 'arts_centre'
|
|
71
|
+
| 'fitness_centre'
|
|
72
|
+
| 'sports_centre'
|
|
73
|
+
| 'escape_game'
|
|
74
|
+
| 'swimming_pool'
|
|
66
75
|
| string
|
|
67
76
|
|
|
68
77
|
/** Result of an isochrone computation. */
|
|
@@ -97,6 +106,43 @@ interface Venue {
|
|
|
97
106
|
osmId?: string // e.g. 'node/123456'
|
|
98
107
|
}
|
|
99
108
|
|
|
109
|
+
/** GeoJSON LineString geometry. */
|
|
110
|
+
interface GeoJSONLineString {
|
|
111
|
+
type: 'LineString'
|
|
112
|
+
coordinates: number[][]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** A single manoeuvre in a route. */
|
|
116
|
+
interface RouteLeg {
|
|
117
|
+
instruction: string
|
|
118
|
+
distanceKm: number
|
|
119
|
+
durationMinutes: number
|
|
120
|
+
type?: number // Valhalla manoeuvre type (0-38)
|
|
121
|
+
streetNames?: string[]
|
|
122
|
+
beginStreetNames?: string[]
|
|
123
|
+
verbalInstruction?: string
|
|
124
|
+
toll?: boolean
|
|
125
|
+
highway?: boolean
|
|
126
|
+
ferry?: boolean
|
|
127
|
+
rough?: boolean
|
|
128
|
+
gate?: boolean
|
|
129
|
+
bearingBefore?: number
|
|
130
|
+
bearingAfter?: number
|
|
131
|
+
beginShapeIndex?: number
|
|
132
|
+
endShapeIndex?: number
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Result of a single route computation. */
|
|
136
|
+
interface RouteGeometry {
|
|
137
|
+
origin: LatLon
|
|
138
|
+
destination: LatLon
|
|
139
|
+
mode: TransportMode
|
|
140
|
+
durationMinutes: number
|
|
141
|
+
distanceKm: number
|
|
142
|
+
geometry: GeoJSONLineString
|
|
143
|
+
legs?: RouteLeg[]
|
|
144
|
+
}
|
|
145
|
+
|
|
100
146
|
/** Options for rendezvous calculation. */
|
|
101
147
|
interface RendezvousOptions {
|
|
102
148
|
participants: LatLon[] // at least 2 required
|
|
@@ -105,6 +151,7 @@ interface RendezvousOptions {
|
|
|
105
151
|
venueTypes: VenueType[]
|
|
106
152
|
fairness?: FairnessStrategy // default: 'min_max'
|
|
107
153
|
limit?: number // max suggestions to return, default: 5
|
|
154
|
+
strategy?: 'auto' | 'hull' | 'isochrone' // pipeline strategy, default: 'auto'
|
|
108
155
|
}
|
|
109
156
|
|
|
110
157
|
/** A ranked rendezvous suggestion. */
|
|
@@ -112,6 +159,7 @@ interface RendezvousSuggestion {
|
|
|
112
159
|
venue: Venue
|
|
113
160
|
travelTimes: Record<string, number> // keyed by participant label or 'participant_N'
|
|
114
161
|
fairnessScore: number // lower is better
|
|
162
|
+
metadata?: { strategy: 'hull' | 'isochrone' } // which pipeline was used
|
|
115
163
|
}
|
|
116
164
|
|
|
117
165
|
/** Engine-agnostic routing interface. Implement this to add a custom engine. */
|
|
@@ -119,6 +167,7 @@ interface RoutingEngine {
|
|
|
119
167
|
readonly name: string
|
|
120
168
|
computeIsochrone(origin: LatLon, mode: TransportMode, timeMinutes: number): Promise<Isochrone>
|
|
121
169
|
computeRouteMatrix(origins: LatLon[], destinations: LatLon[], mode: TransportMode): Promise<RouteMatrix>
|
|
170
|
+
computeRoute(origin: LatLon, destination: LatLon, mode: TransportMode): Promise<RouteGeometry>
|
|
122
171
|
}
|
|
123
172
|
|
|
124
173
|
/** Bounding box (from rendezvous-kit/geo). */
|
|
@@ -413,6 +462,15 @@ Built-in `VenueType` to Overpass tag mapping:
|
|
|
413
462
|
| `pub` | `amenity=pub` |
|
|
414
463
|
| `playground` | `leisure=playground` |
|
|
415
464
|
| `community_centre` | `amenity=community_centre` |
|
|
465
|
+
| `bar` | `amenity=bar` |
|
|
466
|
+
| `fast_food` | `amenity=fast_food` |
|
|
467
|
+
| `garden` | `leisure=garden` |
|
|
468
|
+
| `theatre` | `amenity=theatre` |
|
|
469
|
+
| `arts_centre` | `amenity=arts_centre` |
|
|
470
|
+
| `fitness_centre` | `leisure=fitness_centre` |
|
|
471
|
+
| `sports_centre` | `leisure=sports_centre` |
|
|
472
|
+
| `escape_game` | `leisure=escape_game` |
|
|
473
|
+
| `swimming_pool` | `leisure=swimming_pool` |
|
|
416
474
|
|
|
417
475
|
Unknown strings are passed through as `amenity=<value>`.
|
|
418
476
|
|
|
@@ -421,7 +479,7 @@ Unknown strings are passed through as `amenity=<value>`.
|
|
|
421
479
|
## Implementing a Custom Engine
|
|
422
480
|
|
|
423
481
|
```typescript
|
|
424
|
-
import type { RoutingEngine, LatLon, TransportMode, Isochrone, RouteMatrix } from 'rendezvous-kit'
|
|
482
|
+
import type { RoutingEngine, LatLon, TransportMode, Isochrone, RouteMatrix, RouteGeometry } from 'rendezvous-kit'
|
|
425
483
|
|
|
426
484
|
class MyRoutingEngine implements RoutingEngine {
|
|
427
485
|
readonly name = 'MyEngine'
|
|
@@ -454,6 +512,27 @@ class MyRoutingEngine implements RoutingEngine {
|
|
|
454
512
|
}
|
|
455
513
|
return { origins, destinations, entries }
|
|
456
514
|
}
|
|
515
|
+
|
|
516
|
+
async computeRoute(
|
|
517
|
+
origin: LatLon,
|
|
518
|
+
destination: LatLon,
|
|
519
|
+
mode: TransportMode,
|
|
520
|
+
): Promise<RouteGeometry> {
|
|
521
|
+
const raw = await myApi.getRoute(origin, destination, mode)
|
|
522
|
+
return {
|
|
523
|
+
origin,
|
|
524
|
+
destination,
|
|
525
|
+
mode,
|
|
526
|
+
durationMinutes: raw.seconds / 60,
|
|
527
|
+
distanceKm: raw.metres / 1000,
|
|
528
|
+
geometry: { type: 'LineString', coordinates: raw.polyline },
|
|
529
|
+
legs: raw.steps.map((s: any) => ({
|
|
530
|
+
instruction: s.text,
|
|
531
|
+
distanceKm: s.metres / 1000,
|
|
532
|
+
durationMinutes: s.seconds / 60,
|
|
533
|
+
})),
|
|
534
|
+
}
|
|
535
|
+
}
|
|
457
536
|
}
|
|
458
537
|
|
|
459
538
|
// Use it with findRendezvous
|
|
@@ -464,12 +543,12 @@ const suggestions = await findRendezvous(new MyRoutingEngine(), options)
|
|
|
464
543
|
|
|
465
544
|
## Engine Comparison
|
|
466
545
|
|
|
467
|
-
| Engine | Isochrone | Matrix | Auth | Notes |
|
|
468
|
-
|
|
469
|
-
| Valhalla | Yes | Yes | None | Best self-hosted option; supports public transit |
|
|
470
|
-
| OpenRouteService | Yes | Yes | API key | Free tier available; no public transit |
|
|
471
|
-
| GraphHopper | Yes | Yes | Optional | API key only for cloud; optional self-hosted |
|
|
472
|
-
| OSRM | No | Yes | None | Fastest matrix; no isochrone support |
|
|
546
|
+
| Engine | Isochrone | Matrix | Route | Auth | Notes |
|
|
547
|
+
|--------|:---------:|:------:|:-----:|------|-------|
|
|
548
|
+
| Valhalla | Yes | Yes | Yes | None | Best self-hosted option; supports public transit |
|
|
549
|
+
| OpenRouteService | Yes | Yes | No | API key | Free tier available; no public transit |
|
|
550
|
+
| GraphHopper | Yes | Yes | No | Optional | API key only for cloud; optional self-hosted |
|
|
551
|
+
| OSRM | No | Yes | No | None | Fastest matrix; no isochrone support |
|
|
473
552
|
|
|
474
553
|
---
|
|
475
554
|
|
package/llms.txt
CHANGED
|
@@ -52,10 +52,13 @@ Pure-TypeScript polygon geometry.
|
|
|
52
52
|
- GeoJSONPolygon: { type: 'Polygon', coordinates: number[][][] }
|
|
53
53
|
- TransportMode: 'drive' | 'cycle' | 'walk' | 'public_transit'
|
|
54
54
|
- FairnessStrategy: 'min_max' | 'min_total' | 'min_variance'
|
|
55
|
-
- VenueType: 'park' | 'cafe' | 'restaurant' | 'service_station' | 'library' | 'pub' | 'playground' | 'community_centre' | string
|
|
56
|
-
- RendezvousOptions: { participants, mode, maxTimeMinutes, venueTypes, fairness?, limit? }
|
|
57
|
-
- RendezvousSuggestion: { venue, travelTimes: Record<string, number>, fairnessScore }
|
|
58
|
-
- RoutingEngine: interface { name, computeIsochrone, computeRouteMatrix }
|
|
55
|
+
- VenueType: 'park' | 'cafe' | 'restaurant' | 'service_station' | 'library' | 'pub' | 'playground' | 'community_centre' | 'bar' | 'fast_food' | 'garden' | 'theatre' | 'arts_centre' | 'fitness_centre' | 'sports_centre' | 'escape_game' | 'swimming_pool' | string
|
|
56
|
+
- RendezvousOptions: { participants, mode, maxTimeMinutes, venueTypes, fairness?, limit?, strategy? }
|
|
57
|
+
- RendezvousSuggestion: { venue, travelTimes: Record<string, number>, fairnessScore, metadata? }
|
|
58
|
+
- RoutingEngine: interface { name, computeIsochrone, computeRouteMatrix, computeRoute }
|
|
59
|
+
- RouteGeometry: { origin, destination, mode, durationMinutes, distanceKm, geometry: GeoJSONLineString, legs?: RouteLeg[] }
|
|
60
|
+
- RouteLeg: { instruction, distanceKm, durationMinutes, type?, streetNames?, verbalInstruction?, ... }
|
|
61
|
+
- GeoJSONLineString: { type: 'LineString', coordinates: number[][] }
|
|
59
62
|
|
|
60
63
|
## Fairness Strategies
|
|
61
64
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rendezvous-kit",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Find fair meeting points for N people — isochrone intersection, venue search, and fairness scoring.",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -85,6 +85,6 @@
|
|
|
85
85
|
"homepage": "https://github.com/forgesworn/rendezvous-kit",
|
|
86
86
|
"funding": {
|
|
87
87
|
"type": "lightning",
|
|
88
|
-
"url": "
|
|
88
|
+
"url": "lightning:thedonkey@strike.me"
|
|
89
89
|
}
|
|
90
90
|
}
|