@ingissa/navcore-core 1.0.0 → 1.0.1
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 +279 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# @ingissa/navcore-core
|
|
2
|
+
|
|
3
|
+
> **The navigation layer you own.** A framework-agnostic, zero-dependency navigation engine that runs everywhere — browsers, React Native, Node.js, and CI/CD.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@ingissa/navcore-core)
|
|
6
|
+
[](https://navcore.dev/pricing)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://www.npmjs.com/package/@ingissa/navcore-core)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Why NavCore?
|
|
13
|
+
|
|
14
|
+
| Feature | NavCore | Mapbox Nav SDK | Google Maps |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
| **Framework** | Any (pure TS) | React Native only | Platform-locked |
|
|
17
|
+
| **Runtime deps** | 0 | 50+ | N/A |
|
|
18
|
+
| **Map renderer** | BYO (adapter) | Mapbox GL only | Google Maps only |
|
|
19
|
+
| **Directions** | BYO (adapter) | Mapbox API only | Google API only |
|
|
20
|
+
| **Off-route detection** | Built-in FSM | Basic | Basic |
|
|
21
|
+
| **U-turn protection** | ✅ Bearing penalty | ❌ | ❌ |
|
|
22
|
+
| **Parallel road resolver** | ✅ Built-in | ❌ | ❌ |
|
|
23
|
+
| **Dead reckoning** | ✅ Built-in | ❌ | ❌ |
|
|
24
|
+
| **Geofencing** | ✅ Built-in | ❌ | Paid API |
|
|
25
|
+
| **ETA** | ✅ Offline | API only | API only |
|
|
26
|
+
| **Voice triggers** | ✅ Built-in | SDK only | ❌ |
|
|
27
|
+
| **Headless testing** | ✅ Full pipeline | ❌ | ❌ |
|
|
28
|
+
| **Custom routes** | ✅ GPX/GeoJSON/Builder | ❌ | ❌ |
|
|
29
|
+
| **License** | Core MIT / Pro commercial | Commercial | Commercial |
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Tier Model
|
|
34
|
+
|
|
35
|
+
NavCore uses a two-tier model controlled by a signed license key:
|
|
36
|
+
|
|
37
|
+
| Tier | Import | License | Includes |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| **Core** | `@ingissa/navcore-core/core` | MIT — free forever | Geo utils, Kalman filter, route snapping, directions adapters, route builder |
|
|
40
|
+
| **Pro** | `@ingissa/navcore-core/pro` | Commercial key required | Dead reckoning, advanced bearing, deviation detection, FSMs, voice, ETA, geofencing |
|
|
41
|
+
| **Engine** | `@ingissa/navcore-core` | Gated internally at runtime | Full `NavCore` orchestrator (license key unlocks Pro features) |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @ingissa/navcore-core
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### Core tier (no license needed)
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { NavCore } from '@ingissa/navcore-core';
|
|
59
|
+
import { OSRMDirectionsProvider } from '@ingissa/navcore-core/core';
|
|
60
|
+
|
|
61
|
+
// 1. Get a route from your self-hosted OSRM (free)
|
|
62
|
+
const provider = new OSRMDirectionsProvider({ baseUrl: 'http://router.project-osrm.org' });
|
|
63
|
+
const route = await provider.getRoute([[2.3522, 48.8566], [2.3400, 48.8700]]);
|
|
64
|
+
|
|
65
|
+
// 2. Create engine (Core features work without a key)
|
|
66
|
+
const engine = new NavCore();
|
|
67
|
+
engine.setRoute(route.geometry);
|
|
68
|
+
engine.startNavigation();
|
|
69
|
+
|
|
70
|
+
// 3. Feed GPS updates
|
|
71
|
+
engine.on('arrival', () => console.log('Arrived!'));
|
|
72
|
+
|
|
73
|
+
navigator.geolocation.watchPosition(({ coords }) => {
|
|
74
|
+
const state = engine.update({
|
|
75
|
+
coord: [coords.longitude, coords.latitude],
|
|
76
|
+
accuracy: coords.accuracy,
|
|
77
|
+
bearing: coords.heading,
|
|
78
|
+
speed: coords.speed ?? 0,
|
|
79
|
+
timestamp: Date.now(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
console.log('Distance remaining:', state.distanceToDestination, 'm');
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Pro tier (with license key)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { NavCore } from '@ingissa/navcore-core';
|
|
90
|
+
|
|
91
|
+
// Pro features unlock automatically with a valid key
|
|
92
|
+
const engine = new NavCore({ licenseKey: 'your-signed-license-key' });
|
|
93
|
+
engine.setRoute(routeCoords, instructions);
|
|
94
|
+
engine.startNavigation();
|
|
95
|
+
|
|
96
|
+
engine.on('instruction', (instr) => speak(instr.text)); // voice cues (PRO)
|
|
97
|
+
engine.on('deviation', ({ anchorIndex }) => recalculate(anchorIndex));
|
|
98
|
+
engine.on('arrival', () => console.log('Arrived!'));
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Using subpath imports directly
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Free MIT tier
|
|
105
|
+
import { KalmanFilter2D } from '@ingissa/navcore-core/core';
|
|
106
|
+
import { OSRMDirectionsProvider } from '@ingissa/navcore-core/core';
|
|
107
|
+
import { CustomRouteBuilder } from '@ingissa/navcore-core/core';
|
|
108
|
+
|
|
109
|
+
// Commercial Pro tier
|
|
110
|
+
import { DeadReckoningEngine } from '@ingissa/navcore-core/pro';
|
|
111
|
+
import { VoiceTriggerEngine } from '@ingissa/navcore-core/pro';
|
|
112
|
+
import { ETAEngine } from '@ingissa/navcore-core/pro';
|
|
113
|
+
import { GeofencingEngine } from '@ingissa/navcore-core/pro';
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Directions Providers (built-in, no extra install)
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import {
|
|
122
|
+
OSRMDirectionsProvider, // Self-hosted OSRM (recommended, free)
|
|
123
|
+
ValhallaDirectionsProvider, // Self-hosted Valhalla (free)
|
|
124
|
+
OpenRouteServiceProvider, // openrouteservice.org (free tier)
|
|
125
|
+
} from '@ingissa/navcore-core/core';
|
|
126
|
+
|
|
127
|
+
// OSRM
|
|
128
|
+
const osrm = new OSRMDirectionsProvider({ baseUrl: 'http://router.project-osrm.org' });
|
|
129
|
+
const route = await osrm.getRoute([[lng1, lat1], [lng2, lat2]]);
|
|
130
|
+
|
|
131
|
+
// Valhalla
|
|
132
|
+
const valhalla = new ValhallaDirectionsProvider({ baseUrl: 'https://valhalla1.openstreetmap.de' });
|
|
133
|
+
const route = await valhalla.getRoute([[lng1, lat1], [lng2, lat2]], { costing: 'auto' });
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Renderer Adapters (separate packages)
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm install @ingissa/navcore-maplibre # Web + MapLibre GL
|
|
142
|
+
npm install @ingissa/navcore-leaflet # Web + Leaflet.js
|
|
143
|
+
npm install @ingissa/navcore-google-maps # Google Maps JS API
|
|
144
|
+
npm install @ingissa/navcore-mapbox # React Native + @rnmapbox/maps
|
|
145
|
+
npm install @ingissa/navcore-react-native # React Native bindings
|
|
146
|
+
npm install @ingissa/navcore-headless # Node.js / CI testing
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
> ⚠️ Renderer adapter packages require a commercial license. [Get yours at navcore.dev/pricing](https://navcore.dev/pricing)
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Feature Reference
|
|
154
|
+
|
|
155
|
+
### CORE — free, MIT
|
|
156
|
+
|
|
157
|
+
| Feature | API |
|
|
158
|
+
|---|---|
|
|
159
|
+
| GPS smoothing | `KalmanFilter2D` |
|
|
160
|
+
| Route snapping | `RouteSnapper` |
|
|
161
|
+
| Haversine & bearing | `haversineDistance`, `getBearingBetweenPoints` |
|
|
162
|
+
| Cumulative distances | `buildForwardCumulativeDistances` |
|
|
163
|
+
| Route builder | `CustomRouteBuilder` |
|
|
164
|
+
| Directions — OSRM | `OSRMDirectionsProvider` |
|
|
165
|
+
| Directions — Valhalla | `ValhallaDirectionsProvider` |
|
|
166
|
+
| Directions — ORS | `OpenRouteServiceProvider` |
|
|
167
|
+
| Renderer interface | `MapRendererAdapter` |
|
|
168
|
+
| License verification | `LicenseManager` |
|
|
169
|
+
|
|
170
|
+
### PRO — commercial license required
|
|
171
|
+
|
|
172
|
+
| Feature | API | FEATURES key |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| Advanced snapping (bearing + inertia) | `RouteSnapper` options | `ADVANCED_SNAPPING` |
|
|
175
|
+
| Parallel road resolver | `ParallelRoadResolver` | `PARALLEL_ROAD_RESOLUTION` |
|
|
176
|
+
| Dead reckoning | `DeadReckoningEngine` | `DEAD_RECKONING` |
|
|
177
|
+
| Compound deviation detection | `DeviationDetector` | `COMPOUND_DEVIATION` |
|
|
178
|
+
| Advanced bearing engine | `BearingEngine` | `ADVANCED_BEARING` |
|
|
179
|
+
| Progress anti-regression | `ProgressTracker` | `PROGRESS_TRACKING` |
|
|
180
|
+
| Route offset predictor | `RouteOffsetPredictor` | `ROUTE_OFFSET` |
|
|
181
|
+
| Navigation lifecycle FSM | `NavigationFSM` | — |
|
|
182
|
+
| Off-route FSM | `OffRouteFSM` | — |
|
|
183
|
+
| Instruction editor | `InstructionEditor` | — |
|
|
184
|
+
| Voice trigger engine | `VoiceTriggerEngine` | `VOICE_TRIGGERS` |
|
|
185
|
+
| ETA engine (offline) | `ETAEngine` | `ETA` |
|
|
186
|
+
| Geofencing engine | `GeofencingEngine` | `GEOFENCING` |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## License Gate Behaviour
|
|
191
|
+
|
|
192
|
+
| Condition | Result |
|
|
193
|
+
|---|---|
|
|
194
|
+
| No `licenseKey` | Core features work; Pro features blocked with `console.warn` |
|
|
195
|
+
| Valid Pro key | All features unlocked; `🔑 [NavCore] License validation complete. Plan: pro` logged |
|
|
196
|
+
| `isDev: true` | All features bypassed (development mode) |
|
|
197
|
+
| Expired / tampered key | Pro features blocked; status: `EXPIRED` / `INVALID` |
|
|
198
|
+
|
|
199
|
+
License keys are verified **offline** using ECDSA P-256 — no network calls, no tracking.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## NavCore Engine API
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
const engine = new NavCore(options?: NavCoreOptions);
|
|
207
|
+
|
|
208
|
+
// Setup
|
|
209
|
+
engine.setRoute(coords: Coordinate[], instructions?: NavInstruction[]);
|
|
210
|
+
engine.startNavigation();
|
|
211
|
+
|
|
212
|
+
// GPS update (returns state snapshot)
|
|
213
|
+
const state: NavCoreState = engine.update(gpsUpdate: NavGpsUpdate);
|
|
214
|
+
|
|
215
|
+
// Render tick (call at ~60fps between GPS updates)
|
|
216
|
+
engine.tick(nowMs: number);
|
|
217
|
+
|
|
218
|
+
// Events
|
|
219
|
+
engine.on('instruction', (instr: NavInstruction) => void);
|
|
220
|
+
engine.on('deviation', ({ anchorIndex, ghostCoord }) => void);
|
|
221
|
+
engine.on('arrival', () => void);
|
|
222
|
+
engine.on('routeLoaded', ({ routeLength }) => void);
|
|
223
|
+
engine.off(event, handler);
|
|
224
|
+
|
|
225
|
+
// State & introspection
|
|
226
|
+
engine.getState(): NavCoreState;
|
|
227
|
+
engine.getLicenseManager(): LicenseManager;
|
|
228
|
+
engine.getRoute(): ReadonlyArray<Coordinate>;
|
|
229
|
+
engine.destroy();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### NavCoreState
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
interface NavCoreState {
|
|
236
|
+
snappedCoord: Coordinate | null; // GPS-snapped position on route
|
|
237
|
+
rawGpsCoord: Coordinate | null; // Raw GPS position
|
|
238
|
+
bearing: number; // Smoothed heading (degrees)
|
|
239
|
+
routeIndex: number; // Current segment index
|
|
240
|
+
distanceToRoute: number; // Distance from route (metres)
|
|
241
|
+
corridor: number; // Dynamic off-route threshold (metres)
|
|
242
|
+
isOffRoute: boolean; // True when deviation confirmed
|
|
243
|
+
hasArrived: boolean;
|
|
244
|
+
distanceToDestination: number | null; // Remaining distance (metres)
|
|
245
|
+
distanceToNextInstruction: number | null; // Distance to next turn
|
|
246
|
+
nextInstructionIndex: number | null;
|
|
247
|
+
currentSpeed: number; // m/s
|
|
248
|
+
isGpsStale: boolean;
|
|
249
|
+
gpsAgeMs: number;
|
|
250
|
+
licenseStatus: string; // 'VALID' | 'INVALID' | 'EXPIRED' | 'MISSING'
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Documentation
|
|
257
|
+
|
|
258
|
+
| Guide | Link |
|
|
259
|
+
|---|---|
|
|
260
|
+
| Architecture | [docs/architecture.md](./docs/architecture.md) |
|
|
261
|
+
| Getting Started | [docs/getting-started.md](./docs/getting-started.md) |
|
|
262
|
+
| Directions Providers | [docs/directions-providers.md](./docs/directions-providers.md) |
|
|
263
|
+
| Renderer Adapters | [docs/renderer-adapters.md](./docs/renderer-adapters.md) |
|
|
264
|
+
| API Reference | [docs/api-reference.md](./docs/api-reference.md) |
|
|
265
|
+
| Custom Routes | [docs/custom-routes.md](./docs/custom-routes.md) |
|
|
266
|
+
| Instructions & Voice | [docs/instructions.md](./docs/instructions.md) |
|
|
267
|
+
| Pro Features | [docs/p3-features.md](./docs/p3-features.md) |
|
|
268
|
+
| Testing Guide | [docs/testing.md](./docs/testing.md) |
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
- **Core engine** (`@ingissa/navcore-core`): [MIT](./LICENSE) for open-source projects
|
|
275
|
+
- **Pro features & adapters**: Commercial license required — [navcore.dev/pricing](https://navcore.dev/pricing)
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
© Ingissa · [navcore.dev](https://navcore.dev) · [contact@navcore.dev](mailto:contact@navcore.dev)
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingissa/navcore-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "NavCore navigation engine — zero runtime dependencies. Framework-agnostic. Works in browsers, React Native, Node.js, and CI/CD.",
|
|
5
5
|
"author": "Ingissa <contact@navcore.dev>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://navcore.dev",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
|
-
"url": "https://github.com/ingissa/navcore-sdk"
|
|
10
|
+
"url": "git+https://github.com/ingissa/navcore-sdk.git"
|
|
11
11
|
},
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/ingissa/navcore-sdk/issues"
|