### Clone and Setup Project Source: https://github.com/forgesworn/rendezvous-kit/blob/main/CONTRIBUTING.md Initial steps to clone the repository and install dependencies. ```bash git clone https://github.com/forgesworn/rendezvous-kit.git cd rendezvous-kit npm install npm test ``` -------------------------------- ### Install rendezvous-kit Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Install the rendezvous-kit package using npm. This is the first step before importing any functionalities. ```bash npm install rendezvous-kit ``` -------------------------------- ### Initialize OpenRouteServiceEngine Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Usage examples for cloud and self-hosted OpenRouteService configurations. ```typescript import { OpenRouteServiceEngine } from 'rendezvous-kit/engines/openrouteservice' // Cloud (requires free API key from openrouteservice.org) const engine = new OpenRouteServiceEngine({ apiKey: 'your-api-key' }) // Self-hosted const engine = new OpenRouteServiceEngine({ apiKey: 'local', baseUrl: 'http://localhost:8080/ors', }) ``` -------------------------------- ### Initialize GraphHopperEngine Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Usage examples for cloud and self-hosted GraphHopper configurations. ```typescript import { GraphHopperEngine } from 'rendezvous-kit/engines/graphhopper' // Self-hosted (no key needed) const engine = new GraphHopperEngine({ baseUrl: 'http://localhost:8989' }) // Cloud const engine = new GraphHopperEngine({ baseUrl: 'https://graphhopper.com/api/1', apiKey: 'your-api-key', }) ``` -------------------------------- ### Initialize and Use OsrmEngine Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Usage example for OSRM engine, which supports route matrix calculations. ```typescript import { OsrmEngine } from 'rendezvous-kit/engines/osrm' const engine = new OsrmEngine({ baseUrl: 'http://localhost:5000' }) // Use directly for matrix-only workflows const matrix = await engine.computeRouteMatrix(origins, destinations, 'drive') ``` -------------------------------- ### MinTotal Fairness Strategy Example Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/choosing-a-fairness-strategy.md Demonstrates the min_total fairness strategy, which optimizes for the sum of all travel times. This is best for logistics or scenarios where total cost is more important than individual fairness. ```text Alice: 30 min, Bob: 45 min, Carol: 20 min → score = 95 ``` -------------------------------- ### Run GraphHopper Docker Container Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md Starts a GraphHopper routing engine instance using its official Docker image. Configure memory allocation with JAVA_OPTS and provide the PBF URL for data download. ```bash docker run -d --name graphhopper \ -p 8989:8989 \ -e JAVA_OPTS="-Xmx4g" \ -v graphhopper_data:/data \ graphhopper/graphhopper:latest \ --url https://download.geofabrik.de/europe/great-britain-latest.osm.pbf \ --host 0.0.0.0 ``` -------------------------------- ### Execute searchVenues Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Example of searching for venues within an intersection of polygons. ```typescript import { searchVenues } from 'rendezvous-kit/venues' import { intersectPolygons } from 'rendezvous-kit/geo' const intersection = intersectPolygons([isoA.polygon, isoB.polygon]) if (intersection) { const venues = await searchVenues(intersection, ['cafe', 'restaurant']) // [{ name: 'The Red Lion', lat: 51.9, lon: -1.4, venueType: 'pub', osmId: 'node/123' }, ...] } ``` -------------------------------- ### MinMax Fairness Strategy Example Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/choosing-a-fairness-strategy.md Illustrates the min_max fairness strategy where the score is the longest individual journey. This is suitable for social meetups where excessive travel for one person is undesirable. ```text Alice: 30 min, Bob: 45 min, Carol: 20 min → score = 45 ``` -------------------------------- ### Implement Custom Routing Engine in TypeScript Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Implement the `RoutingEngine` interface to create a custom routing engine. This example shows how to define methods for `computeIsochrone`, `computeRouteMatrix`, and `computeRoute` using an external API. ```typescript import type { RoutingEngine, LatLon, TransportMode, Isochrone, RouteMatrix, RouteGeometry } from 'rendezvous-kit' class MyRoutingEngine implements RoutingEngine { readonly name = 'MyEngine' async computeIsochrone( origin: LatLon, mode: TransportMode, timeMinutes: number, ): Promise { const polygon = await myApi.getIsochrone(origin.lat, origin.lon, timeMinutes) return { origin, mode, timeMinutes, polygon } } async computeRouteMatrix( origins: LatLon[], destinations: LatLon[], mode: TransportMode, ): Promise { const raw = await myApi.getMatrix(origins, destinations) const entries = [] for (let oi = 0; oi < origins.length; oi++) { for (let di = 0; di < destinations.length; di++) { entries.push({ originIndex: oi, destinationIndex: di, durationMinutes: raw[oi][di].seconds / 60, distanceKm: raw[oi][di].metres / 1000, }) } } return { origins, destinations, entries } } async computeRoute( origin: LatLon, destination: LatLon, mode: TransportMode, ): Promise { const raw = await myApi.getRoute(origin, destination, mode) return { origin, destination, mode, durationMinutes: raw.seconds / 60, distanceKm: raw.metres / 1000, geometry: { type: 'LineString', coordinates: raw.polyline }, legs: raw.steps.map((s: any) => ({ instruction: s.text, distanceKm: s.metres / 1000, durationMinutes: s.seconds / 60, })), } } } // Use it with findRendezvous const suggestions = await findRendezvous(new MyRoutingEngine(), options) ``` -------------------------------- ### Valhalla Error Handling (Payment Required) Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Example of how to catch and handle specific Valhalla errors, such as a 402 'Payment Required' status, by checking the error type and status code. ```typescript // Handle L402 payment errors try { await engine.computeRoute(origin, destination, 'drive') } catch (err) { if (err instanceof ValhallaError && err.status === 402) { console.log('Payment required:', err.body) } } ``` -------------------------------- ### MinVariance Fairness Strategy Examples Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/choosing-a-fairness-strategy.md Shows the min_variance fairness strategy, which optimizes for equalizing travel times by minimizing the standard deviation. This is ideal for repeated meetings where perceived fairness over time is crucial. ```text Alice: 30 min, Bob: 45 min, Carol: 20 min → score = 10.3 Alice: 35 min, Bob: 32 min, Carol: 33 min → score = 1.2 ← preferred ``` -------------------------------- ### Intersect Polygons - Examples Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Demonstrates the usage of intersectPolygons for computing the intersection of GeoJSON polygons. Returns null if the intersection is empty. ```typescript intersectPolygons(polygons: GeoJSONPolygon[]): GeoJSONPolygon | null // Single polygon — returned unchanged intersectPolygons([poly]) // poly // Two overlapping polygons intersectPolygons([polyA, polyB]) // intersection polygon // No overlap intersectPolygons([polyA, polyFarAway]) // null ``` -------------------------------- ### Initialize and use OpenRouteServiceEngine Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Configures the OpenRouteService adapter and demonstrates computing isochrones and route matrices. ```typescript import { OpenRouteServiceEngine } from 'rendezvous-kit/engines/openrouteservice' const engine = new OpenRouteServiceEngine({ apiKey: 'your-ors-api-key', baseUrl: 'https://api.openrouteservice.org', // optional override timeoutMs: 30000, // optional timeout }) const isochrone = await engine.computeIsochrone( { lat: 51.5074, lon: -0.1278 }, 'cycle', 15 ) const matrix = await engine.computeRouteMatrix( [{ lat: 51.5074, lon: -0.1278 }], [{ lat: 51.4545, lon: -2.5879 }, { lat: 52.4862, lon: -1.8904 }], 'walk' ) // matrix.entries contains: { originIndex, destinationIndex, durationMinutes, distanceKm } ``` -------------------------------- ### Project Build and Development Commands Source: https://github.com/forgesworn/rendezvous-kit/blob/main/AGENTS.md Standard npm scripts for managing the project lifecycle. ```bash npm install # install dependencies npm run build # compile TypeScript → dist/ npm test # run all tests (vitest) npm run typecheck # type-check without emitting npm run bench # performance benchmarks ``` -------------------------------- ### Run Development Commands Source: https://github.com/forgesworn/rendezvous-kit/blob/main/CONTRIBUTING.md Commonly used npm scripts for testing, benchmarking, and type checking. ```bash npm test # run all tests npm run test:watch # watch mode npm run bench # benchmarks npm run typecheck # type checking only ``` -------------------------------- ### Prepare and Run OSRM Docker Container Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md This sequence of commands prepares OpenStreetMap data for OSRM by extracting, partitioning, and customizing it, then runs the OSRM backend server. Ensure the data path is correct. ```bash # Download and prepare data wget https://download.geofabrik.de/europe/great-britain-latest.osm.pbf docker run -t -v $(pwd):/data osrm/osrm-backend osrm-extract -p /opt/car.lua /data/great-britain-latest.osm.pbf docker run -t -v $(pwd):/data osrm/osrm-backend osrm-partition /data/great-britain-latest.osrm docker run -t -v $(pwd):/data osrm/osrm-backend osrm-customize /data/great-britain-latest.osrm # Run the server docker run -d --name osrm \ -p 5000:5000 \ -v $(pwd):/data \ osrm/osrm-backend osrm-routed --algorithm mld /data/great-britain-latest.osrm ``` -------------------------------- ### Comparing Fairness Strategies in a Table Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/choosing-a-fairness-strategy.md Presents a scenario comparing the three fairness strategies (`min_max`, `min_total`, `min_variance`) across two candidate cafés, highlighting how each strategy might select a different optimal venue based on its optimization goal. ```text | Café | Alice | Bob | Carol | min_max | min_total | min_variance | |------|-------|-----|-------|---------|-----------|--------------| | The Fox | 25 min | 50 min | 25 min | 50 | 100 | 11.8 | | The Bear | 35 min | 35 min | 35 min | 35 | 105 | 0.0 | ``` -------------------------------- ### Valhalla Engine Initialization Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Initialize `ValhallaEngine` with the base URL of your Valhalla routing instance. Optional configuration includes custom headers for authentication and a request timeout in milliseconds. ```typescript import { ValhallaEngine, ValhallaError } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002', headers: { 'Authorization': 'Bearer token' }, // optional custom headers timeoutMs: 30000, // optional timeout (default 30s) }) ``` -------------------------------- ### Initialize and use OsrmEngine Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Configures the OSRM adapter for route matrices. Note that isochrone computation is not supported and will throw an error. ```typescript import { OsrmEngine } from 'rendezvous-kit/engines/osrm' const engine = new OsrmEngine({ baseUrl: 'http://localhost:5000', timeoutMs: 30000, }) // Route matrix works const matrix = await engine.computeRouteMatrix( [{ lat: 51.5074, lon: -0.1278 }], [{ lat: 51.4545, lon: -2.5879 }, { lat: 52.4862, lon: -1.8904 }], 'drive' ) // Isochrone throws an error try { await engine.computeIsochrone({ lat: 51.5074, lon: -0.1278 }, 'drive', 30) } catch (err) { // Error: OSRM does not support isochrone computation. Use Valhalla, ORS, or GraphHopper instead. } ``` -------------------------------- ### Run Valhalla Docker Container Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md Launches a Valhalla routing engine instance using the GIS-OPS Docker image. Ensure to map the correct port and provide tile URLs. The first run may take time to download and build tiles. ```bash docker run -d --name valhalla \ -p 8002:8002 \ -e tile_urls=https://download.geofabrik.de/europe/great-britain-latest.osm.pbf \ -v valhalla_data:/custom_files \ ghcr.io/gis-ops/docker-valhalla/valhalla:latest ``` -------------------------------- ### Routing Engines Initialization Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Configuration and initialization for OpenRouteService, GraphHopper, and OSRM routing engines. ```APIDOC ## Routing Engines ### OpenRouteServiceEngine - **Constructor**: `new OpenRouteServiceEngine({ apiKey: string, baseUrl?: string })` - **Description**: Supports isochrone and route matrix. Defaults to 'https://api.openrouteservice.org'. ### GraphHopperEngine - **Constructor**: `new GraphHopperEngine({ baseUrl: string, apiKey?: string })` - **Description**: Supports isochrone and route matrix. API key is optional for self-hosted. ### OsrmEngine - **Constructor**: `new OsrmEngine({ baseUrl: string })` - **Description**: Route matrix only. `computeIsochrone` will throw an error. ``` -------------------------------- ### Initialize and use GraphHopperEngine Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Configures the GraphHopper adapter for either self-hosted or cloud instances and performs routing operations. ```typescript import { GraphHopperEngine } from 'rendezvous-kit/engines/graphhopper' // Self-hosted (no API key) const engine = new GraphHopperEngine({ baseUrl: 'http://localhost:8989', timeoutMs: 30000, }) // Cloud instance (with API key) const cloudEngine = new GraphHopperEngine({ baseUrl: 'https://graphhopper.com/api/1', apiKey: 'your-graphhopper-key', }) const isochrone = await engine.computeIsochrone( { lat: 48.8566, lon: 2.3522 }, 'cycle', 20 ) const matrix = await engine.computeRouteMatrix( [{ lat: 48.8566, lon: 2.3522 }, { lat: 48.8738, lon: 2.2950 }], [{ lat: 48.8606, lon: 2.3376 }], 'drive' ) ``` -------------------------------- ### Initialize OpenRouteService Engine in rendezvous-kit Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md Instantiates the OpenRouteService engine client for rendezvous-kit. Requires an API key obtained from openrouteservice.org. ```typescript import { OpenRouteServiceEngine } from 'rendezvous-kit/engines/openrouteservice' const engine = new OpenRouteServiceEngine({ apiKey: 'your-api-key' }) ``` -------------------------------- ### Import everything from rendezvous-kit Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Import all available functions and classes from the rendezvous-kit library using the barrel export. This is convenient but may lead to larger bundle sizes. ```typescript // Barrel (everything) import { findRendezvous, ValhallaEngine, intersectPolygons } from 'rendezvous-kit' ``` -------------------------------- ### Importing rendezvous-kit modules Source: https://github.com/forgesworn/rendezvous-kit/blob/main/README.md Shows the available subpath exports for core functions, geometry utilities, routing engines, and venue search. ```typescript import { findRendezvous } from 'rendezvous-kit' // barrel import { intersectPolygons, intersectPolygonsAll, centroid, circleToPolygon, getDestinationPoint } from 'rendezvous-kit/geo' // geometry import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' import { OpenRouteServiceEngine } from 'rendezvous-kit/engines/openrouteservice' import { GraphHopperEngine } from 'rendezvous-kit/engines/graphhopper' import { OsrmEngine } from 'rendezvous-kit/engines/osrm' import { searchVenues } from 'rendezvous-kit/venues' import { findRendezvous } from 'rendezvous-kit/rendezvous' // same as barrel ``` -------------------------------- ### ValhallaEngine Adapter Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Adapter for self-hosted Valhalla routing instances. Supports isochrone computation, route matrices, and turn-by-turn routing. ```APIDOC ## ValhallaEngine ### Description An adapter for Valhalla routing instances, providing methods to compute isochrones, route matrices, and detailed routes. ### Method Class Instantiation and Method Calls ### Endpoint N/A (Library Class) ### Parameters #### Constructor - **options** (ValhallaEngineOptions) - Optional - Configuration options for the Valhalla engine. - **baseUrl** (string) - Required - The base URL of the Valhalla service. - **headers** (Object.) - Optional - Custom headers to include in requests. - **timeoutMs** (number) - Optional - Request timeout in milliseconds (default 30000). #### `computeIsochrone` Method - **origin** (Point) - Required - The starting point for the isochrone calculation. - **lat** (number) - Required - Latitude. - **lon** (number) - Required - Longitude. - **mode** ('drive' | 'cycle' | 'walk' | 'public_transit') - Required - The transport mode. - **timeBudgetMinutes** (number) - Required - The time budget in minutes. #### `computeRouteMatrix` Method - **origins** (Array) - Required - An array of origin points. - **destinations** (Array) - Required - An array of destination points. - **mode** ('drive' | 'cycle' | 'walk' | 'public_transit') - Required - The transport mode. #### `computeRoute` Method - **origin** (Point) - Required - The starting point of the route. - **destination** (Point) - Required - The ending point of the route. - **mode** ('drive' | 'cycle' | 'walk' | 'public_transit') - Required - The transport mode. ### Request Example ```typescript import { ValhallaEngine, ValhallaError } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002', headers: { 'Authorization': 'Bearer token' }, timeoutMs: 30000 }) // Compute isochrone const isochrone = await engine.computeIsochrone({ lat: 51.5074, lon: -0.1278 }, 'drive', 30) // Compute route matrix const matrix = await engine.computeRouteMatrix( [{ lat: 51.5074, lon: -0.1278 }, { lat: 51.4545, lon: -2.5879 }], [{ lat: 52.4862, lon: -1.8904 }, { lat: 52.2053, lon: 0.1218 }], 'drive' ) // Compute detailed route const route = await engine.computeRoute({ lat: 51.5074, lon: -0.1278 }, { lat: 52.4862, lon: -1.8904 }, 'drive') // Handle specific errors try { await engine.computeRoute({ lat: 51.5074, lon: -0.1278 }, { lat: 52.4862, lon: -1.8904 }, 'drive') } catch (err) { if (err instanceof ValhallaError && err.status === 402) { console.log('Payment required:', err.body) } } ``` ### Response #### Success Response (Isochrone) - **origin** (Point) - The origin point. - **mode** (string) - The transport mode. - **timeMinutes** (number) - The time budget in minutes. - **polygon** (GeoJSONPolygon) - The GeoJSON polygon representing the reachable area. #### Success Response (RouteMatrix) - **origins** (Array) - The input origin points. - **destinations** (Array) - The input destination points. - **entries** (Array) - An array of matrix entries containing travel times. #### Success Response (Route) - **origin** (Point) - The origin point. - **destination** (Point) - The destination point. - **mode** (string) - The transport mode. - **durationMinutes** (number) - The total duration in minutes. - **distanceKm** (number) - The total distance in kilometers. - **geometry** (GeoJSONLineString) - The GeoJSON LineString representing the route path. - **legs** (Array) - An array of route legs with detailed maneuver instructions. #### Error Response (ValhallaError) - **status** (number) - The HTTP status code of the error. - **body** (any) - The error response body from the Valhalla service. ``` -------------------------------- ### Initialize Valhalla Engine in rendezvous-kit Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md Instantiates the Valhalla engine client for rendezvous-kit. The baseUrl should point to your running Valhalla Docker container's exposed port. ```typescript import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' }) ``` -------------------------------- ### Find rendezvous points with Valhalla engine Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms.txt Demonstrates the main pipeline function to find meeting suggestions for multiple participants using the Valhalla routing engine. ```typescript import { findRendezvous } from 'rendezvous-kit' import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' }) const suggestions = await findRendezvous(engine, { participants: [ { lat: 51.5074, lon: -0.1278, label: 'Alice' }, { lat: 51.4545, lon: -2.5879, label: 'Bob' }, ], mode: 'drive', maxTimeMinutes: 60, venueTypes: ['cafe'], fairness: 'min_max', limit: 3, }) ``` -------------------------------- ### Routing Engines Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms.txt Initialization of supported routing engines for rendezvous calculations. ```APIDOC ## Routing Engine Constructors ### ValhallaEngine({ baseUrl: string }) Initializes a Valhalla routing engine. ### OpenRouteServiceEngine({ apiKey: string, baseUrl?: string }) Initializes an OpenRouteService engine. ### GraphHopperEngine({ baseUrl: string, apiKey?: string }) Initializes a GraphHopper engine. ### OsrmEngine({ baseUrl: string }) Initializes an OSRM engine (matrix only). ``` -------------------------------- ### Find Rendezvous Points Source: https://github.com/forgesworn/rendezvous-kit/blob/main/README.md Initialize a routing engine and execute the rendezvous search pipeline with participant locations and fairness preferences. ```typescript import { findRendezvous } from 'rendezvous-kit' import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' }) const suggestions = await findRendezvous(engine, { participants: [ { lat: 51.5074, lon: -0.1278, label: 'Alice' }, // London { lat: 51.4545, lon: -2.5879, label: 'Bob' }, // Bristol { lat: 52.4862, lon: -1.8904, label: 'Carol' }, // Birmingham ], mode: 'drive', maxTimeMinutes: 90, venueTypes: ['cafe', 'restaurant'], fairness: 'min_max', limit: 5, }) for (const s of suggestions) { console.log(`${s.venue.name} — score: ${s.fairnessScore.toFixed(1)} min`) console.log(' Travel times:', s.travelTimes) } ``` -------------------------------- ### Initialize OSRM Engine in rendezvous-kit Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md Instantiates the OSRM engine client for rendezvous-kit. Note that OSRM does not support isochrone computations, so it should only be used for route matrix calculations. ```typescript import { OsrmEngine } from 'rendezvous-kit/engines/osrm' const engine = new OsrmEngine({ baseUrl: 'http://localhost:5000' }) // Note: OSRM cannot compute isochrones — findRendezvous will throw. // Use OSRM for computeRouteMatrix only. ``` -------------------------------- ### Initialize GraphHopper Engine in rendezvous-kit Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md Instantiates the GraphHopper engine client for rendezvous-kit. The baseUrl should point to your running GraphHopper Docker container. ```typescript import { GraphHopperEngine } from 'rendezvous-kit/engines/graphhopper' const engine = new GraphHopperEngine({ baseUrl: 'http://localhost:8989' }) ``` -------------------------------- ### Fairness Strategies for Rendezvous Planning Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Demonstrates three strategies ('min_max', 'min_total', 'min_variance') for scoring venues based on participant travel times using the `findRendezvous` function. Requires an engine (e.g., `ValhallaEngine`) and participant data. ```typescript import { findRendezvous } from 'rendezvous-kit' import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' import type { FairnessStrategy } from 'rendezvous-kit' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' }) const participants = [ { lat: 51.5074, lon: -0.1278, label: 'Alice' }, { lat: 51.4545, lon: -2.5879, label: 'Bob' }, { lat: 52.4862, lon: -1.8904, label: 'Carol' }, ] // min_max: Minimise worst-case travel time (default) // Score = max(travel times) - nobody travels excessively // Alice: 30, Bob: 45, Carol: 20 => score = 45 const minMaxResults = await findRendezvous(engine, { participants, mode: 'drive', maxTimeMinutes: 90, venueTypes: ['cafe'], fairness: 'min_max', }) // min_total: Minimise sum of all travel times // Score = sum(travel times) - minimise group effort // Alice: 30, Bob: 45, Carol: 20 => score = 95 const minTotalResults = await findRendezvous(engine, { participants, mode: 'drive', maxTimeMinutes: 90, venueTypes: ['cafe'], fairness: 'min_total', }) // min_variance: Equalise travel times (standard deviation) // Score = stddev(travel times) - everyone travels roughly equally // Alice: 30, Bob: 45, Carol: 20 => score = 10.3 // Alice: 35, Bob: 32, Carol: 33 => score = 1.2 (preferred) const minVarianceResults = await findRendezvous(engine, { participants, mode: 'drive', maxTimeMinutes: 90, venueTypes: ['cafe'], fairness: 'min_variance', }) // Compare strategies side-by-side const strategies: FairnessStrategy[] = ['min_max', 'min_total', 'min_variance'] for (const fairness of strategies) { const results = await findRendezvous(engine, { participants, mode: 'drive', maxTimeMinutes: 90, venueTypes: ['cafe', 'pub'], fairness, limit: 3, }) console.log(` === ${fairness} ===`) for (const s of results) { console.log(`${s.venue.name}: score=${s.fairnessScore.toFixed(1)}`) } } ``` -------------------------------- ### Import specific modules from rendezvous-kit Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Import specific functions and classes from their respective subpaths for better tree-shaking and smaller bundle sizes. This approach is recommended for production builds. ```typescript // Subpath (tree-shakeable) import { findRendezvous } from 'rendezvous-kit/rendezvous' ``` ```typescript import { intersectPolygons, boundingBox, centroid, polygonArea } from 'rendezvous-kit/geo' ``` ```typescript import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' ``` ```typescript import { OpenRouteServiceEngine } from 'rendezvous-kit/engines/openrouteservice' ``` ```typescript import { GraphHopperEngine } from 'rendezvous-kit/engines/graphhopper' ``` ```typescript import { OsrmEngine } from 'rendezvous-kit/engines/osrm' ``` ```typescript import { searchVenues } from 'rendezvous-kit/venues' ``` -------------------------------- ### Implement Custom Routing Engine Source: https://github.com/forgesworn/rendezvous-kit/blob/main/README.md Implement the RoutingEngine interface to create a custom routing engine. This involves defining methods for computing isochrones, route matrices, and routes. ```typescript import type { RoutingEngine, LatLon, TransportMode, Isochrone, RouteMatrix, RouteGeometry } from 'rendezvous-kit' class MyEngine implements RoutingEngine { readonly name = 'MyEngine' async computeIsochrone(origin: LatLon, mode: TransportMode, timeMinutes: number): Promise { // call your API and return an Isochrone } async computeRouteMatrix(origins: LatLon[], destinations: LatLon[], mode: TransportMode): Promise { // call your API and return a RouteMatrix } async computeRoute(origin: LatLon, destination: LatLon, mode: TransportMode): Promise { // call your API and return a RouteGeometry with optional turn-by-turn legs } } ``` -------------------------------- ### Repository Directory Structure Source: https://github.com/forgesworn/rendezvous-kit/blob/main/AGENTS.md Overview of the source code organization within the project. ```text src/ types.ts — All shared interfaces and types geo.ts — Polygon geometry (intersection, area, bbox, centroid, circle) hull.ts — Convex hull fast-path strategy engines/ — Routing engine adapters (Valhalla, ORS, GraphHopper, OSRM) venues.ts — Overpass API venue search rendezvous.ts — Main pipeline function validate.ts — Input validation helpers index.ts — Barrel re-export examples/ — Runnable TypeScript examples docs/ — Guides + interactive demo page (GitHub Pages) ``` -------------------------------- ### Hull Strategy Utilities in TypeScript Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Provides functions for the fast-path hull strategy, including checking speeds, automatically choosing between 'hull' and 'isochrone' strategies based on participant proximity, and computing/buffering search hulls. Imports from 'rendezvous-kit'. ```typescript import { chooseStrategy, computeSearchHull, bufferHull, SPEED_KMH } from 'rendezvous-kit' import type { LatLon, TransportMode } from 'rendezvous-kit' const participants: LatLon[] = [ { lat: 51.5074, lon: -0.1278 }, { lat: 51.5200, lon: -0.1000 }, { lat: 51.4900, lon: -0.1400 }, ] // Check approximate speeds used for hull calculations console.log(SPEED_KMH) // { drive: 50, cycle: 15, walk: 5, public_transit: 30 } // Automatically choose strategy based on participant spread const strategy = chooseStrategy(participants, 'drive', 30) // Returns: 'hull' (if participants are close) or 'isochrone' (if spread out) // Compute buffered convex hull for venue search const hull: [number, number][] = computeSearchHull(participants, 'drive', 30) // Returns: Array of [lon, lat] coordinates forming the search polygon // Manually buffer an existing hull const expandedHull = bufferHull(hull, 5) // expand by 5 km ``` -------------------------------- ### Find Rendezvous - Three Participants (Valhalla) Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Finds optimal meeting venues for three participants using the Valhalla engine, prioritizing minimizing the worst-case travel time. ```typescript import { findRendezvous } from 'rendezvous-kit' import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' }) const suggestions = await findRendezvous(engine, { participants: [ { lat: 51.5074, lon: -0.1278, label: 'Alice' }, // London { lat: 51.4545, lon: -2.5879, label: 'Bob' }, // Bristol { lat: 52.4862, lon: -1.8904, label: 'Carol' }, // Birmingham ], mode: 'drive', maxTimeMinutes: 90, venueTypes: ['cafe', 'restaurant'], fairness: 'min_max', limit: 5, }) // suggestions[0] is the venue with the lowest worst-case travel time console.log(suggestions[0].venue.name) console.log(suggestions[0].travelTimes) // { Alice: 72.3, Bob: 81.1, Carol: 68.4 } console.log(suggestions[0].fairnessScore) // 81.1 (max of travel times, for min_max) ``` -------------------------------- ### Find Rendezvous with Specified Fairness Strategy Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/choosing-a-fairness-strategy.md Demonstrates how to use the `findRendezvous` function with a specific fairness strategy. You can choose between 'min_variance', 'min_max' (default), or 'min_total'. Ensure participants, mode, max time, and venue types are configured. ```typescript const suggestions = await findRendezvous(engine, { participants: [alice, bob, carol], mode: 'drive', maxTimeMinutes: 60, venueTypes: ['cafe'], fairness: 'min_variance', // or 'min_max' (default), 'min_total' }) ``` -------------------------------- ### Merge OSM PBF Files with Osmium Source: https://github.com/forgesworn/rendezvous-kit/blob/main/docs/self-hosting-a-routing-engine.md Combines multiple OpenStreetMap PBF files into a single file using the Osmium tool. This is useful for covering non-contiguous regions. ```bash osmium merge england.osm.pbf scotland.osm.pbf wales.osm.pbf -o gb.osm.pbf ``` -------------------------------- ### Routing Engines Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Information about supported routing engines for the Rendezvous Kit. ```APIDOC ## Engines ### ValhallaEngine **Description:** Integrates with a self-hosted [Valhalla](https://github.com/valhalla/valhalla) routing engine. Supports isochrone and route matrix calculations. No authentication is required. **Usage:** ```typescript class ValhallaEngine implements RoutingEngine { readonly name = 'Valhalla' constructor(config: { baseUrl: string }) } ``` **Example:** ```typescript import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' }) ``` **Transport Mode Mapping:** - `drive` maps to `auto` - `cycle` maps to `bicycle` - `walk` maps to `pedestrian` - `public_transit` maps to `multimodal` ``` -------------------------------- ### Geometry Utilities in TypeScript Source: https://context7.com/forgesworn/rendezvous-kit/llms.txt Provides functions for calculating bounding boxes, centroids, areas, and creating polygons for circles and destination points using GeoJSON data. Ensure 'rendezvous-kit/geo' is imported. ```typescript import { boundingBox, centroid, polygonArea, circleToPolygon, getDestinationPoint, } from 'rendezvous-kit/geo' import type { GeoJSONPolygon, BBox, Coordinate } from 'rendezvous-kit' const polygon: GeoJSONPolygon = { type: 'Polygon', coordinates: [[[-0.15, 51.50], [-0.10, 51.50], [-0.10, 51.52], [-0.15, 51.52], [-0.15, 51.50]]], } // Axis-aligned bounding box const bbox: BBox = boundingBox(polygon) // { minLon: -0.15, minLat: 51.50, maxLon: -0.10, maxLat: 51.52 } // Geometric centroid const center: Coordinate = centroid(polygon) // { lon: -0.125, lat: 51.51 } // Approximate area in square metres const area: number = polygonArea(polygon) // ~1,850,000 (m^2) // Create a circle polygon (e.g., for fallback search areas) const circle: GeoJSONPolygon = circleToPolygon( [-0.1278, 51.5074], // centre [lon, lat] 5000, // radius in metres 64 // number of segments (default 64) ) // Haversine destination point (for expanding search areas) const destination: [number, number] = getDestinationPoint( [-0.1278, 51.5074], // start [lon, lat] 10000, // distance in metres 45 // bearing in degrees (0=north, 90=east) ) // Returns: [lon, lat] ``` -------------------------------- ### rendezvous-kit/geo Utilities Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Geometric utility functions for polygon manipulation and analysis. ```APIDOC ## rendezvous-kit/geo ### intersectPolygons(polygons) **Description:** Computes the intersection of N GeoJSON polygons using the Sutherland–Hodgman algorithm. **Parameters:** - **polygons** (Array) - An array of GeoJSON polygons. **Returns:** GeoJSONPolygon | null - The intersection polygon, or null if the intersection is empty or any input polygon is degenerate. **Examples:** ```typescript // Single polygon — returned unchanged intersectPolygons([poly]) // poly // Two overlapping polygons intersectPolygons([polyA, polyB]) // intersection polygon // No overlap intersectPolygons([polyA, polyFarAway]) // null ``` ### boundingBox(polygon) **Description:** Computes the axis-aligned bounding box of a GeoJSON polygon. **Parameters:** - **polygon** (GeoJSONPolygon) - The input GeoJSON polygon. **Returns:** BBox - An object representing the bounding box with `minLon`, `minLat`, `maxLon`, and `maxLat` properties. **Example:** ```typescript boundingBox(poly) // { minLon: -0.15, minLat: 51.50, maxLon: -0.10, maxLat: 51.52 } ``` ### centroid(polygon) **Description:** Computes the arithmetic centroid of the outer ring of a GeoJSON polygon. **Parameters:** - **polygon** (GeoJSONPolygon) - The input GeoJSON polygon. **Returns:** { lat: number; lon: number } - An object containing the latitude and longitude of the centroid. **Example:** ```typescript centroid(poly) // { lat: 51.51, lon: -0.125 } ``` ### polygonArea(polygon) **Description:** Computes the area of a GeoJSON polygon in square metres using the shoelace formula with local metric projection. **Parameters:** - **polygon** (GeoJSONPolygon) - The input GeoJSON polygon. **Returns:** number - The area of the polygon in square metres. **Example:** ```typescript polygonArea(poly) // area in m² ``` ``` -------------------------------- ### Define OpenRouteServiceEngine Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Class definition for the OpenRouteService engine. ```typescript class OpenRouteServiceEngine implements RoutingEngine { readonly name = 'OpenRouteService' constructor(options: { apiKey: string; baseUrl?: string }) // baseUrl defaults to 'https://api.openrouteservice.org' } ``` -------------------------------- ### Find Rendezvous - Two Participants (OpenRouteService) Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Finds optimal meeting venues for two participants using the OpenRouteService engine, prioritizing minimizing travel time variance. ```typescript import { findRendezvous } from 'rendezvous-kit' import { OpenRouteServiceEngine } from 'rendezvous-kit/engines/openrouteservice' const engine = new OpenRouteServiceEngine({ apiKey: 'your-api-key' }) const suggestions = await findRendezvous(engine, { participants: [ { lat: 48.8566, lon: 2.3522, label: 'Paris' }, { lat: 50.8503, lon: 4.3517, label: 'Brussels' }, ], mode: 'drive', maxTimeMinutes: 120, venueTypes: ['restaurant'], fairness: 'min_variance', }) ``` -------------------------------- ### Fairness Strategies Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Explanation of the different fairness strategies available for scoring venues. ```APIDOC ## Fairness Strategies ### min_max (default) **Description:** Minimises the maximum travel time among all participants. **Score Calculation:** `Math.max(...travelTimes)` **Use Case:** Best when you want to guarantee nobody has an excessively long journey. The classic minimax fairness criterion. ### min_total **Description:** Minimises the total travel time across all participants. **Score Calculation:** `sum(travelTimes)` **Use Case:** Best when you want the group's combined travel effort to be as low as possible. Can allow one person to travel much further than others. ### min_variance **Description:** Minimises variance in travel times (standard deviation). **Score Calculation:** `sqrt(variance(travelTimes))` **Use Case:** Best when you want everyone to travel roughly the same distance. Venues near the geometric centre of the group tend to score well. ``` -------------------------------- ### findRendezvous Source: https://github.com/forgesworn/rendezvous-kit/blob/main/llms-full.txt Runs the full rendezvous pipeline to compute and return ranked venue suggestions based on participant locations, travel preferences, and fairness strategies. ```APIDOC ## findRendezvous(engine, options) ### Description Computes an isochrone for each participant, intersects them, searches for venues within the intersection, calculates travel times, scores venues based on a selected fairness strategy, and returns the top ranked suggestions. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **engine** (RoutingEngine) - The routing engine to use for calculations (e.g., ValhallaEngine, OpenRouteServiceEngine). - **options** (RendezvousOptions) - **participants** (Array<{ lat: number; lon: number; label: string }>) - An array of participant objects, each with latitude, longitude, and an optional label. - **mode** (string) - The travel mode (e.g., 'drive', 'cycle', 'walk', 'public_transit'). - **maxTimeMinutes** (number) - The maximum allowed travel time in minutes for any participant. - **venueTypes** (Array) - An array of venue types to search for (e.g., 'cafe', 'restaurant'). - **fairness** (string) - The fairness strategy to use ('min_max', 'min_total', 'min_variance'). Defaults to 'min_max'. - **limit** (number) - The maximum number of suggestions to return. Defaults to 5. ### Request Example ```typescript import { findRendezvous } from 'rendezvous-kit' import { ValhallaEngine } from 'rendezvous-kit/engines/valhalla' const engine = new ValhallaEngine({ baseUrl: 'http://localhost:8002' }) const suggestions = await findRendezvous(engine, { participants: [ { lat: 51.5074, lon: -0.1278, label: 'Alice' }, // London { lat: 51.4545, lon: -2.5879, label: 'Bob' }, // Bristol { lat: 52.4862, lon: -1.8904, label: 'Carol' }, // Birmingham ], mode: 'drive', maxTimeMinutes: 90, venueTypes: ['cafe', 'restaurant'], fairness: 'min_max', limit: 5, }) console.log(suggestions[0].venue.name) console.log(suggestions[0].travelTimes) // { Alice: 72.3, Bob: 81.1, Carol: 68.4 } console.log(suggestions[0].fairnessScore) // 81.1 ``` ### Response #### Success Response (200) - **venue** (object) - Details of the suggested venue. - **travelTimes** (object) - An object mapping participant labels to their travel times to the venue. - **fairnessScore** (number) - The calculated fairness score for the venue. #### Response Example ```json { "venue": { "name": "The Cozy Cafe", "lat": 51.5000, "lon": -0.1200 }, "travelTimes": { "Alice": 30.5, "Bob": 75.2, "Carol": 60.1 }, "fairnessScore": 75.2 } ``` ### Error Handling - Throws `RangeError` if `participants.length < 2`. ```