@mappedin/blue-dot 6.15.0-beta.0 → 6.17.0-beta.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.
@@ -0,0 +1,3039 @@
1
+ import { Coordinate, Floor, MapView, Model } from "@mappedin/mappedin-js";
2
+
3
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/primitive.d.ts
4
+
5
+ /**
6
+ Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
7
+
8
+ @category Type
9
+ */
10
+ type Primitive = null | undefined | string | number | boolean | symbol | bigint;
11
+ //#endregion
12
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/is-any.d.ts
13
+ /**
14
+ Returns a boolean for whether the given type is `any`.
15
+
16
+ @link https://stackoverflow.com/a/49928360/1490091
17
+
18
+ Useful in type utilities, such as disallowing `any`s to be passed to a function.
19
+
20
+ @example
21
+ ```
22
+ import type {IsAny} from 'type-fest';
23
+
24
+ const typedObject = {a: 1, b: 2} as const;
25
+ const anyObject: any = {a: 1, b: 2};
26
+
27
+ function get<O extends (IsAny<O> extends true ? {} : Record<string, number>), K extends keyof O = keyof O>(object: O, key: K) {
28
+ return object[key];
29
+ }
30
+
31
+ const typedA = get(typedObject, 'a');
32
+ //=> 1
33
+
34
+ const anyA = get(anyObject, 'a');
35
+ //=> any
36
+ ```
37
+
38
+ @category Type Guard
39
+ @category Utilities
40
+ */
41
+ type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
42
+ //#endregion
43
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/is-optional-key-of.d.ts
44
+ /**
45
+ Returns a boolean for whether the given key is an optional key of type.
46
+
47
+ This is useful when writing utility types or schema validators that need to differentiate `optional` keys.
48
+
49
+ @example
50
+ ```
51
+ import type {IsOptionalKeyOf} from 'type-fest';
52
+
53
+ type User = {
54
+ name: string;
55
+ surname: string;
56
+
57
+ luckyNumber?: number;
58
+ };
59
+
60
+ type Admin = {
61
+ name: string;
62
+ surname?: string;
63
+ };
64
+
65
+ type T1 = IsOptionalKeyOf<User, 'luckyNumber'>;
66
+ //=> true
67
+
68
+ type T2 = IsOptionalKeyOf<User, 'name'>;
69
+ //=> false
70
+
71
+ type T3 = IsOptionalKeyOf<User, 'name' | 'luckyNumber'>;
72
+ //=> boolean
73
+
74
+ type T4 = IsOptionalKeyOf<User | Admin, 'name'>;
75
+ //=> false
76
+
77
+ type T5 = IsOptionalKeyOf<User | Admin, 'surname'>;
78
+ //=> boolean
79
+ ```
80
+
81
+ @category Type Guard
82
+ @category Utilities
83
+ */
84
+ type IsOptionalKeyOf<Type extends object, Key$1 extends keyof Type> = IsAny<Type | Key$1> extends true ? never : Key$1 extends keyof Type ? Type extends Record<Key$1, Type[Key$1]> ? false : true : false;
85
+ //#endregion
86
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/optional-keys-of.d.ts
87
+ /**
88
+ Extract all optional keys from the given type.
89
+
90
+ This is useful when you want to create a new type that contains different type values for the optional keys only.
91
+
92
+ @example
93
+ ```
94
+ import type {OptionalKeysOf, Except} from 'type-fest';
95
+
96
+ type User = {
97
+ name: string;
98
+ surname: string;
99
+
100
+ luckyNumber?: number;
101
+ };
102
+
103
+ const REMOVE_FIELD = Symbol('remove field symbol');
104
+ type UpdateOperation<Entity extends object> = Except<Partial<Entity>, OptionalKeysOf<Entity>> & {
105
+ [Key in OptionalKeysOf<Entity>]?: Entity[Key] | typeof REMOVE_FIELD;
106
+ };
107
+
108
+ const update1: UpdateOperation<User> = {
109
+ name: 'Alice',
110
+ };
111
+
112
+ const update2: UpdateOperation<User> = {
113
+ name: 'Bob',
114
+ luckyNumber: REMOVE_FIELD,
115
+ };
116
+ ```
117
+
118
+ @category Utilities
119
+ */
120
+ type OptionalKeysOf<Type extends object> = Type extends unknown // For distributing `Type`
121
+ ? (keyof { [Key in keyof Type as IsOptionalKeyOf<Type, Key> extends false ? never : Key]: never }) & keyof Type // Intersect with `keyof Type` to ensure result of `OptionalKeysOf<Type>` is always assignable to `keyof Type`
122
+ : never;
123
+ //#endregion
124
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/required-keys-of.d.ts
125
+ /**
126
+ Extract all required keys from the given type.
127
+
128
+ This is useful when you want to create a new type that contains different type values for the required keys only or use the list of keys for validation purposes, etc...
129
+
130
+ @example
131
+ ```
132
+ import type {RequiredKeysOf} from 'type-fest';
133
+
134
+ declare function createValidation<
135
+ Entity extends object,
136
+ Key extends RequiredKeysOf<Entity> = RequiredKeysOf<Entity>,
137
+ >(field: Key, validator: (value: Entity[Key]) => boolean): (entity: Entity) => boolean;
138
+
139
+ type User = {
140
+ name: string;
141
+ surname: string;
142
+ luckyNumber?: number;
143
+ };
144
+
145
+ const validator1 = createValidation<User>('name', value => value.length < 25);
146
+ const validator2 = createValidation<User>('surname', value => value.length < 25);
147
+
148
+ // @ts-expect-error
149
+ const validator3 = createValidation<User>('luckyNumber', value => value > 0);
150
+ // Error: Argument of type '"luckyNumber"' is not assignable to parameter of type '"name" | "surname"'.
151
+ ```
152
+
153
+ @category Utilities
154
+ */
155
+ type RequiredKeysOf<Type extends object> = Type extends unknown // For distributing `Type`
156
+ ? Exclude<keyof Type, OptionalKeysOf<Type>> : never;
157
+ //#endregion
158
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/is-never.d.ts
159
+ /**
160
+ Returns a boolean for whether the given type is `never`.
161
+
162
+ @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
163
+ @link https://stackoverflow.com/a/53984913/10292952
164
+ @link https://www.zhenghao.io/posts/ts-never
165
+
166
+ Useful in type utilities, such as checking if something does not occur.
167
+
168
+ @example
169
+ ```
170
+ import type {IsNever, And} from 'type-fest';
171
+
172
+ type A = IsNever<never>;
173
+ //=> true
174
+
175
+ type B = IsNever<any>;
176
+ //=> false
177
+
178
+ type C = IsNever<unknown>;
179
+ //=> false
180
+
181
+ type D = IsNever<never[]>;
182
+ //=> false
183
+
184
+ type E = IsNever<object>;
185
+ //=> false
186
+
187
+ type F = IsNever<string>;
188
+ //=> false
189
+ ```
190
+
191
+ @example
192
+ ```
193
+ import type {IsNever} from 'type-fest';
194
+
195
+ type IsTrue<T> = T extends true ? true : false;
196
+
197
+ // When a distributive conditional is instantiated with `never`, the entire conditional results in `never`.
198
+ type A = IsTrue<never>;
199
+ //=> never
200
+
201
+ // If you don't want that behaviour, you can explicitly add an `IsNever` check before the distributive conditional.
202
+ type IsTrueFixed<T> =
203
+ IsNever<T> extends true ? false : T extends true ? true : false;
204
+
205
+ type B = IsTrueFixed<never>;
206
+ //=> false
207
+ ```
208
+
209
+ @category Type Guard
210
+ @category Utilities
211
+ */
212
+ type IsNever<T> = [T] extends [never] ? true : false;
213
+ //#endregion
214
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/if.d.ts
215
+ /**
216
+ An if-else-like type that resolves depending on whether the given `boolean` type is `true` or `false`.
217
+
218
+ Use-cases:
219
+ - You can use this in combination with `Is*` types to create an if-else-like experience. For example, `If<IsAny<any>, 'is any', 'not any'>`.
220
+
221
+ Note:
222
+ - Returns a union of if branch and else branch if the given type is `boolean` or `any`. For example, `If<boolean, 'Y', 'N'>` will return `'Y' | 'N'`.
223
+ - Returns the else branch if the given type is `never`. For example, `If<never, 'Y', 'N'>` will return `'N'`.
224
+
225
+ @example
226
+ ```
227
+ import type {If} from 'type-fest';
228
+
229
+ type A = If<true, 'yes', 'no'>;
230
+ //=> 'yes'
231
+
232
+ type B = If<false, 'yes', 'no'>;
233
+ //=> 'no'
234
+
235
+ type C = If<boolean, 'yes', 'no'>;
236
+ //=> 'yes' | 'no'
237
+
238
+ type D = If<any, 'yes', 'no'>;
239
+ //=> 'yes' | 'no'
240
+
241
+ type E = If<never, 'yes', 'no'>;
242
+ //=> 'no'
243
+ ```
244
+
245
+ @example
246
+ ```
247
+ import type {If, IsAny, IsNever} from 'type-fest';
248
+
249
+ type A = If<IsAny<unknown>, 'is any', 'not any'>;
250
+ //=> 'not any'
251
+
252
+ type B = If<IsNever<never>, 'is never', 'not never'>;
253
+ //=> 'is never'
254
+ ```
255
+
256
+ @example
257
+ ```
258
+ import type {If, IsEqual} from 'type-fest';
259
+
260
+ type IfEqual<T, U, IfBranch, ElseBranch> = If<IsEqual<T, U>, IfBranch, ElseBranch>;
261
+
262
+ type A = IfEqual<string, string, 'equal', 'not equal'>;
263
+ //=> 'equal'
264
+
265
+ type B = IfEqual<string, number, 'equal', 'not equal'>;
266
+ //=> 'not equal'
267
+ ```
268
+
269
+ Note: Sometimes using the `If` type can make an implementation non–tail-recursive, which can impact performance. In such cases, it’s better to use a conditional directly. Refer to the following example:
270
+
271
+ @example
272
+ ```
273
+ import type {If, IsEqual, StringRepeat} from 'type-fest';
274
+
275
+ type HundredZeroes = StringRepeat<'0', 100>;
276
+
277
+ // The following implementation is not tail recursive
278
+ type Includes<S extends string, Char extends string> =
279
+ S extends `${infer First}${infer Rest}`
280
+ ? If<IsEqual<First, Char>,
281
+ 'found',
282
+ Includes<Rest, Char>>
283
+ : 'not found';
284
+
285
+ // Hence, instantiations with long strings will fail
286
+ // @ts-expect-error
287
+ type Fails = Includes<HundredZeroes, '1'>;
288
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
289
+ // Error: Type instantiation is excessively deep and possibly infinite.
290
+
291
+ // However, if we use a simple conditional instead of `If`, the implementation becomes tail-recursive
292
+ type IncludesWithoutIf<S extends string, Char extends string> =
293
+ S extends `${infer First}${infer Rest}`
294
+ ? IsEqual<First, Char> extends true
295
+ ? 'found'
296
+ : IncludesWithoutIf<Rest, Char>
297
+ : 'not found';
298
+
299
+ // Now, instantiations with long strings will work
300
+ type Works = IncludesWithoutIf<HundredZeroes, '1'>;
301
+ //=> 'not found'
302
+ ```
303
+
304
+ @category Type Guard
305
+ @category Utilities
306
+ */
307
+ type If<Type extends boolean, IfBranch, ElseBranch> = IsNever<Type> extends true ? ElseBranch : Type extends true ? IfBranch : ElseBranch;
308
+ //#endregion
309
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/internal/type.d.ts
310
+ /**
311
+ Matches any primitive, `void`, `Date`, or `RegExp` value.
312
+ */
313
+ type BuiltIns = Primitive | void | Date | RegExp;
314
+ /**
315
+ Test if the given function has multiple call signatures.
316
+
317
+ Needed to handle the case of a single call signature with properties.
318
+
319
+ Multiple call signatures cannot currently be supported due to a TypeScript limitation.
320
+ @see https://github.com/microsoft/TypeScript/issues/29732
321
+ */
322
+ type HasMultipleCallSignatures<T extends (...arguments_: any[]) => unknown> = T extends {
323
+ (...arguments_: infer A): unknown;
324
+ (...arguments_: infer B): unknown;
325
+ } ? B extends A ? A extends B ? false : true : true : false;
326
+ //#endregion
327
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/simplify.d.ts
328
+ /**
329
+ Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
330
+
331
+ @example
332
+ ```
333
+ import type {Simplify} from 'type-fest';
334
+
335
+ type PositionProps = {
336
+ top: number;
337
+ left: number;
338
+ };
339
+
340
+ type SizeProps = {
341
+ width: number;
342
+ height: number;
343
+ };
344
+
345
+ // In your editor, hovering over `Props` will show a flattened object with all the properties.
346
+ type Props = Simplify<PositionProps & SizeProps>;
347
+ ```
348
+
349
+ Sometimes it is desired to pass a value as a function argument that has a different type. At first inspection it may seem assignable, and then you discover it is not because the `value`'s type definition was defined as an interface. In the following example, `fn` requires an argument of type `Record<string, unknown>`. If the value is defined as a literal, then it is assignable. And if the `value` is defined as type using the `Simplify` utility the value is assignable. But if the `value` is defined as an interface, it is not assignable because the interface is not sealed and elsewhere a non-string property could be added to the interface.
350
+
351
+ If the type definition must be an interface (perhaps it was defined in a third-party npm package), then the `value` can be defined as `const value: Simplify<SomeInterface> = ...`. Then `value` will be assignable to the `fn` argument. Or the `value` can be cast as `Simplify<SomeInterface>` if you can't re-declare the `value`.
352
+
353
+ @example
354
+ ```
355
+ import type {Simplify} from 'type-fest';
356
+
357
+ interface SomeInterface {
358
+ foo: number;
359
+ bar?: string;
360
+ baz: number | undefined;
361
+ }
362
+
363
+ type SomeType = {
364
+ foo: number;
365
+ bar?: string;
366
+ baz: number | undefined;
367
+ };
368
+
369
+ const literal = {foo: 123, bar: 'hello', baz: 456};
370
+ const someType: SomeType = literal;
371
+ const someInterface: SomeInterface = literal;
372
+
373
+ declare function fn(object: Record<string, unknown>): void;
374
+
375
+ fn(literal); // Good: literal object type is sealed
376
+ fn(someType); // Good: type is sealed
377
+ // @ts-expect-error
378
+ fn(someInterface); // Error: Index signature for type 'string' is missing in type 'someInterface'. Because `interface` can be re-opened
379
+ fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface` into a `type`
380
+ ```
381
+
382
+ @link https://github.com/microsoft/TypeScript/issues/15300
383
+ @see {@link SimplifyDeep}
384
+ @category Object
385
+ */
386
+ type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {};
387
+ //#endregion
388
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/omit-index-signature.d.ts
389
+ /**
390
+ Omit any index signatures from the given object type, leaving only explicitly defined properties.
391
+
392
+ This is the counterpart of `PickIndexSignature`.
393
+
394
+ Use-cases:
395
+ - Remove overly permissive signatures from third-party types.
396
+
397
+ This type was taken from this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747).
398
+
399
+ It relies on the fact that an empty object (`{}`) is assignable to an object with just an index signature, like `Record<string, unknown>`, but not to an object with explicitly defined keys, like `Record<'foo' | 'bar', unknown>`.
400
+
401
+ (The actual value type, `unknown`, is irrelevant and could be any type. Only the key type matters.)
402
+
403
+ ```
404
+ const indexed: Record<string, unknown> = {}; // Allowed
405
+
406
+ // @ts-expect-error
407
+ const keyed: Record<'foo', unknown> = {}; // Error
408
+ // TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar
409
+ ```
410
+
411
+ Instead of causing a type error like the above, you can also use a [conditional type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html) to test whether a type is assignable to another:
412
+
413
+ ```
414
+ type Indexed = {} extends Record<string, unknown>
415
+ ? '✅ `{}` is assignable to `Record<string, unknown>`'
416
+ : '❌ `{}` is NOT assignable to `Record<string, unknown>`';
417
+
418
+ type IndexedResult = Indexed;
419
+ //=> '✅ `{}` is assignable to `Record<string, unknown>`'
420
+
421
+ type Keyed = {} extends Record<'foo' | 'bar', unknown>
422
+ ? '✅ `{}` is assignable to `Record<\'foo\' | \'bar\', unknown>`'
423
+ : '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`';
424
+
425
+ type KeyedResult = Keyed;
426
+ //=> '❌ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`'
427
+ ```
428
+
429
+ Using a [mapped type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#further-exploration), you can then check for each `KeyType` of `ObjectType`...
430
+
431
+ ```
432
+ type OmitIndexSignature<ObjectType> = {
433
+ [KeyType in keyof ObjectType // Map each key of `ObjectType`...
434
+ ]: ObjectType[KeyType]; // ...to its original value, i.e. `OmitIndexSignature<Foo> == Foo`.
435
+ };
436
+ ```
437
+
438
+ ...whether an empty object (`{}`) would be assignable to an object with that `KeyType` (`Record<KeyType, unknown>`)...
439
+
440
+ ```
441
+ type OmitIndexSignature<ObjectType> = {
442
+ [KeyType in keyof ObjectType
443
+ // Is `{}` assignable to `Record<KeyType, unknown>`?
444
+ as {} extends Record<KeyType, unknown>
445
+ ? never // ✅ `{}` is assignable to `Record<KeyType, unknown>`
446
+ : KeyType // ❌ `{}` is NOT assignable to `Record<KeyType, unknown>`
447
+ ]: ObjectType[KeyType];
448
+ };
449
+ ```
450
+
451
+ If `{}` is assignable, it means that `KeyType` is an index signature and we want to remove it. If it is not assignable, `KeyType` is a "real" key and we want to keep it.
452
+
453
+ @example
454
+ ```
455
+ import type {OmitIndexSignature} from 'type-fest';
456
+
457
+ type Example = {
458
+ // These index signatures will be removed.
459
+ [x: string]: any;
460
+ [x: number]: any;
461
+ [x: symbol]: any;
462
+ [x: `head-${string}`]: string;
463
+ [x: `${string}-tail`]: string;
464
+ [x: `head-${string}-tail`]: string;
465
+ [x: `${bigint}`]: string;
466
+ [x: `embedded-${number}`]: string;
467
+
468
+ // These explicitly defined keys will remain.
469
+ foo: 'bar';
470
+ qux?: 'baz';
471
+ };
472
+
473
+ type ExampleWithoutIndexSignatures = OmitIndexSignature<Example>;
474
+ //=> {foo: 'bar'; qux?: 'baz'}
475
+ ```
476
+
477
+ @see {@link PickIndexSignature}
478
+ @category Object
479
+ */
480
+ type OmitIndexSignature<ObjectType> = { [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> ? never : KeyType]: ObjectType[KeyType] };
481
+ //#endregion
482
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/pick-index-signature.d.ts
483
+ /**
484
+ Pick only index signatures from the given object type, leaving out all explicitly defined properties.
485
+
486
+ This is the counterpart of `OmitIndexSignature`.
487
+
488
+ @example
489
+ ```
490
+ import type {PickIndexSignature} from 'type-fest';
491
+
492
+ declare const symbolKey: unique symbol;
493
+
494
+ type Example = {
495
+ // These index signatures will remain.
496
+ [x: string]: unknown;
497
+ [x: number]: unknown;
498
+ [x: symbol]: unknown;
499
+ [x: `head-${string}`]: string;
500
+ [x: `${string}-tail`]: string;
501
+ [x: `head-${string}-tail`]: string;
502
+ [x: `${bigint}`]: string;
503
+ [x: `embedded-${number}`]: string;
504
+
505
+ // These explicitly defined keys will be removed.
506
+ ['kebab-case-key']: string;
507
+ [symbolKey]: string;
508
+ foo: 'bar';
509
+ qux?: 'baz';
510
+ };
511
+
512
+ type ExampleIndexSignature = PickIndexSignature<Example>;
513
+ // {
514
+ // [x: string]: unknown;
515
+ // [x: number]: unknown;
516
+ // [x: symbol]: unknown;
517
+ // [x: `head-${string}`]: string;
518
+ // [x: `${string}-tail`]: string;
519
+ // [x: `head-${string}-tail`]: string;
520
+ // [x: `${bigint}`]: string;
521
+ // [x: `embedded-${number}`]: string;
522
+ // }
523
+ ```
524
+
525
+ @see {@link OmitIndexSignature}
526
+ @category Object
527
+ */
528
+ type PickIndexSignature<ObjectType> = { [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> ? KeyType : never]: ObjectType[KeyType] };
529
+ //#endregion
530
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/merge.d.ts
531
+ // Merges two objects without worrying about index signatures.
532
+ type SimpleMerge<Destination, Source> = Simplify<{ [Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key] } & Source>;
533
+
534
+ /**
535
+ Merge two types into a new type. Keys of the second type overrides keys of the first type.
536
+
537
+ @example
538
+ ```
539
+ import type {Merge} from 'type-fest';
540
+
541
+ type Foo = {
542
+ [x: string]: unknown;
543
+ [x: number]: unknown;
544
+ foo: string;
545
+ bar: symbol;
546
+ };
547
+
548
+ type Bar = {
549
+ [x: number]: number;
550
+ [x: symbol]: unknown;
551
+ bar: Date;
552
+ baz: boolean;
553
+ };
554
+
555
+ export type FooBar = Merge<Foo, Bar>;
556
+ //=> {
557
+ // [x: string]: unknown;
558
+ // [x: number]: number;
559
+ // [x: symbol]: unknown;
560
+ // foo: string;
561
+ // bar: Date;
562
+ // baz: boolean;
563
+ // }
564
+ ```
565
+
566
+ Note: If you want a merge type that more accurately reflects the runtime behavior of object spread or `Object.assign`, refer to the {@link ObjectMerge} type.
567
+
568
+ @see {@link ObjectMerge}
569
+ @category Object
570
+ */
571
+ type Merge<Destination, Source> = Destination extends unknown // For distributing `Destination`
572
+ ? Source extends unknown // For distributing `Source`
573
+ ? Simplify<SimpleMerge<PickIndexSignature<Destination>, PickIndexSignature<Source>> & SimpleMerge<OmitIndexSignature<Destination>, OmitIndexSignature<Source>>> : never // Should never happen
574
+ : never;
575
+ //#endregion
576
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/internal/object.d.ts
577
+
578
+ /**
579
+ Merges user specified options with default options.
580
+
581
+ @example
582
+ ```
583
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
584
+ type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
585
+ type SpecifiedOptions = {leavesOnly: true};
586
+
587
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
588
+ //=> {maxRecursionDepth: 10; leavesOnly: true}
589
+ ```
590
+
591
+ @example
592
+ ```
593
+ // Complains if default values are not provided for optional options
594
+
595
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
596
+ type DefaultPathsOptions = {maxRecursionDepth: 10};
597
+ type SpecifiedOptions = {};
598
+
599
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
600
+ // ~~~~~~~~~~~~~~~~~~~
601
+ // Property 'leavesOnly' is missing in type 'DefaultPathsOptions' but required in type '{ maxRecursionDepth: number; leavesOnly: boolean; }'.
602
+ ```
603
+
604
+ @example
605
+ ```
606
+ // Complains if an option's default type does not conform to the expected type
607
+
608
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
609
+ type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: 'no'};
610
+ type SpecifiedOptions = {};
611
+
612
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
613
+ // ~~~~~~~~~~~~~~~~~~~
614
+ // Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
615
+ ```
616
+
617
+ @example
618
+ ```
619
+ // Complains if an option's specified type does not conform to the expected type
620
+
621
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
622
+ type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
623
+ type SpecifiedOptions = {leavesOnly: 'yes'};
624
+
625
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
626
+ // ~~~~~~~~~~~~~~~~
627
+ // Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
628
+ ```
629
+ */
630
+ type ApplyDefaultOptions<Options extends object, Defaults extends Simplify<Omit<Required<Options>, RequiredKeysOf<Options>> & Partial<Record<RequiredKeysOf<Options>, never>>>, SpecifiedOptions extends Options> = If<IsAny<SpecifiedOptions>, Defaults, If<IsNever<SpecifiedOptions>, Defaults, Simplify<Merge<Defaults, { [Key in keyof SpecifiedOptions as Key extends OptionalKeysOf<Options> ? undefined extends SpecifiedOptions[Key] ? never : Key : Key]: SpecifiedOptions[Key] }> & Required<Options>>>>;
631
+ //#endregion
632
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/partial-deep.d.ts
633
+ /**
634
+ @see {@link PartialDeep}
635
+ */
636
+ type PartialDeepOptions = {
637
+ /**
638
+ Whether to affect the individual elements of arrays and tuples.
639
+ @default false
640
+ */
641
+ readonly recurseIntoArrays?: boolean;
642
+
643
+ /**
644
+ Allows `undefined` values in non-tuple arrays.
645
+ - When set to `true`, elements of non-tuple arrays can be `undefined`.
646
+ - When set to `false`, only explicitly defined elements are allowed in non-tuple arrays, ensuring stricter type checking.
647
+ @default false
648
+ @example
649
+ You can allow `undefined` values in non-tuple arrays by passing `{recurseIntoArrays: true; allowUndefinedInNonTupleArrays: true}` as the second type argument:
650
+ ```
651
+ import type {PartialDeep} from 'type-fest';
652
+ type Settings = {
653
+ languages: string[];
654
+ };
655
+ declare const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true; allowUndefinedInNonTupleArrays: true}>;
656
+ partialSettings.languages = [undefined]; // OK
657
+ ```
658
+ */
659
+ readonly allowUndefinedInNonTupleArrays?: boolean;
660
+ };
661
+ type DefaultPartialDeepOptions = {
662
+ recurseIntoArrays: false;
663
+ allowUndefinedInNonTupleArrays: false;
664
+ };
665
+
666
+ /**
667
+ Create a type from another type with all keys and nested keys set to optional.
668
+
669
+ Use-cases:
670
+ - Merging a default settings/config object with another object, the second object would be a deep partial of the default object.
671
+ - Mocking and testing complex entities, where populating an entire object with its keys would be redundant in terms of the mock or test.
672
+
673
+ @example
674
+ ```
675
+ import type {PartialDeep} from 'type-fest';
676
+
677
+ let settings = {
678
+ textEditor: {
679
+ fontSize: 14,
680
+ fontColor: '#000000',
681
+ fontWeight: 400,
682
+ },
683
+ autocomplete: false,
684
+ autosave: true,
685
+ };
686
+
687
+ const applySavedSettings = (savedSettings: PartialDeep<typeof settings>) => (
688
+ {...settings, ...savedSettings, textEditor: {...settings.textEditor, ...savedSettings.textEditor}}
689
+ );
690
+
691
+ settings = applySavedSettings({textEditor: {fontWeight: 500}});
692
+ ```
693
+
694
+ By default, this does not affect elements in array and tuple types. You can change this by passing `{recurseIntoArrays: true}` as the second type argument:
695
+
696
+ ```
697
+ import type {PartialDeep} from 'type-fest';
698
+
699
+ type Shape = {
700
+ dimensions: [number, number];
701
+ };
702
+
703
+ const partialShape: PartialDeep<Shape, {recurseIntoArrays: true}> = {
704
+ dimensions: [], // OK
705
+ };
706
+
707
+ partialShape.dimensions = [15]; // OK
708
+ ```
709
+
710
+ @see {@link PartialDeepOptions}
711
+
712
+ @category Object
713
+ @category Array
714
+ @category Set
715
+ @category Map
716
+ */
717
+ type PartialDeep<T, Options extends PartialDeepOptions = {}> = _PartialDeep<T, ApplyDefaultOptions<PartialDeepOptions, DefaultPartialDeepOptions, Options>>;
718
+ type _PartialDeep<T, Options extends Required<PartialDeepOptions>> = T extends BuiltIns | ((new (...arguments_: any[]) => unknown)) ? T : T extends Map<infer KeyType, infer ValueType> ? PartialMapDeep<KeyType, ValueType, Options> : T extends Set<infer ItemType> ? PartialSetDeep<ItemType, Options> : T extends ReadonlyMap<infer KeyType, infer ValueType> ? PartialReadonlyMapDeep<KeyType, ValueType, Options> : T extends ReadonlySet<infer ItemType> ? PartialReadonlySetDeep<ItemType, Options> : T extends ((...arguments_: any[]) => unknown) ? IsNever<keyof T> extends true ? T // For functions with no properties
719
+ : HasMultipleCallSignatures<T> extends true ? T : ((...arguments_: Parameters<T>) => ReturnType<T>) & PartialObjectDeep<T, Options> : T extends object ? T extends ReadonlyArray<infer ItemType> // Test for arrays/tuples, per https://github.com/microsoft/TypeScript/issues/35156
720
+ ? Options['recurseIntoArrays'] extends true ? ItemType[] extends T // Test for arrays (non-tuples) specifically
721
+ ? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
722
+ ? ReadonlyArray<_PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>> : Array<_PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>> : PartialObjectDeep<T, Options> // Tuples behave properly
723
+ : T // If they don't opt into array testing, just use the original type
724
+ : PartialObjectDeep<T, Options> : unknown;
725
+
726
+ /**
727
+ Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
728
+ */
729
+ type PartialMapDeep<KeyType$1, ValueType$1, Options extends Required<PartialDeepOptions>> = {} & Map<_PartialDeep<KeyType$1, Options>, _PartialDeep<ValueType$1, Options>>;
730
+
731
+ /**
732
+ Same as `PartialDeep`, but accepts only `Set`s as inputs. Internal helper for `PartialDeep`.
733
+ */
734
+ type PartialSetDeep<T, Options extends Required<PartialDeepOptions>> = {} & Set<_PartialDeep<T, Options>>;
735
+
736
+ /**
737
+ Same as `PartialDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `PartialDeep`.
738
+ */
739
+ type PartialReadonlyMapDeep<KeyType$1, ValueType$1, Options extends Required<PartialDeepOptions>> = {} & ReadonlyMap<_PartialDeep<KeyType$1, Options>, _PartialDeep<ValueType$1, Options>>;
740
+
741
+ /**
742
+ Same as `PartialDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `PartialDeep`.
743
+ */
744
+ type PartialReadonlySetDeep<T, Options extends Required<PartialDeepOptions>> = {} & ReadonlySet<_PartialDeep<T, Options>>;
745
+
746
+ /**
747
+ Same as `PartialDeep`, but accepts only `object`s as inputs. Internal helper for `PartialDeep`.
748
+ */
749
+ type PartialObjectDeep<ObjectType extends object, Options extends Required<PartialDeepOptions>> = { [KeyType in keyof ObjectType]?: _PartialDeep<ObjectType[KeyType], Options> };
750
+ //#endregion
751
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/literal-union.d.ts
752
+ /**
753
+ Allows creating a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union.
754
+
755
+ Currently, when a union type of a primitive type is combined with literal types, TypeScript loses all information about the combined literals. Thus, when such type is used in an IDE with autocompletion, no suggestions are made for the declared literals.
756
+
757
+ This type is a workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729). It will be removed as soon as it's not needed anymore.
758
+
759
+ @example
760
+ ```
761
+ import type {LiteralUnion} from 'type-fest';
762
+
763
+ // Before
764
+
765
+ type Pet = 'dog' | 'cat' | string;
766
+
767
+ const petWithoutAutocomplete: Pet = '';
768
+ // Start typing in your TypeScript-enabled IDE.
769
+ // You **will not** get auto-completion for `dog` and `cat` literals.
770
+
771
+ // After
772
+
773
+ type Pet2 = LiteralUnion<'dog' | 'cat', string>;
774
+
775
+ const petWithAutoComplete: Pet2 = '';
776
+ // You **will** get auto-completion for `dog` and `cat` literals.
777
+ ```
778
+
779
+ @category Type
780
+ */
781
+ type LiteralUnion<LiteralType, BaseType extends Primitive> = LiteralType | (BaseType & Record<never, never>);
782
+ //#endregion
783
+ //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/readonly-deep.d.ts
784
+ /**
785
+ Convert `object`s, `Map`s, `Set`s, and `Array`s and all of their keys/elements into immutable structures recursively.
786
+
787
+ This is useful when a deeply nested structure needs to be exposed as completely immutable, for example, an imported JSON module or when receiving an API response that is passed around.
788
+
789
+ Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/13923) if you want to have this type as a built-in in TypeScript.
790
+
791
+ @example
792
+ ```
793
+ import type {ReadonlyDeep} from 'type-fest';
794
+
795
+ declare const foo: {
796
+ a: string;
797
+ b: {c: number};
798
+ d: Array<{e: number}>;
799
+ };
800
+
801
+ foo.a = 'bar'; // Allowed
802
+
803
+ foo.b = {c: 3}; // Allowed
804
+
805
+ foo.b.c = 4; // Allowed
806
+
807
+ foo.d = [{e: 5}]; // Allowed
808
+
809
+ foo.d.push({e: 6}); // Allowed
810
+
811
+ const last = foo.d.at(-1);
812
+ if (last) {
813
+ last.e = 7; // Allowed
814
+ }
815
+
816
+ declare const readonlyFoo: ReadonlyDeep<typeof foo>;
817
+
818
+ // @ts-expect-error
819
+ readonlyFoo.a = 'bar';
820
+ // Error: Cannot assign to 'a' because it is a read-only property.
821
+
822
+ // @ts-expect-error
823
+ readonlyFoo.b = {c: 3};
824
+ // Error: Cannot assign to 'b' because it is a read-only property.
825
+
826
+ // @ts-expect-error
827
+ readonlyFoo.b.c = 4;
828
+ // Error: Cannot assign to 'c' because it is a read-only property.
829
+
830
+ // @ts-expect-error
831
+ readonlyFoo.d = [{e: 5}];
832
+ // Error: Cannot assign to 'd' because it is a read-only property.
833
+
834
+ // @ts-expect-error
835
+ readonlyFoo.d.push({e: 6});
836
+ // Error: Property 'push' does not exist on type 'ReadonlyArray<{readonly e: number}>'.
837
+
838
+ const readonlyLast = readonlyFoo.d.at(-1);
839
+ if (readonlyLast) {
840
+ // @ts-expect-error
841
+ readonlyLast.e = 8;
842
+ // Error: Cannot assign to 'e' because it is a read-only property.
843
+ }
844
+ ```
845
+
846
+ Note that types containing overloaded functions are not made deeply readonly due to a [TypeScript limitation](https://github.com/microsoft/TypeScript/issues/29732).
847
+
848
+ @category Object
849
+ @category Array
850
+ @category Set
851
+ @category Map
852
+ */
853
+ type ReadonlyDeep<T> = T extends BuiltIns ? T : T extends (new (...arguments_: any[]) => unknown) ? T // Skip class constructors
854
+ : T extends ((...arguments_: any[]) => unknown) ? {} extends _ReadonlyObjectDeep<T> ? T : HasMultipleCallSignatures<T> extends true ? T : ((...arguments_: Parameters<T>) => ReturnType<T>) & _ReadonlyObjectDeep<T> : T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>> ? ReadonlyMapDeep<KeyType, ValueType> : T extends Readonly<ReadonlySet<infer ItemType>> ? ReadonlySetDeep<ItemType> :
855
+ // Identify tuples to avoid converting them to arrays inadvertently; special case `readonly [...never[]]`, as it emerges undesirably from recursive invocations of ReadonlyDeep below.
856
+ T extends readonly [] | readonly [...never[]] ? readonly [] : T extends readonly [infer U, ...infer V] ? readonly [ReadonlyDeep<U>, ...ReadonlyDeep<V>] : T extends readonly [...infer U, infer V] ? readonly [...ReadonlyDeep<U>, ReadonlyDeep<V>] : T extends ReadonlyArray<infer ItemType> ? ReadonlyArray<ReadonlyDeep<ItemType>> : T extends object ? _ReadonlyObjectDeep<T> : unknown;
857
+ /**
858
+ Same as `ReadonlyDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `ReadonlyDeep`.
859
+ */
860
+ type ReadonlyMapDeep<KeyType$1, ValueType$1> = {} & Readonly<ReadonlyMap<ReadonlyDeep<KeyType$1>, ReadonlyDeep<ValueType$1>>>;
861
+
862
+ /**
863
+ Same as `ReadonlyDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `ReadonlyDeep`.
864
+ */
865
+ type ReadonlySetDeep<ItemType$1> = {} & Readonly<ReadonlySet<ReadonlyDeep<ItemType$1>>>;
866
+
867
+ /**
868
+ Same as `ReadonlyDeep`, but accepts only `object`s as inputs. Internal helper for `ReadonlyDeep`.
869
+ */
870
+ type _ReadonlyObjectDeep<ObjectType extends object> = { readonly [KeyType in keyof ObjectType]: ReadonlyDeep<ObjectType[KeyType]> };
871
+ //#endregion
872
+ //#region src/sensors/types.d.ts
873
+ /**
874
+ * Built-in sensor IDs
875
+ */
876
+ declare const BUILT_IN_SENSOR_IDS: readonly ["geolocation", "deviceorientation", "devicemotion", "manual", "fusion"];
877
+ /**
878
+ * Built-in sensor IDs.
879
+ */
880
+ type BuiltInSensorId = (typeof BUILT_IN_SENSOR_IDS)[number];
881
+ /**
882
+ * Utility type that rejects built-in IDs when they are known as literals.
883
+ *
884
+ * TypeScript cannot represent "any string except these specific literals" as a standalone type
885
+ * (i.e., `Exclude<string, 'a' | 'b'>` evaluates to `string`). This helper is meant for APIs like
886
+ * `SensorRegistry.register()` where the sensor's `id` is typically a string literal type.
887
+ */
888
+ type CustomSensorId<Id extends string> = Id extends BuiltInSensorId ? never : Id;
889
+ /**
890
+ * Sensor ID - either a built-in ID or a custom string ID.
891
+ */
892
+ type SensorId = LiteralUnion<BuiltInSensorId, string>;
893
+ /**
894
+ * Event payloads for internal sensor communication.
895
+ *
896
+ * These are INTERNAL events used between sensors and the FusionEngine.
897
+ * They are NOT the same as the external `position-update` event that
898
+ * app developers subscribe to on the BlueDot class.
899
+ *
900
+ * ## Event Flow
901
+ *
902
+ * ```
903
+ * Sensors ──► SensorRegistry ──► FusionEngine ──► BlueDot ──► App
904
+ * │ │ │ │
905
+ * │ absolute-update │ │ │ position-update
906
+ * │ relative-update │ │ │ (external API)
907
+ * │ (internal) │ │ │
908
+ * ```
909
+ *
910
+ * ## Event Types
911
+ *
912
+ * - **`absolute-update`**: Sensors providing global coordinates (GPS lat/lon, compass heading)
913
+ * - **`relative-update`**: Sensors providing displacement from a reference (PDR steps: dx/dy meters)
914
+ * - **`anchor-set`**: Sensors setting a high-confidence position anchor (VPS, AI Localizer)
915
+ * - **`anchor-clear`**: Sensors clearing their anchor
916
+ * - **`error`**: Sensor errors
917
+ *
918
+ * The FusionEngine processes these differently:
919
+ * - Absolute updates → `ekf.updatePosition(lat, lon, noise, timestamp)`
920
+ * - Relative updates → `ekf.updateOdometry(dx, dy, noise, timestamp)`
921
+ */
922
+ type SensorEventPayloads = {
923
+ /**
924
+ * Emitted when a sensor provides an absolute position or heading update.
925
+ *
926
+ * "Absolute" means the data represents a global/world coordinate or direction,
927
+ * not a displacement from a previous position.
928
+ *
929
+ * Examples of absolute updates:
930
+ * - GPS position (latitude, longitude)
931
+ * - Compass heading (0-360 degrees from north)
932
+ * - Gyroscope angular velocity (for heading integration)
933
+ * - VPS/AI Localizer position (high-confidence anchor)
934
+ *
935
+ * The FusionEngine routes these to `ekf.updatePosition()` for lat/lon data,
936
+ * or to the HeadingFusionFilter for heading/angular velocity data.
937
+ *
938
+ * @see {@link relative-update} for displacement-based updates
939
+ */
940
+ 'absolute-update': {
941
+ /** Which sensor produced this update */
942
+ sensorId: SensorId;
943
+ /** The position/heading data (fields are optional - sensors provide what they have) */
944
+ update: PartialPositionUpdate;
945
+ };
946
+ /**
947
+ * Emitted when a sensor provides a relative displacement update.
948
+ *
949
+ * "Relative" means the data represents movement FROM a reference position,
950
+ * not an absolute world coordinate. Used for Pedestrian Dead Reckoning (PDR).
951
+ *
952
+ * Examples of relative updates:
953
+ * - Step detection: "moved 0.7 meters in direction of current heading"
954
+ * - Inertial navigation: "displaced (dx, dy) meters since last update"
955
+ *
956
+ * The FusionEngine routes these to `ekf.updateOdometry()`.
957
+ *
958
+ * **Important**: Relative updates are only useful when an anchor is active.
959
+ * Without an anchor, there's no reference point to apply the displacement to.
960
+ * The FusionEngine will ignore relative updates when `anchorState === 'none'`.
961
+ *
962
+ * @see {@link absolute-update} for global coordinate updates
963
+ */
964
+ 'relative-update': {
965
+ /** Which sensor produced this update */
966
+ sensorId: SensorId;
967
+ /** The displacement data */
968
+ update: RelativePositionUpdate;
969
+ };
970
+ /**
971
+ * Emitted when a sensor encounters an error.
972
+ */
973
+ error: {
974
+ /** Which sensor encountered the error */
975
+ sensorId: SensorId;
976
+ /** The error (may be a GeolocationPositionError for geolocation sensor) */
977
+ error: Error | GeolocationPositionError;
978
+ };
979
+ /**
980
+ * Emitted when a sensor sets a position anchor.
981
+ *
982
+ * Anchors are high-confidence absolute positions from calibration sources
983
+ * (VPS, AI Localizer, QR code scan, manual correction). When an anchor is
984
+ * active, it serves as the reference point for position fusion.
985
+ *
986
+ * The FusionEngine resets the EKF state and uses the anchor as ground truth.
987
+ */
988
+ 'anchor-set': {
989
+ /** Which sensor is setting the anchor */
990
+ sensorId: SensorId;
991
+ /** The anchor position data */
992
+ anchor: PositionAnchor;
993
+ /** Optional config override for this anchor (e.g., extended anchorOnlyPeriod for forcePosition) */
994
+ configOverride?: {
995
+ anchorOnlyPeriodMs: number;
996
+ };
997
+ };
998
+ /**
999
+ * Emitted when a sensor clears its anchor.
1000
+ *
1001
+ * After clearing, the FusionEngine will fall back to other position sources.
1002
+ */
1003
+ 'anchor-clear': {
1004
+ /** Which sensor is clearing the anchor */
1005
+ sensorId: SensorId;
1006
+ };
1007
+ };
1008
+ //#endregion
1009
+ //#region src/fusion/anchor-state.d.ts
1010
+ /**
1011
+ * Anchor state in the fusion engine's hybrid anchor behavior model.
1012
+ *
1013
+ * - `'none'`: No anchor active; GPS measurements accepted, PDR ignored
1014
+ * - `'anchor-only'`: Anchor active and in exclusive period; GPS rejected, PDR accepted
1015
+ * - `'transition'`: Anchor active but past exclusive period; GPS accepted with increasing weight
1016
+ */
1017
+ type AnchorState = 'none' | 'anchor-only' | 'transition';
1018
+ //#endregion
1019
+ //#region src/fusion/types.d.ts
1020
+ type FusionEventPayloads = {
1021
+ 'fused-position': {
1022
+ position: FusedPosition;
1023
+ };
1024
+ 'heading-update': {
1025
+ heading: number;
1026
+ };
1027
+ 'anchor-set': {
1028
+ anchor: PositionAnchor;
1029
+ };
1030
+ 'anchor-expired': {
1031
+ anchor: PositionAnchor;
1032
+ };
1033
+ error: {
1034
+ error: Error | GeolocationPositionError;
1035
+ };
1036
+ };
1037
+ type PositionMetadata = {
1038
+ /** Confidence score 0-1 (0 = no confidence, 1 = 100% certain) */
1039
+ confidence: number;
1040
+ };
1041
+ /**
1042
+ * Represents a position update from a position source with an associated confidence score.
1043
+ * This interface is explicitly defined to include core geolocation fields, avoiding TypeScript interface extension errors.
1044
+ */
1045
+ type PositionUpdate = {
1046
+ /** Latitude in degrees */
1047
+ latitude: number;
1048
+ /** Longitude in degrees */
1049
+ longitude: number;
1050
+ /** Accuracy in meters */
1051
+ accuracy?: number;
1052
+ /** Altitude in meters above the WGS84 ellipsoid (if available) */
1053
+ altitude?: number | null;
1054
+ /** Altitude accuracy in meters (if available) */
1055
+ altitudeAccuracy?: number | null;
1056
+ /** Heading in degrees (if available) */
1057
+ heading?: number | null;
1058
+ /** Angular velocity in degrees per second (gyroscope z-axis rotation rate) */
1059
+ angularVelocity?: number | null;
1060
+ /** Speed in meters per second (if available) */
1061
+ speed?: number | null;
1062
+ /** Floor level from device (used to resolve floor) */
1063
+ floorLevel?: number | null;
1064
+ /** Timestamp in milliseconds */
1065
+ timestamp?: number;
1066
+ } & PositionMetadata;
1067
+ type PartialPositionUpdate = PartialDeep<PositionUpdate> & PositionMetadata;
1068
+ /**
1069
+ * Contribution from a single sensor to the fused position.
1070
+ */
1071
+ interface SensorContribution {
1072
+ /** Sensor identifier */
1073
+ sensorId: SensorId;
1074
+ /** Weight applied to this sensor (normalized 0-1, 0 for heading-only sensors) */
1075
+ weight: number;
1076
+ /** Original position update from the sensor (may be partial) */
1077
+ position: PartialPositionUpdate;
1078
+ }
1079
+ /**
1080
+ * A fused position combining multiple sensor updates.
1081
+ */
1082
+ interface FusedPosition extends PositionUpdate {
1083
+ sensorId: 'fusion';
1084
+ /** Individual contributions from each sensor */
1085
+ contributions: SensorContribution[];
1086
+ /** Whether position is calibrated via an anchor (VPS/AI Localizer) */
1087
+ isCalibrated: boolean;
1088
+ /** Accumulated displacement from anchor in meters (only present when isCalibrated is true) */
1089
+ displacement?: DisplacementVector;
1090
+ }
1091
+ /**
1092
+ * A displacement vector in meters.
1093
+ */
1094
+ interface DisplacementVector {
1095
+ /** Displacement in meters along east-west axis (positive = east) */
1096
+ dx: number;
1097
+ /** Displacement in meters along north-south axis (positive = north) */
1098
+ dy: number;
1099
+ }
1100
+ /**
1101
+ * A relative displacement update from a motion sensor (e.g., PDR).
1102
+ * Displacement is in meters, relative to the last known position.
1103
+ * Used for dead reckoning from a calibrated anchor position.
1104
+ */
1105
+ interface RelativePositionUpdate {
1106
+ /** Displacement in meters along east-west axis (positive = east) */
1107
+ dx: number;
1108
+ /** Displacement in meters along north-south axis (positive = north) */
1109
+ dy: number;
1110
+ /** Heading in degrees (0-360) at time of displacement */
1111
+ heading?: number;
1112
+ /** Timestamp in milliseconds */
1113
+ timestamp: number;
1114
+ /** Confidence score 0-1 */
1115
+ confidence: number;
1116
+ }
1117
+ /**
1118
+ * Configuration for the multi-sensor EKF fusion engine.
1119
+ */
1120
+ interface FusionEngineConfig {
1121
+ /**
1122
+ * Duration in ms where anchor is exclusive (GPS rejected).
1123
+ * @default 5000 (5 seconds)
1124
+ */
1125
+ anchorOnlyPeriodMs: number;
1126
+ /**
1127
+ * Half-life for state uncertainty growth in milliseconds.
1128
+ * The state uncertainty doubles every halfLifeMs when no measurements arrive.
1129
+ * Lower values = faster decay of old position estimates.
1130
+ * @default 10000 (10 seconds)
1131
+ */
1132
+ halfLifeMs: number;
1133
+ /**
1134
+ * Maximum age of position updates to consider in milliseconds.
1135
+ * Updates older than this cause filter reset.
1136
+ * @default 5000 (5 seconds)
1137
+ */
1138
+ maxAgeMs: number;
1139
+ }
1140
+ /**
1141
+ * Position anchor from a calibration source (VPS, AI Localizer).
1142
+ * Anchors represent absolute ground truth positions that other sensors
1143
+ * can reference for relative positioning.
1144
+ */
1145
+ interface PositionAnchor {
1146
+ /** Absolute latitude in degrees */
1147
+ latitude: number;
1148
+ /** Absolute longitude in degrees */
1149
+ longitude: number;
1150
+ /** Heading/bearing from calibration source in degrees */
1151
+ heading?: number;
1152
+ /** Floor level from calibration source */
1153
+ floorLevel?: number;
1154
+ /** Sensor that set this anchor */
1155
+ sensorId: SensorId;
1156
+ /** When anchor was established (timestamp in ms) */
1157
+ timestamp: number;
1158
+ /** How long anchor remains valid in milliseconds */
1159
+ ttl: number;
1160
+ /**
1161
+ * Initial confidence of this anchor (0-1).
1162
+ * Used for transition decay: anchor confidence decreases over time.
1163
+ * @default 1.0
1164
+ */
1165
+ confidence?: number;
1166
+ }
1167
+ //#endregion
1168
+ //#region ../packages/common/browser.d.ts
1169
+ type BrowserPermissionState = PermissionState | 'unavailable';
1170
+ //#endregion
1171
+ //#region ../packages/common/extensions.d.ts
1172
+ interface MapViewExtension<T> {
1173
+ enable(options?: PartialDeep<T>): void;
1174
+ disable(): void;
1175
+ get isEnabled(): boolean;
1176
+ destroy(): void;
1177
+ }
1178
+ //#endregion
1179
+ //#region src/status/types.d.ts
1180
+ type BlueDotStatus = 'hidden' | 'active' | 'inactive' | 'disabled';
1181
+ type BlueDotAction = 'timeout' | 'error' | 'position-update' | 'enable' | 'disable' | 'initialize';
1182
+ //#endregion
1183
+ //#region src/follow/types.d.ts
1184
+ type FollowMode = /** Camera position follows the Blue Dot's position. */
1185
+ 'position-only'
1186
+ /** Camera position follows the Blue Dot's position. Camera bearing matches the Blue Dot's heading. */ | 'position-and-heading'
1187
+ /** Camera position follows the Blue Dot's position. Camera bearing is calculated based on the Navigation path. */ | 'position-and-path-direction'
1188
+ /** Disables follow mode */ | false;
1189
+ //#endregion
1190
+ //#region src/types.d.ts
1191
+ type FollowCameraOptions = {
1192
+ /**
1193
+ * @default 21
1194
+ */
1195
+ zoomLevel?: number;
1196
+ /**
1197
+ * @default 45
1198
+ */
1199
+ pitch?: number;
1200
+ /**
1201
+ * Camera bearing in degrees clockwise from North. 0 is North, 90 is East, 180 is South, 270 is West.
1202
+ * This option is only available in 'position-only' mode. In all other modes, the bearing will be calculated automatically.
1203
+ * @default undefined
1204
+ */
1205
+ bearing?: number;
1206
+ /**
1207
+ * @default undefined
1208
+ */
1209
+ elevation?: number;
1210
+ /**
1211
+ * @default 1000
1212
+ */
1213
+ duration?: number;
1214
+ /**
1215
+ * @default 'ease-in-out'
1216
+ */
1217
+ easing?: 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear';
1218
+ };
1219
+ type BlueDotEventPayloads = {
1220
+ /**
1221
+ * Emitted when the Blue Dot's position is updated either from the device's geolocation API or by calling {@link BlueDot.update}.
1222
+ * see {@link BlueDot.watchDevicePosition} for more details.
1223
+ */
1224
+ 'position-update': {
1225
+ floor: Floor | undefined;
1226
+ heading: GeolocationPosition['coords']['heading'] | undefined;
1227
+ accuracy: GeolocationPosition['coords']['accuracy'] | undefined;
1228
+ coordinate: Coordinate;
1229
+ };
1230
+ /**
1231
+ * Emitted when the device's orientation changes and the Blue Dot's heading is updated.
1232
+ * see {@link BlueDot.watchDeviceOrientation} for more details.
1233
+ */
1234
+ 'device-orientation-update': {
1235
+ heading: GeolocationPosition['coords']['heading'] | undefined;
1236
+ };
1237
+ /**
1238
+ * Emitted when the Blue Dot's status changes.
1239
+ */
1240
+ 'status-change': {
1241
+ /**
1242
+ * The new status of the Blue Dot.
1243
+ */
1244
+ status: BlueDotStatus;
1245
+ /**
1246
+ * The action that caused the status change.
1247
+ */
1248
+ action: BlueDotAction;
1249
+ };
1250
+ /**
1251
+ * Emitted when the Blue Dot encounters an error.
1252
+ */
1253
+ error: GeolocationPositionError;
1254
+ /**
1255
+ * Emitted when the Blue Dot's following state changes.
1256
+ */
1257
+ 'follow-change': {
1258
+ /**
1259
+ * Whether the Blue Dot is following the user.
1260
+ */
1261
+ following: boolean;
1262
+ /**
1263
+ * The mode the Blue Dot is following the user in.
1264
+ */
1265
+ mode?: FollowMode;
1266
+ };
1267
+ /**
1268
+ * Emitted when the user clicks on the Blue Dot.
1269
+ */
1270
+ click: {
1271
+ coordinate: Coordinate;
1272
+ };
1273
+ /**
1274
+ * Emitted when the user hovers over the Blue Dot.
1275
+ */
1276
+ hover: {
1277
+ coordinate: Coordinate;
1278
+ };
1279
+ /**
1280
+ * Emitted when a calibration anchor is set (e.g. from VPS or {@link BlueDot.forcePosition}).
1281
+ */
1282
+ 'anchor-set': {
1283
+ anchor: PositionAnchor;
1284
+ };
1285
+ /**
1286
+ * Emitted when a calibration anchor's TTL expires.
1287
+ */
1288
+ 'anchor-expired': {
1289
+ anchor: PositionAnchor;
1290
+ };
1291
+ };
1292
+ type BlueDotState = {
1293
+ /**
1294
+ * The radius of the BlueDot in pixels. The BlueDot will maintain this size clamped to a minimum of 0.35 metres.
1295
+ * @default 10
1296
+ */
1297
+ radius: number;
1298
+ /**
1299
+ * The color of the BlueDot core element.
1300
+ * @default #2266ff
1301
+ */
1302
+ color: string;
1303
+ /**
1304
+ * The color of the BlueDot when it has timed out and gone inactive.
1305
+ * @default #808080
1306
+ */
1307
+ inactiveColor: string;
1308
+ /**
1309
+ * Options for the accuracy ring around the BlueDot.
1310
+ */
1311
+ accuracyRing: {
1312
+ /**
1313
+ * The color of the accuracy ring.
1314
+ * @default #2266ff
1315
+ */
1316
+ color: string;
1317
+ /**
1318
+ * The opacity of the accuracy ring.
1319
+ * @default 0.3
1320
+ */
1321
+ opacity: number;
1322
+ };
1323
+ /**
1324
+ * Options for the heading directional indicator.
1325
+ */
1326
+ heading: {
1327
+ /**
1328
+ * The color of the heading cone.
1329
+ * @default #2266ff
1330
+ */
1331
+ color: string;
1332
+ /**
1333
+ * The opacity of the heading cone.
1334
+ * @default 0.7
1335
+ */
1336
+ opacity: number;
1337
+ /**
1338
+ * Whether to display the heading cone when the BlueDot is inactive (timed out).
1339
+ * @default false
1340
+ */
1341
+ displayWhenInactive: boolean;
1342
+ };
1343
+ /**
1344
+ * The duration of the timeout in milliseconds.
1345
+ * If the BlueDot does not receive a position update within this time, it will grey out until a position is received.
1346
+ * @default 30000
1347
+ */
1348
+ timeout: number;
1349
+ /**
1350
+ * Whether to watch the device's position.
1351
+ * @default true
1352
+ */
1353
+ watchDevicePosition: boolean;
1354
+ /**
1355
+ * Whether to log debug messages.
1356
+ * @default false
1357
+ */
1358
+ debug: boolean;
1359
+ /**
1360
+ * The maximum acceptable accuracy in meters. Position updates with accuracy exceeding this value will be dropped.
1361
+ * @default 50
1362
+ */
1363
+ accuracyThreshold: number;
1364
+ /**
1365
+ * The initial state of the BlueDot when enabled.
1366
+ * @default 'hidden'
1367
+ */
1368
+ initialState: 'hidden' | 'inactive';
1369
+ /**
1370
+ * @hidden
1371
+ * Whether the BlueDot must remain within the map bounds. Disabling this will disable analytics as well.
1372
+ * @default true
1373
+ */
1374
+ preventOutOfBounds: boolean;
1375
+ /**
1376
+ * If true, timestamp will be used to discard updates which are received out of order.
1377
+ * @default true
1378
+ */
1379
+ discardStaleUpdates: boolean;
1380
+ };
1381
+ type BlueDotUpdateState = PartialDeep<BlueDotState>;
1382
+ /**
1383
+ * Position update options for the {@link BlueDot.update} method.
1384
+ */
1385
+ type BlueDotPositionUpdate = {
1386
+ /**
1387
+ * Latitude to override.
1388
+ * Set to `'device'` to reset to the device's latitude.
1389
+ */
1390
+ latitude?: GeolocationPosition['coords']['latitude'] | 'device' | undefined;
1391
+ /**
1392
+ * Longitude to override.
1393
+ * Set to `'device'` to reset to the device's longitude.
1394
+ */
1395
+ longitude?: GeolocationPosition['coords']['longitude'] | 'device' | undefined;
1396
+ /**
1397
+ * Accuracy to override.
1398
+ * Set to `'device'` to reset to the device's accuracy.
1399
+ * Set to `undefined` to disable the accuracy ring.
1400
+ */
1401
+ accuracy?: GeolocationPosition['coords']['accuracy'] | 'device' | undefined;
1402
+ /**
1403
+ * Heading to override.
1404
+ * Set to `'device'` to reset to the device's heading.
1405
+ * Set to `undefined` to disable the heading indicator.
1406
+ */
1407
+ heading?: GeolocationPosition['coords']['heading'] | 'device' | undefined;
1408
+ /**
1409
+ * Floor or floorId to override.
1410
+ * Set to `'device'` to reset to the device's floor level.
1411
+ * Set to `undefined` to disable floor level and show the BlueDot on all floors.
1412
+ */
1413
+ floorOrFloorId?: Floor | string | 'device' | undefined;
1414
+ /**
1415
+ * Timestamp of the position update in milliseconds.
1416
+ */
1417
+ timestamp?: number;
1418
+ };
1419
+ type BlueDotPositionUpdateWithFloor = Omit<BlueDotPositionUpdate, 'floorOrFloorId'> & {
1420
+ floor?: Floor | 'device' | undefined;
1421
+ };
1422
+ type BlueDotPositionProcessor = (current: BlueDotPositionUpdateWithFloor, incoming: BlueDotPositionUpdateWithFloor) => BlueDotPositionUpdateWithFloor | undefined;
1423
+ /**
1424
+ * Options for the BlueDot update method.
1425
+ */
1426
+ type BlueDotUpdateOptions = {
1427
+ /**
1428
+ * If true, maintains the current state and skips timers and analytics for this update.
1429
+ * @default false
1430
+ */
1431
+ silent?: boolean;
1432
+ /**
1433
+ * If true, animates the position change. If false, updates immediately.
1434
+ * @default true
1435
+ */
1436
+ animate?: boolean;
1437
+ };
1438
+ type GeolocationPositionExtended = GeolocationPosition & {
1439
+ coords: GeolocationPosition['coords'] & {
1440
+ readonly floorLevel?: number | null;
1441
+ };
1442
+ };
1443
+ //#endregion
1444
+ //#region ../packages/common/pubsub.d.ts
1445
+ /**
1446
+ * Generic PubSub class implementing the Publish-Subscribe pattern for event handling.
1447
+ *
1448
+ * @template EVENT_PAYLOAD - The type of the event payload.
1449
+ * @template EVENT - The type of the event.
1450
+ */
1451
+ declare class PubSub<EVENT_PAYLOAD, EVENT extends keyof EVENT_PAYLOAD = keyof EVENT_PAYLOAD> {
1452
+ /**
1453
+ * @private
1454
+ * @internal
1455
+ */
1456
+ private _subscribers;
1457
+ /**
1458
+ * @private
1459
+ * @internal
1460
+ * AbortController for managing lifecycle and cleanup
1461
+ */
1462
+ private _abortController;
1463
+ /**
1464
+ * @protected
1465
+ * @internal
1466
+ * Tracks all cleanup functions for subscriptions made via on()
1467
+ */
1468
+ protected _cleanupFunctions: Array<() => void>;
1469
+ /**
1470
+ * Returns the AbortSignal for this PubSub instance.
1471
+ * Use this signal with APIs that support cancellation (fetch, addEventListener, etc.)
1472
+ * When the PubSub is destroyed, the signal will be aborted and all listeners using it will be automatically removed.
1473
+ *
1474
+ * @example
1475
+ * ```typescript
1476
+ * // Automatically cleaned up when PubSub is destroyed
1477
+ * pubsub.addEventListener(window, 'resize', handler, { signal: pubsub.signal });
1478
+ * ```
1479
+ */
1480
+ get signal(): AbortSignal;
1481
+ /**
1482
+ * @private
1483
+ * @internal
1484
+ */
1485
+ publish<EVENT_NAME extends EVENT>(eventName: EVENT_NAME, data?: EVENT_PAYLOAD[EVENT_NAME]): void;
1486
+ /**
1487
+ * Subscribe a function to be called when the signal is aborted.
1488
+ * @param fn The function to call when the signal is aborted.
1489
+ */
1490
+ onAbort<T extends (...args: any[]) => void>(fn: T): void;
1491
+ /**
1492
+ * Subscribe a function to an event.
1493
+ *
1494
+ * @param eventName An event name which, when fired, will call the provided
1495
+ * function.
1496
+ * @param fn A callback that gets called when the corresponding event is fired. The
1497
+ * callback will get passed an argument with a type that's one of event payloads.
1498
+ * @param options Optional options object. If a signal is provided, the subscription will be
1499
+ * automatically cleaned up when that signal is aborted.
1500
+ * @returns A cleanup function that unsubscribes the event listener when called.
1501
+ * @example
1502
+ * // Subscribe to the 'click' event
1503
+ * const handler = (event) => {
1504
+ * const { coordinate } = event;
1505
+ * const { latitude, longitude } = coordinate;
1506
+ * console.log(`Map was clicked at ${latitude}, ${longitude}`);
1507
+ * };
1508
+ * map.on('click', handler);
1509
+ */
1510
+ on<EVENT_NAME extends EVENT>(eventName: EVENT_NAME, fn: (payload: EVENT_PAYLOAD[EVENT_NAME] extends {
1511
+ data: null;
1512
+ } ? EVENT_PAYLOAD[EVENT_NAME]['data'] : EVENT_PAYLOAD[EVENT_NAME]) => void, options?: {
1513
+ signal?: AbortSignal;
1514
+ }): () => void;
1515
+ /**
1516
+ * Unsubscribe a function previously subscribed with {@link on}
1517
+ *
1518
+ * @param eventName An event name to which the provided function was previously
1519
+ * subscribed.
1520
+ * @param fn A function that was previously passed to {@link on}. The function must
1521
+ * have the same reference as the function that was subscribed.
1522
+ * @example
1523
+ * // Unsubscribe from the 'click' event
1524
+ * const handler = (event) => {
1525
+ * console.log('Map was clicked', event);
1526
+ * };
1527
+ * map.off('click', handler);
1528
+ */
1529
+ off<EVENT_NAME extends EVENT>(eventName: EVENT_NAME, fn: (payload: EVENT_PAYLOAD[EVENT_NAME] extends {
1530
+ data: null;
1531
+ } ? EVENT_PAYLOAD[EVENT_NAME]['data'] : EVENT_PAYLOAD[EVENT_NAME]) => void): void;
1532
+ /**
1533
+ * @private
1534
+ * @internal
1535
+ * Destroys the PubSub instance and automatically unsubscribes all listeners registered via on().
1536
+ */
1537
+ destroy(): void;
1538
+ }
1539
+ //#endregion
1540
+ //#region src/sensors/base-sensor.d.ts
1541
+ /**
1542
+ * Options for setting an anchor from a sensor.
1543
+ */
1544
+ interface SetAnchorOptions {
1545
+ /** Latitude in degrees */
1546
+ latitude: number;
1547
+ /** Longitude in degrees */
1548
+ longitude: number;
1549
+ /** Heading in degrees (0-360, clockwise from north) */
1550
+ heading?: number;
1551
+ /** Floor level (elevation) */
1552
+ floorLevel?: number;
1553
+ /**
1554
+ * How long the anchor remains valid in milliseconds.
1555
+ * @default 30000 (30 seconds)
1556
+ */
1557
+ ttl?: number;
1558
+ /**
1559
+ * Confidence score (0-1) for this anchor.
1560
+ * @default 1.0
1561
+ */
1562
+ confidence?: number;
1563
+ /**
1564
+ * Duration in ms where this anchor is exclusive (GPS rejected).
1565
+ * If not specified, uses the FusionEngine's default anchorOnlyPeriodMs.
1566
+ */
1567
+ anchorOnlyPeriodMs?: number;
1568
+ }
1569
+ /**
1570
+ * Abstract base class for all position sources.
1571
+ * Extend this class to create custom position sources (e.g., IPS, BLE beacons).
1572
+ */
1573
+ declare abstract class BaseSensor extends PubSub<SensorEventPayloads> {
1574
+ /** Unique identifier for this sensor */
1575
+ abstract readonly id: string;
1576
+ /** Whether this sensor requires browser/device permission to operate */
1577
+ abstract readonly requiresPermission: boolean;
1578
+ /** Whether this source is currently running */
1579
+ protected enabled: boolean;
1580
+ constructor();
1581
+ /**
1582
+ * Whether this source is currently running and producing updates.
1583
+ */
1584
+ get isEnabled(): boolean;
1585
+ /**
1586
+ * Start receiving position updates from this source.
1587
+ * This is called automatically when the source is enabled.
1588
+ */
1589
+ protected abstract start(): Promise<void>;
1590
+ /**
1591
+ * Stop receiving position updates from this source.
1592
+ * This is called automatically when the source is disabled.
1593
+ */
1594
+ protected abstract stop(): void;
1595
+ /**
1596
+ * Check the current permission state for this source.
1597
+ * @returns The current permission state
1598
+ */
1599
+ abstract checkPermission(): Promise<BrowserPermissionState>;
1600
+ /**
1601
+ * Request permission to use this source.
1602
+ * Must be called in response to a user gesture (click, tap, etc.).
1603
+ * @returns true if permission was granted, false otherwise
1604
+ */
1605
+ abstract requestPermission(): Promise<BrowserPermissionState>;
1606
+ /**
1607
+ * Called when the fusion engine produces a new fused position.
1608
+ * Override this method to receive fused positions for calibration or anchoring.
1609
+ * @param position The fused position from all sources
1610
+ */
1611
+ onFusedPosition(position: FusedPosition): void;
1612
+ /**
1613
+ * Set a position anchor from this sensor.
1614
+ *
1615
+ * Use this when your sensor has a high-confidence absolute position
1616
+ * (e.g., VPS localization, QR code scan, beacon detection).
1617
+ * The anchor will be used as the reference point for position fusion.
1618
+ *
1619
+ * @param options - Anchor position and configuration
1620
+ *
1621
+ * @example
1622
+ * ```typescript
1623
+ * // In your custom sensor after successful localization:
1624
+ * this.setAnchor({
1625
+ * latitude: 43.4723,
1626
+ * longitude: -80.5449,
1627
+ * heading: 90,
1628
+ * floorLevel: 2,
1629
+ * ttl: 30000,
1630
+ * });
1631
+ * ```
1632
+ */
1633
+ protected setAnchor(options: SetAnchorOptions): void;
1634
+ /**
1635
+ * Clear the anchor set by this sensor.
1636
+ *
1637
+ * After clearing, the FusionEngine will fall back to other position sources.
1638
+ */
1639
+ protected clearAnchor(): void;
1640
+ enable(): Promise<BrowserPermissionState>;
1641
+ disable(): void;
1642
+ }
1643
+ //#endregion
1644
+ //#region src/sensors/deviceorientation/deviceorientation.d.ts
1645
+ /**
1646
+ * Configuration options for the device orientation sensor.
1647
+ */
1648
+ interface OrientationSensorConfig {
1649
+ /** Minimum heading change (degrees) before emitting update. */
1650
+ deltaThreshold: number;
1651
+ }
1652
+ declare class DeviceOrientationSensor extends BaseSensor {
1653
+ #private;
1654
+ readonly id = "deviceorientation";
1655
+ constructor();
1656
+ get requiresPermission(): boolean;
1657
+ /**
1658
+ * Configure the sensor parameters at runtime.
1659
+ * @param config Partial configuration to apply
1660
+ */
1661
+ configure(config: Partial<OrientationSensorConfig>): void;
1662
+ /**
1663
+ * Get current configuration values.
1664
+ */
1665
+ getConfig(): OrientationSensorConfig;
1666
+ protected start: () => Promise<void>;
1667
+ protected stop: () => void;
1668
+ checkPermission: () => Promise<BrowserPermissionState>;
1669
+ requestPermission: () => Promise<BrowserPermissionState>;
1670
+ }
1671
+ //#endregion
1672
+ //#region src/sensors/geolocation/outlier-detection.d.ts
1673
+ /**
1674
+ * Configuration for outlier detection.
1675
+ */
1676
+ interface OutlierDetectionConfig {
1677
+ /**
1678
+ * Maximum plausible speed in m/s for a pedestrian.
1679
+ * Positions implying faster movement are considered outliers.
1680
+ * @default 10 (~36 km/h, faster than sprinting)
1681
+ */
1682
+ maxPlausibleSpeed: number;
1683
+ /**
1684
+ * Minimum time between positions to perform speed check (ms).
1685
+ * Avoids division by near-zero for rapid updates.
1686
+ * @default 500
1687
+ */
1688
+ minTimeForSpeedCheck: number;
1689
+ }
1690
+ //#endregion
1691
+ //#region src/sensors/geolocation/geolocation.d.ts
1692
+ declare class GeolocationSensor extends BaseSensor {
1693
+ #private;
1694
+ readonly id = "geolocation";
1695
+ readonly requiresPermission = false;
1696
+ /**
1697
+ * Whether we're likely receiving IPS (Indoor Positioning System) data.
1698
+ * True when positions include floor level, indicating Apple IPS or similar.
1699
+ * This is an assumption based on available signals, not a certainty.
1700
+ */
1701
+ get isLikelyIPS(): boolean;
1702
+ /**
1703
+ * Configure outlier detection parameters.
1704
+ * @param config Partial configuration to apply
1705
+ */
1706
+ configureOutlierDetection(config: Partial<OutlierDetectionConfig>): void;
1707
+ enable(): Promise<BrowserPermissionState>;
1708
+ start(): Promise<void>;
1709
+ protected stop(): void;
1710
+ checkPermission(): Promise<BrowserPermissionState>;
1711
+ requestPermission(): Promise<BrowserPermissionState>;
1712
+ }
1713
+ //#endregion
1714
+ //#region src/sensors/devicemotion/devicemotion.d.ts
1715
+ /**
1716
+ * Configuration options for the device motion sensor.
1717
+ */
1718
+ interface MotionSensorConfig {
1719
+ /** Step detection threshold (m/s²). Lower = more sensitive. */
1720
+ stepDetectionThreshold: number;
1721
+ /** Step length in meters. */
1722
+ stepLength: number;
1723
+ /** Stride adaptation factor (0-1). Higher = vary step length with cadence. */
1724
+ strideAdaptation: number;
1725
+ /** Motion detection threshold (m/s²). Lower = more responsive. */
1726
+ motionThreshold: number;
1727
+ /** Enable PDR displacement calculation. */
1728
+ pdrEnabled: boolean;
1729
+ }
1730
+ /**
1731
+ * Sensor that provides device motion data (acceleration).
1732
+ * Useful for detecting if the user is stationary or moving,
1733
+ * which can affect confidence in position estimates.
1734
+ *
1735
+ * PDR (Pedestrian Dead Reckoning) logic is implemented using pure functions
1736
+ * from `./pdr.ts` for testability. The sensor manages state and coordinates
1737
+ * the pure functions.
1738
+ */
1739
+ declare class DeviceMotionSensor extends BaseSensor {
1740
+ #private;
1741
+ readonly id = "devicemotion";
1742
+ get requiresPermission(): boolean;
1743
+ protected start: () => Promise<void>;
1744
+ protected stop: () => void;
1745
+ checkPermission: () => Promise<BrowserPermissionState>;
1746
+ requestPermission: () => Promise<BrowserPermissionState>;
1747
+ /**
1748
+ * Whether the device is currently detected as moving.
1749
+ */
1750
+ get isMoving(): boolean;
1751
+ /**
1752
+ * Set current heading for PDR displacement calculation.
1753
+ * Called by SensorRegistry when heading updates arrive from deviceorientation.
1754
+ * Applies exponential smoothing to prevent zigzag paths from heading jitter.
1755
+ * @param heading Heading in degrees (0-360)
1756
+ */
1757
+ setHeading(heading: number): void;
1758
+ /**
1759
+ * Configure the sensor parameters at runtime.
1760
+ * @param config Partial configuration to apply
1761
+ */
1762
+ configure(config: Partial<MotionSensorConfig>): void;
1763
+ /**
1764
+ * Get current configuration values.
1765
+ */
1766
+ getConfig(): MotionSensorConfig;
1767
+ }
1768
+ //#endregion
1769
+ //#region src/sensors/manual/manual-sensor.d.ts
1770
+ /**
1771
+ * Options for reporting a manual position update.
1772
+ */
1773
+ interface ManualPositionOptions {
1774
+ /** Latitude in degrees */
1775
+ latitude: number;
1776
+ /** Longitude in degrees */
1777
+ longitude: number;
1778
+ /** Accuracy in meters */
1779
+ accuracy?: number;
1780
+ /** Heading in degrees (0-360, clockwise from north) */
1781
+ heading?: number;
1782
+ /** Floor level (elevation) */
1783
+ floorLevel?: number;
1784
+ /**
1785
+ * Confidence score (0-1) indicating how much to trust this position.
1786
+ * Higher confidence = more influence on the fused position.
1787
+ * @default 0.5
1788
+ */
1789
+ confidence?: number;
1790
+ /** Timestamp in milliseconds. Defaults to Date.now() */
1791
+ timestamp?: number;
1792
+ }
1793
+ /**
1794
+ * Options for reporting a manual relative displacement.
1795
+ */
1796
+ interface ManualDisplacementOptions {
1797
+ /** Displacement in meters along east-west axis (positive = east) */
1798
+ dx: number;
1799
+ /** Displacement in meters along north-south axis (positive = north) */
1800
+ dy: number;
1801
+ /** Heading in degrees (optional) */
1802
+ heading?: number;
1803
+ /**
1804
+ * Confidence score (0-1) indicating how much to trust this displacement.
1805
+ * @default 0.8
1806
+ */
1807
+ confidence?: number;
1808
+ /** Timestamp in milliseconds. Defaults to Date.now() */
1809
+ timestamp?: number;
1810
+ }
1811
+ /**
1812
+ * A manual sensor that allows programmatic position reporting.
1813
+ *
1814
+ * This sensor enables integrating external positioning systems (IPS, beacons,
1815
+ * custom algorithms) into the BlueDot fusion engine. Positions are weighted
1816
+ * by confidence and combined with other sensor data.
1817
+ *
1818
+ * @example Basic IPS integration
1819
+ * ```typescript
1820
+ * const manual = blueDot.Sensors.get('manual');
1821
+ *
1822
+ * // Report position from your IPS with confidence
1823
+ * myIPS.onPosition((pos) => {
1824
+ * manual.reportPosition({
1825
+ * latitude: pos.lat,
1826
+ * longitude: pos.lon,
1827
+ * accuracy: pos.accuracy,
1828
+ * confidence: pos.confidence,
1829
+ * });
1830
+ * });
1831
+ * ```
1832
+ */
1833
+ declare class ManualSensor extends BaseSensor {
1834
+ #private;
1835
+ readonly id: "manual";
1836
+ readonly requiresPermission = false;
1837
+ /**
1838
+ * Report an absolute position to the fusion engine.
1839
+ *
1840
+ * The position will be combined with other sensor data based on its
1841
+ * confidence score. Higher confidence = more influence on the result.
1842
+ *
1843
+ * @param options - Position data with confidence
1844
+ *
1845
+ * @example
1846
+ * ```typescript
1847
+ * manualSensor.reportPosition({
1848
+ * latitude: 43.4723,
1849
+ * longitude: -80.5449,
1850
+ * accuracy: 5,
1851
+ * confidence: 0.9,
1852
+ * });
1853
+ * ```
1854
+ */
1855
+ reportPosition(options: ManualPositionOptions): void;
1856
+ /**
1857
+ * Report a relative displacement to the fusion engine.
1858
+ *
1859
+ * Use this for dead-reckoning style updates where you know the
1860
+ * displacement from the previous position but not the absolute location.
1861
+ * Only meaningful when an anchor is active.
1862
+ *
1863
+ * @param options - Displacement data with confidence
1864
+ *
1865
+ * @example
1866
+ * ```typescript
1867
+ * manualSensor.reportDisplacement({
1868
+ * dx: 0.5, // 0.5 meters east
1869
+ * dy: 1.0, // 1.0 meters north
1870
+ * confidence: 0.8,
1871
+ * });
1872
+ * ```
1873
+ */
1874
+ reportDisplacement(options: ManualDisplacementOptions): void;
1875
+ /**
1876
+ * Force a position as an anchor, overriding all other sensors for the specified duration.
1877
+ *
1878
+ * This is a convenience method that wraps `setAnchor()` for the manual sensor.
1879
+ * The position will completely dominate the fusion engine until the TTL expires.
1880
+ *
1881
+ * @param options - Position and duration options
1882
+ *
1883
+ * @example
1884
+ * ```typescript
1885
+ * manualSensor.forcePosition({
1886
+ * latitude: 43.4723,
1887
+ * longitude: -80.5449,
1888
+ * heading: 90,
1889
+ * ttl: 30000, // 30 seconds
1890
+ * });
1891
+ * ```
1892
+ */
1893
+ forcePosition(options: {
1894
+ latitude: number;
1895
+ longitude: number;
1896
+ heading?: number;
1897
+ floorLevel?: number;
1898
+ /** How long the forced position remains active in milliseconds. @default 30000 */
1899
+ ttl?: number;
1900
+ }): void;
1901
+ /**
1902
+ * Clear the forced position set by this sensor.
1903
+ * After clearing, the fusion engine will fall back to other position sources.
1904
+ */
1905
+ clearForcedPosition(): void;
1906
+ protected start(): Promise<void>;
1907
+ protected stop(): void;
1908
+ checkPermission(): Promise<BrowserPermissionState>;
1909
+ requestPermission(): Promise<BrowserPermissionState>;
1910
+ }
1911
+ //#endregion
1912
+ //#region src/sensors/sensor-registry.d.ts
1913
+ /**
1914
+ * Maps built-in sensor IDs to their concrete sensor types.
1915
+ */
1916
+ type BuiltInSensorMap = {
1917
+ geolocation: GeolocationSensor;
1918
+ deviceorientation: DeviceOrientationSensor;
1919
+ devicemotion: DeviceMotionSensor;
1920
+ manual: ManualSensor;
1921
+ };
1922
+ /**
1923
+ * Registry for managing position sensors.
1924
+ *
1925
+ * @example
1926
+ * ```ts
1927
+ * // Enable built-in sensors
1928
+ * blueDot.Sensors.get('geolocation')?.enable();
1929
+ * blueDot.Sensors.get('deviceorientation')?.enable();
1930
+ *
1931
+ * // Register and enable a custom sensor
1932
+ * const customSensor = blueDot.Sensors.register(new MyCustomSensor());
1933
+ * customSensor.enable();
1934
+ * ```
1935
+ */
1936
+ declare class SensorRegistry extends PubSub<SensorEventPayloads> {
1937
+ #private;
1938
+ constructor();
1939
+ /**
1940
+ * Register a sensor.
1941
+ * @param sensor The sensor to register
1942
+ * @returns The sensor if registered, undefined if already registered
1943
+ */
1944
+ register<T extends BaseSensor>(sensor: T & {
1945
+ id: CustomSensorId<T['id']>;
1946
+ }): T | undefined;
1947
+ /**
1948
+ * Get a registered sensor by ID.
1949
+ * @param sensorId The ID of the sensor to get
1950
+ * @returns The sensor, or undefined if not found
1951
+ */
1952
+ get<K extends SensorId>(sensorId: K): K extends keyof BuiltInSensorMap ? BuiltInSensorMap[K] | undefined : BaseSensor | undefined;
1953
+ /**
1954
+ * Unregister a sensor.
1955
+ * @param sensor The sensor to unregister
1956
+ */
1957
+ unregister(sensor: BaseSensor): void;
1958
+ /**
1959
+ * Unregister a sensor.
1960
+ * @param sensorId The ID of the sensor to unregister
1961
+ */
1962
+ unregister(sensorId: SensorId): void;
1963
+ /**
1964
+ * Get all registered sensors.
1965
+ * @returns An iterator of [sensorId, sensor] pairs
1966
+ */
1967
+ getAll(): IterableIterator<[SensorId, BaseSensor]>;
1968
+ /**
1969
+ * Destroy the registry and clean up all sensors.
1970
+ */
1971
+ destroy(): void;
1972
+ }
1973
+ //#endregion
1974
+ //#region src/fusion/algorithms/types.d.ts
1975
+ /**
1976
+ * Interface for heading fusion algorithms.
1977
+ * Combines compass, gyroscope, and GPS heading for stable heading estimation.
1978
+ */
1979
+ interface HeadingFusionAlgorithm {
1980
+ /**
1981
+ * Update with compass heading (absolute but noisy).
1982
+ * @param heading Compass heading in degrees [0, 360)
1983
+ * @param timestamp Update timestamp in milliseconds
1984
+ */
1985
+ updateCompass(heading: number, timestamp: number): void;
1986
+ /**
1987
+ * Update with gyroscope angular velocity (smooth relative changes).
1988
+ * @param angularVelocity Angular velocity in deg/s around vertical axis
1989
+ * @param timestamp Update timestamp in milliseconds
1990
+ */
1991
+ updateGyro(angularVelocity: number, timestamp: number): void;
1992
+ /**
1993
+ * Correct heading with GPS ground truth when moving.
1994
+ * @param gpsHeading GPS heading in degrees [0, 360)
1995
+ * @param speed Current speed in m/s
1996
+ */
1997
+ correctWithGps(gpsHeading: number, speed: number): void;
1998
+ /**
1999
+ * Get the current fused heading.
2000
+ * @returns Fused heading in degrees [0, 360), or null if not initialized
2001
+ */
2002
+ getHeading(): number | null;
2003
+ /**
2004
+ * Reset the algorithm state.
2005
+ */
2006
+ reset(): void;
2007
+ }
2008
+ //#endregion
2009
+ //#region src/fusion/algorithms/heading-filter.d.ts
2010
+ /**
2011
+ * Configuration options for the heading fusion filter.
2012
+ */
2013
+ interface HeadingFilterConfig {
2014
+ /** Complementary filter alpha (0-1). Higher = more gyro weight. */
2015
+ complementaryAlpha: number;
2016
+ /** Minimum angular velocity to integrate (deg/s). */
2017
+ gyroNoiseThreshold: number;
2018
+ /** Maximum heading error before snapping to compass (degrees). */
2019
+ maxHeadingError: number;
2020
+ /** Enable magnetic disturbance detection. */
2021
+ magneticGatingEnabled: boolean;
2022
+ /** Minimum heading delta to emit updates (degrees). */
2023
+ deltaThreshold: number;
2024
+ }
2025
+ /**
2026
+ * Complementary filter for heading fusion.
2027
+ * Combines compass (absolute but noisy), gyroscope (smooth relative changes),
2028
+ * and GPS heading (ground truth when moving) to produce stable heading.
2029
+ *
2030
+ * The filter works by:
2031
+ * 1. Short-term: Integrate gyroscope angular velocity for smooth rotations
2032
+ * 2. Long-term: Slowly blend toward compass to prevent gyroscope drift
2033
+ * 3. Correction: When GPS heading is valid (moving fast enough), use as ground truth
2034
+ *
2035
+ * @example
2036
+ * ```ts
2037
+ * const filter = new HeadingFusionFilter();
2038
+ *
2039
+ * // Update with compass reading
2040
+ * filter.updateCompass(45, Date.now());
2041
+ *
2042
+ * // Update with gyroscope angular velocity
2043
+ * filter.updateGyro(5.0, Date.now()); // 5 deg/s rotation
2044
+ *
2045
+ * // Correct with GPS when moving
2046
+ * filter.correctWithGps(47, 1.5); // heading 47°, speed 1.5 m/s
2047
+ *
2048
+ * // Get fused heading
2049
+ * const heading = filter.getHeading(); // ~46°
2050
+ * ```
2051
+ */
2052
+ declare class HeadingFusionFilter implements HeadingFusionAlgorithm {
2053
+ #private;
2054
+ /**
2055
+ * Update the filter with a compass heading reading.
2056
+ * The compass provides absolute heading but is susceptible to magnetic interference.
2057
+ * @param heading Compass heading in degrees [0, 360)
2058
+ * @param timestamp Update timestamp in milliseconds
2059
+ */
2060
+ updateCompass(heading: number, _timestamp: number): void;
2061
+ /**
2062
+ * Update the filter with gyroscope angular velocity.
2063
+ * The gyroscope provides smooth relative heading changes immune to magnetic fields.
2064
+ * @param angularVelocity Angular velocity around vertical axis in deg/s
2065
+ * @param timestamp Update timestamp in milliseconds
2066
+ */
2067
+ updateGyro(angularVelocity: number, timestamp: number): void;
2068
+ /**
2069
+ * Correct the heading with GPS when available.
2070
+ * GPS heading is only considered when moving fast enough and with sufficient confidence.
2071
+ * @param gpsHeading GPS heading in degrees [0, 360)
2072
+ * @param speed Current speed in m/s
2073
+ * @param confidence GPS confidence (0-1), affects how much GPS heading influences result
2074
+ */
2075
+ correctWithGps(gpsHeading: number, speed: number, confidence?: number): void;
2076
+ /**
2077
+ * Configure the filter parameters at runtime.
2078
+ * @param config Partial configuration to apply
2079
+ */
2080
+ configure(config: Partial<HeadingFilterConfig>): void;
2081
+ /**
2082
+ * Get current configuration values.
2083
+ */
2084
+ getConfig(): HeadingFilterConfig;
2085
+ /**
2086
+ * Check if magnetic disturbance is currently detected.
2087
+ */
2088
+ isMagneticDisturbanceActive(): boolean;
2089
+ /**
2090
+ * Get the current fused heading.
2091
+ * @returns Fused heading in degrees [0, 360), or null if not initialized
2092
+ */
2093
+ getHeading(): number | null;
2094
+ /**
2095
+ * Check if the filter has been initialized with at least one compass reading.
2096
+ * @returns True if filter is initialized
2097
+ */
2098
+ isInitialized(): boolean;
2099
+ /**
2100
+ * Get the last compass heading received.
2101
+ * @returns Last compass heading in degrees, or null if none received
2102
+ */
2103
+ getLastCompassHeading(): number | null;
2104
+ /**
2105
+ * Reset the filter state.
2106
+ * Call on floor changes or when heading should be re-initialized.
2107
+ */
2108
+ reset(): void;
2109
+ }
2110
+ //#endregion
2111
+ //#region src/fusion/algorithms/multi-sensor-ekf.d.ts
2112
+ /**
2113
+ * Configuration options for the Multi-Sensor EKF.
2114
+ */
2115
+ interface MultiSensorEKFOptions {
2116
+ /**
2117
+ * Half-life for uncertainty growth in milliseconds.
2118
+ * The state uncertainty doubles every halfLifeMs when no measurements arrive.
2119
+ * Lower values = faster decay of old estimates.
2120
+ * @default 10000 (10 seconds)
2121
+ */
2122
+ halfLifeMs: number;
2123
+ }
2124
+ /**
2125
+ * Multi-sensor Extended Kalman Filter for position fusion.
2126
+ *
2127
+ * Combines position measurements from multiple sources (GPS, VPS, anchors) and
2128
+ * displacement measurements from PDR using a constant-velocity motion model.
2129
+ *
2130
+ * Key features:
2131
+ * - All methods take explicit timestamps (no Date.now() inside)
2132
+ * - Confidence-weighted fusion via measurement noise parameter
2133
+ * - Half-life decay of old estimates via process noise scaling
2134
+ * - Supports both absolute position and relative displacement updates
2135
+ *
2136
+ * State vector: [latitude, longitude, velocity_lat, velocity_lon]
2137
+ *
2138
+ * @example
2139
+ * ```ts
2140
+ * const ekf = new MultiSensorEKF({ halfLifeMs: 10000 });
2141
+ *
2142
+ * // Initialize with first position
2143
+ * ekf.updatePosition(43.123, -79.456, 0.0001, 0);
2144
+ *
2145
+ * // Predict forward
2146
+ * ekf.predict(1000);
2147
+ *
2148
+ * // Update with new GPS measurement (low confidence = high noise)
2149
+ * ekf.updatePosition(43.124, -79.455, 0.001, 1000);
2150
+ *
2151
+ * // Get fused position
2152
+ * const pos = ekf.getPosition(); // { latitude: ~43.1235, longitude: ~-79.4555 }
2153
+ * ```
2154
+ */
2155
+ declare class MultiSensorEKF {
2156
+ #private;
2157
+ constructor(options?: Partial<MultiSensorEKFOptions>);
2158
+ /**
2159
+ * Predict step: project state forward to the given timestamp.
2160
+ * Increases uncertainty based on elapsed time and half-life configuration.
2161
+ *
2162
+ * @param timestampMs - Current timestamp in milliseconds
2163
+ */
2164
+ predict(timestampMs: number): void;
2165
+ /**
2166
+ * Update state with a position measurement (GPS, VPS, anchor).
2167
+ *
2168
+ * @param latitude - Measured latitude in degrees
2169
+ * @param longitude - Measured longitude in degrees
2170
+ * @param measurementNoise - Measurement noise variance (higher = less trust)
2171
+ * @param timestampMs - Measurement timestamp in milliseconds
2172
+ */
2173
+ updatePosition(latitude: number, longitude: number, measurementNoise: number, timestampMs: number): void;
2174
+ /**
2175
+ * Update state with an odometry measurement (PDR displacement).
2176
+ *
2177
+ * Unlike position updates, odometry provides relative displacement rather than
2178
+ * absolute position. The displacement is added directly to the state.
2179
+ *
2180
+ * @param dx - Displacement east in meters (positive = east)
2181
+ * @param dy - Displacement north in meters (positive = north)
2182
+ * @param measurementNoise - Measurement noise variance (higher = less trust)
2183
+ * @param timestampMs - Measurement timestamp in milliseconds
2184
+ */
2185
+ updateOdometry(dx: number, dy: number, measurementNoise: number, timestampMs: number): void;
2186
+ /**
2187
+ * Get the current position estimate.
2188
+ * @returns Position or null if filter not initialized
2189
+ */
2190
+ getPosition(): {
2191
+ latitude: number;
2192
+ longitude: number;
2193
+ } | null;
2194
+ /**
2195
+ * Get the current velocity estimate.
2196
+ * @returns Velocity in degrees per second, or null if filter not initialized
2197
+ */
2198
+ getVelocity(): {
2199
+ vLat: number;
2200
+ vLon: number;
2201
+ } | null;
2202
+ /**
2203
+ * Get the current position uncertainty (trace of position covariance).
2204
+ * Higher values indicate less certainty in the position estimate.
2205
+ * @returns Uncertainty value, or Infinity if filter not initialized
2206
+ */
2207
+ getUncertainty(): number;
2208
+ /**
2209
+ * Get the last update timestamp.
2210
+ * @returns Timestamp in ms, or null if filter not initialized
2211
+ */
2212
+ getLastTimestamp(): number | null;
2213
+ /**
2214
+ * Check if the filter has been initialized with at least one measurement.
2215
+ */
2216
+ isInitialized(): boolean;
2217
+ /**
2218
+ * Reset the filter state.
2219
+ * Call on floor changes, large position jumps, or time gaps.
2220
+ */
2221
+ reset(): void;
2222
+ }
2223
+ //#endregion
2224
+ //#region src/fusion/fusion-engine.d.ts
2225
+ /**
2226
+ * Multi-sensor fusion engine that combines position updates from multiple sources.
2227
+ *
2228
+ * Uses an Extended Kalman Filter (EKF) for position fusion with:
2229
+ * - Confidence-weighted measurements (high confidence = more influence)
2230
+ * - Half-life decay of old estimates (uncertainty grows over time)
2231
+ * - Hybrid anchor behavior (anchor-only period, then transition to GPS)
2232
+ *
2233
+ * Heading fusion uses a separate complementary filter combining compass and gyroscope.
2234
+ */
2235
+ declare class FusionEngine extends PubSub<FusionEventPayloads> {
2236
+ #private;
2237
+ constructor(registry: SensorRegistry, config?: Partial<FusionEngineConfig>);
2238
+ /**
2239
+ * Get the current fusion configuration.
2240
+ */
2241
+ get config(): Readonly<FusionEngineConfig>;
2242
+ /**
2243
+ * Get the current anchor state.
2244
+ * @param nowMs - Current timestamp (defaults to Date.now())
2245
+ */
2246
+ getAnchorState(nowMs?: number): AnchorState;
2247
+ /**
2248
+ * Get the current position anchor if one is set and not expired.
2249
+ */
2250
+ get anchor(): Readonly<PositionAnchor> | undefined;
2251
+ /**
2252
+ * Get the current accumulated displacement from the anchor in meters.
2253
+ * Returns (0, 0) if no anchor is set or no movement has occurred.
2254
+ */
2255
+ get displacement(): Readonly<DisplacementVector>;
2256
+ /**
2257
+ * Set an absolute position anchor from a calibration source (VPS, AI Localizer).
2258
+ * When an anchor is active, it provides the absolute position and other sensors
2259
+ * can provide relative updates from this reference point.
2260
+ *
2261
+ * @param anchor - The position anchor to set
2262
+ * @param configOverride - Optional config overrides for this anchor (e.g., anchorOnlyPeriodMs)
2263
+ */
2264
+ setAnchor(anchor: PositionAnchor, configOverride?: Partial<Pick<FusionEngineConfig, 'anchorOnlyPeriodMs'>>): void;
2265
+ /**
2266
+ * Clear the current position anchor and accumulated displacement.
2267
+ */
2268
+ clearAnchor(): void;
2269
+ /**
2270
+ * Reset the EKF state.
2271
+ * Call on floor changes or large position jumps.
2272
+ */
2273
+ resetEKF(): void;
2274
+ /**
2275
+ * Reset the heading fusion filter state.
2276
+ * Call on floor changes or when heading should be re-initialized.
2277
+ */
2278
+ resetHeadingFilter(): void;
2279
+ /**
2280
+ * Get the heading fusion filter for configuration.
2281
+ * @internal Used by debug tools for runtime tuning.
2282
+ */
2283
+ get headingFilter(): HeadingFusionFilter;
2284
+ /**
2285
+ * Get the multi-sensor EKF for inspection.
2286
+ * @internal Used by debug tools for runtime inspection.
2287
+ */
2288
+ get ekf(): MultiSensorEKF;
2289
+ /**
2290
+ * Get the last fused position.
2291
+ * @returns The last fused position, or undefined if none available
2292
+ */
2293
+ getLastPosition(): FusedPosition | undefined;
2294
+ destroy(): void;
2295
+ }
2296
+ //#endregion
2297
+ //#region src/blue-dot.d.ts
2298
+ /**
2299
+ * Show a Blue Dot indicating the device's position on the map.
2300
+ *
2301
+ * @example
2302
+ * ```ts
2303
+ * import { show3dMap } from '@mappedin/mappedin-js';
2304
+ * import { BlueDot } from '@mappedin/blue-dot';
2305
+ *
2306
+ * const mapView = await show3dMap(...);
2307
+ *
2308
+ * // Enable BlueDot
2309
+ * const blueDot = new BlueDot(mapView).enable();
2310
+ *
2311
+ * // Option 1: Listen for position updates from the device
2312
+ * blueDot.on('position-update', (position) => {
2313
+ * console.log('User position:', position);
2314
+ * });
2315
+ *
2316
+ * // Option 2: Update position manually
2317
+ * blueDot.update({ latitude, longitude, accuracy, floorOrFloorId });
2318
+ *
2319
+ * ```
2320
+ */
2321
+ declare class BlueDot implements MapViewExtension<BlueDotState> {
2322
+ #private;
2323
+ /**
2324
+ * Create a new {@link BlueDot} instance.
2325
+ */
2326
+ constructor(mapView: MapView);
2327
+ /** Sensors API */
2328
+ get Sensors(): SensorRegistry;
2329
+ /**
2330
+ * Fusion engine API.
2331
+ * @internal Used by debug tools for runtime tuning and inspection.
2332
+ */
2333
+ get Fusion(): FusionEngine;
2334
+ /**
2335
+ * Get the current position anchor if one is set and not expired.
2336
+ * Anchors provide absolute ground truth positions from calibration sources (VPS, AI Localizer).
2337
+ */
2338
+ get anchor(): Readonly<PositionAnchor> | undefined;
2339
+ /**
2340
+ * Get the current accumulated displacement from the anchor in meters.
2341
+ * Returns { dx: 0, dy: 0 } if no anchor is set or no movement has occurred.
2342
+ */
2343
+ get displacement(): Readonly<DisplacementVector>;
2344
+ /**
2345
+ * Get the Model for the BlueDot core element.
2346
+ */
2347
+ get dotModel(): Model | undefined;
2348
+ /**
2349
+ * Get the Model for the accuracy ring.
2350
+ */
2351
+ get accuracyRingModel(): Model | undefined;
2352
+ /**
2353
+ * Get the Model for the heading cone.
2354
+ */
2355
+ get headingConeModel(): Model | undefined;
2356
+ /**
2357
+ * Whether the BlueDot is currently enabled.
2358
+ */
2359
+ get isEnabled(): boolean;
2360
+ /**
2361
+ * The current state of the BlueDot. Can be 'hidden', 'active', 'inactive', or 'disabled'.
2362
+ * Listen for state changes using the 'status-change' event.
2363
+ *
2364
+ * @example
2365
+ * mapView.BlueDot.on('status-change', ({ status }) => {
2366
+ * if (status === 'active') {
2367
+ * // BlueDot is visible and tracking
2368
+ * }
2369
+ * });
2370
+ */
2371
+ get status(): BlueDotStatus;
2372
+ /**
2373
+ * Whether the BlueDot is currently following the user (camera follow mode).
2374
+ */
2375
+ get isFollowing(): boolean;
2376
+ /**
2377
+ * The direction the user is facing in degrees from north clockwise.
2378
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/GeolocationCoordinates/heading
2379
+ */
2380
+ get heading(): GeolocationPosition['coords']['heading'] | undefined;
2381
+ /**
2382
+ * The accuracy of the current position in metres.
2383
+ */
2384
+ get accuracy(): GeolocationPosition['coords']['accuracy'] | undefined;
2385
+ /**
2386
+ * The coordinate of the current position.
2387
+ */
2388
+ get coordinate(): Coordinate | undefined;
2389
+ /**
2390
+ * Returns the current Blue Dot state.
2391
+ */
2392
+ getState(): ReadonlyDeep<BlueDotState>;
2393
+ /**
2394
+ * The floor the Blue Dot is currently on. If undefined, the Blue Dot will appear on every floor.
2395
+ */
2396
+ get floor(): Floor | undefined;
2397
+ /**
2398
+ * Force the Blue Dot to a specific position for a duration, overriding all other sensors.
2399
+ *
2400
+ * This sets a high-confidence anchor that completely dominates the fusion engine
2401
+ * for the specified duration. GPS, compass, and other sensors are ignored while
2402
+ * the forced position is active. After the duration expires, normal sensor fusion resumes.
2403
+ *
2404
+ * Use this when you have an authoritative position from an external system
2405
+ * (e.g., VPS, QR code scan, manual user correction) that should override everything else.
2406
+ *
2407
+ * @param position - The position to force
2408
+ * @param durationMs - How long to maintain this position in milliseconds (default: 30 seconds)
2409
+ *
2410
+ * @example Force position from VPS scan
2411
+ * ```ts
2412
+ * blueDot.forcePosition({
2413
+ * latitude: 43.4723,
2414
+ * longitude: -80.5449,
2415
+ * heading: 90,
2416
+ * floorLevel: 2,
2417
+ * }, 30000); // 30 seconds
2418
+ * ```
2419
+ *
2420
+ * @example Force position indefinitely (call again with different position or let it expire)
2421
+ * ```ts
2422
+ * blueDot.forcePosition({
2423
+ * latitude: 43.4723,
2424
+ * longitude: -80.5449,
2425
+ * }, Infinity);
2426
+ * ```
2427
+ */
2428
+ forcePosition(position: {
2429
+ latitude: number;
2430
+ longitude: number;
2431
+ heading?: number;
2432
+ floorLevel?: number;
2433
+ }, durationMs?: number): void;
2434
+ /**
2435
+ * Report a position to the fusion engine with a confidence score.
2436
+ *
2437
+ * Unlike {@link forcePosition}, this does NOT override other sensors. Instead,
2438
+ * the reported position is weighted by confidence and combined with GPS, compass,
2439
+ * and other active sensors through the fusion engine.
2440
+ *
2441
+ * Use this for integrating external positioning systems (IPS, beacons, WiFi RTT)
2442
+ * that should contribute to but not dominate the fused position.
2443
+ *
2444
+ * @param options - Position data with confidence score
2445
+ *
2446
+ * @example Simple IPS integration
2447
+ * ```ts
2448
+ * // Low confidence - will blend with GPS
2449
+ * blueDot.reportPosition({
2450
+ * latitude: 43.4723,
2451
+ * longitude: -80.5449,
2452
+ * accuracy: 10,
2453
+ * confidence: 0.3,
2454
+ * });
2455
+ * ```
2456
+ *
2457
+ * @example High confidence beacon
2458
+ * ```ts
2459
+ * // High confidence - will dominate over GPS
2460
+ * blueDot.reportPosition({
2461
+ * latitude: 43.4723,
2462
+ * longitude: -80.5449,
2463
+ * accuracy: 2,
2464
+ * confidence: 0.95,
2465
+ * });
2466
+ * ```
2467
+ */
2468
+ reportPosition(options: ManualPositionOptions): void;
2469
+ /**
2470
+ * Enable a sensor by ID and request permissions if needed.
2471
+ * @param sensorId - The ID of the sensor to enable
2472
+ * @returns The permission state after enabling
2473
+ */
2474
+ __enableSensor(sensorId: string): Promise<BrowserPermissionState>;
2475
+ /**
2476
+ * Disable a sensor by ID.
2477
+ * @param sensorId - The ID of the sensor to disable
2478
+ */
2479
+ __disableSensor(sensorId: string): void;
2480
+ /**
2481
+ * Check the current permission state for a sensor.
2482
+ * @param sensorId - The ID of the sensor to check
2483
+ * @returns The current permission state
2484
+ */
2485
+ __checkSensorPermission(sensorId: string): Promise<BrowserPermissionState>;
2486
+ /**
2487
+ * Request permission for a sensor. Must be called in response to a user gesture.
2488
+ * @param sensorId - The ID of the sensor
2489
+ * @returns The permission state after requesting
2490
+ */
2491
+ __requestSensorPermission(sensorId: string): Promise<BrowserPermissionState>;
2492
+ /**
2493
+ * Check if a sensor is currently enabled.
2494
+ * @param sensorId - The ID of the sensor to check
2495
+ * @returns Whether the sensor is enabled
2496
+ */
2497
+ __isSensorEnabled(sensorId: string): boolean;
2498
+ /**
2499
+ * Enable the Blue Dot. It will be hidden until a position is received either from the browser or by calling {@link BlueDot.update}.
2500
+ * @param options - The options to setup the Blue Dot (see {@link BlueDotUpdateState}).
2501
+ *
2502
+ * @example Enable with default options
2503
+ * ```ts
2504
+ * const blueDot = new BlueDot(mapView);
2505
+ * blueDot.enable();
2506
+ * ```
2507
+ * @example Enable with custom color and accuracy ring
2508
+ * ```ts
2509
+ * const blueDot = new BlueDot(mapView);
2510
+ * blueDot.enable({ color: '#00ff00', accuracyRing: { color: '#00ff00', opacity: 0.2 } });
2511
+ * ```
2512
+ *
2513
+ * @see See the [BlueDot Guide](https://developer.mappedin.com/web-sdk/blue-dot) for more information.
2514
+ */
2515
+ enable: (options?: BlueDotUpdateState) => void;
2516
+ /**
2517
+ * Disable the Blue Dot. It will be hidden and no longer update.
2518
+ *
2519
+ * The status transition to 'disabled' occurs after all cleanup operations complete.
2520
+ * This ensures that any 'status-change' event listeners see the BlueDot in a fully
2521
+ * cleaned up state with all resources released.
2522
+ */
2523
+ disable: () => void;
2524
+ /**
2525
+ * Subscribe to a BlueDot event.
2526
+ * @param eventName The name of the event to listen for.
2527
+ * @param fn The function to call when the event is emitted.
2528
+ */
2529
+ on: <BlueDotEventName extends keyof BlueDotEventPayloads>(eventName: BlueDotEventName, fn: (payload: BlueDotEventPayloads[BlueDotEventName] extends {
2530
+ data: null;
2531
+ } ? BlueDotEventPayloads[BlueDotEventName]["data"] : BlueDotEventPayloads[BlueDotEventName]) => void) => () => void;
2532
+ /**
2533
+ * Unsubscribe from a BlueDot event.
2534
+ * @param eventName The name of the event to unsubscribe from.
2535
+ * @param fn The function to unsubscribe from the event.
2536
+ */
2537
+ off: <BlueDotEventName extends keyof BlueDotEventPayloads>(eventName: BlueDotEventName, fn: (payload: BlueDotEventPayloads[BlueDotEventName] extends {
2538
+ data: null;
2539
+ } ? BlueDotEventPayloads[BlueDotEventName]["data"] : BlueDotEventPayloads[BlueDotEventName]) => void) => void;
2540
+ /**
2541
+ * Update the BlueDot state after it has been enabled.
2542
+ * This allows overriding previously set values like colors, and other options.
2543
+ * @param options - The options to update
2544
+ *
2545
+ * @example Update color and accuracy ring
2546
+ * ```ts
2547
+ * const blueDot = new BlueDot(mapView);
2548
+ * blueDot.updateState({
2549
+ * color: '#ff0000',
2550
+ * accuracyRing: { color: '#ff0000', opacity: 0.5 }
2551
+ * });
2552
+ * ```
2553
+ */
2554
+ updateState: (options: BlueDotUpdateState) => void;
2555
+ /**
2556
+ * Enable or disable the devices's geolocation listener to automatically position the Blue Dot.
2557
+ * If enabled, the device will request permission to access the user's precise location.
2558
+ *
2559
+ * @remarks This will emit a 'position-update' event every time a new position is received.
2560
+ * @deprecated Use the {@link BlueDot.Sensors} API and fusion engine for position updates instead.
2561
+ *
2562
+ * @param watch - Whether to enable or disable the listener.
2563
+ */
2564
+ watchDevicePosition: (watch: boolean) => void;
2565
+ /**
2566
+ * Enable or disable the device orientation listener to automatically update the Blue Dot's heading.
2567
+ * This must be enabled in response to a user action such as a tap or click and cannot be enabled automatically.
2568
+ *
2569
+ * @remarks This will emit a 'device-orientation-update' event every time the device's orientation changes.
2570
+ * Device orientation changes will not emit a 'position-update' event.
2571
+ * @deprecated Use the {@link BlueDot.Sensors} API and fusion engine for heading updates instead.
2572
+ *
2573
+ * @see https://www.w3.org/TR/orientation-event/#dom-deviceorientationevent-requestpermission
2574
+ *
2575
+ * @param watch - Whether to enable or disable the listener.
2576
+ *
2577
+ * @example Enable device orientation listener
2578
+ * ```ts
2579
+ * const blueDot = new BlueDot(mapView);
2580
+ * // Enable device orientation on button click
2581
+ * button.addEventListener('click', () => {
2582
+ * blueDot.watchDeviceOrientation(true);
2583
+ * });
2584
+ * ```
2585
+ */
2586
+ watchDeviceOrientation: (watch: boolean) => Promise<void>;
2587
+ /**
2588
+ * Set the Blue Dot position to specific coordinates or override some properties of the device geolocation.
2589
+ *
2590
+ * @deprecated Use {@link forcePosition} to set an authoritative position that overrides all sensors,
2591
+ * or {@link reportPosition} to feed a confidence-weighted position into the fusion engine.
2592
+ *
2593
+ * @remarks If `floorLevel` is provided with {@link GeolocationPositionExtended}, the floor will be resolved asynchronously and the position will not be applied until this is completed.
2594
+ *
2595
+ * @param position - The position to set. Use {@link BlueDotPositionUpdate} for manual positioning,
2596
+ * a GeolocationPosition object, or undefined to clear the manual position.
2597
+ * @param options - Optional update options (silent, animate).
2598
+ *
2599
+ * @example Set position with floor
2600
+ * ```ts
2601
+ * blueDot.update({
2602
+ * latitude: 43.123,
2603
+ * longitude: -79.456,
2604
+ * accuracy: 5,
2605
+ * floorOrFloorId: floor
2606
+ * });
2607
+ * ```
2608
+ * @example Clear manual position properties and return to device geolocation
2609
+ * ```ts
2610
+ * blueDot.update(undefined);
2611
+ * ```
2612
+ */
2613
+ update: (position: GeolocationPositionExtended | BlueDotPositionUpdate | undefined, options?: BlueDotUpdateOptions) => void;
2614
+ /**
2615
+ * Set the camera to follow the BlueDot in various modes. User interaction will cancel following automatically.
2616
+ * @param mode The follow mode ('position-only', 'position-and-heading', 'position-and-path-direction', or false to disable).
2617
+ * @param cameraOptions Optional camera options (zoom, pitch, etc.).
2618
+ *
2619
+ * @example
2620
+ * mapView.BlueDot.follow('position-and-heading', { zoomLevel: 21, pitch: 45 });
2621
+ */
2622
+ follow: (mode: FollowMode, cameraOptions?: FollowCameraOptions) => void;
2623
+ /**
2624
+ * Set a position processor callback that allows intercepting and modifying device/geolocation position updates before they are applied.
2625
+ *
2626
+ * **Note**: This processor only applies to automatic position updates from device geolocation.
2627
+ * Manual position updates via `update()` method bypass the processor and are applied directly.
2628
+ *
2629
+ * @param processor - A callback function that receives current state and incoming update. Return undefined to discard the update, or return a modified update object.
2630
+ *
2631
+ * @example Discard inaccurate positions
2632
+ * ```ts
2633
+ * blueDot.setPositionProcessor((current, incoming) => {
2634
+ * if (incoming.accuracy && incoming.accuracy > 50) {
2635
+ * return undefined; // Discard update
2636
+ * }
2637
+ * return incoming; // Accept update
2638
+ * });
2639
+ * ```
2640
+ *
2641
+ * @example Modify incoming positions
2642
+ * ```ts
2643
+ * blueDot.setPositionProcessor((current, incoming) => {
2644
+ * // Apply custom smoothing or validation logic
2645
+ * return {
2646
+ * ...incoming,
2647
+ * accuracy: Math.min(incoming.accuracy || 100, 10) // Cap accuracy
2648
+ * };
2649
+ * });
2650
+ * ```
2651
+ */
2652
+ setPositionProcessor(processor?: BlueDotPositionProcessor): void;
2653
+ destroy: () => void;
2654
+ }
2655
+ //#endregion
2656
+ //#region src/debug/tuning-config.d.ts
2657
+ /**
2658
+ * Human-readable tuning knobs for indoor positioning.
2659
+ * These are debug-only settings that can be adjusted per-map/venue.
2660
+ */
2661
+ /**
2662
+ * DeviceOrientation (compass/heading) tuning options.
2663
+ * Controls how compass readings influence the displayed heading.
2664
+ */
2665
+ interface HeadingTuningConfig {
2666
+ /**
2667
+ * Controls how quickly compass readings influence heading.
2668
+ * Range: 0-100 (percentage)
2669
+ * - Higher values = respond faster to compass but may jitter
2670
+ * - Lower values = smoother heading but slower to correct
2671
+ * @default 30
2672
+ */
2673
+ headingResponsiveness: number;
2674
+ /**
2675
+ * Controls how aggressively to ignore noisy compass readings.
2676
+ * Range: 0-100 (percentage)
2677
+ * - Higher values = favor stability, ignore small movements
2678
+ * - Lower values = more reactive to subtle heading changes
2679
+ * @default 50
2680
+ */
2681
+ compassNoiseTolerance: number;
2682
+ /**
2683
+ * If compass differs by more than this threshold (degrees), snap immediately.
2684
+ * Range: 10-90 degrees
2685
+ * - Lower values = correct faster but may cause visible jumps
2686
+ * - Higher values = smoother blending but slower error correction
2687
+ * @default 30
2688
+ */
2689
+ headingSnapThreshold: number;
2690
+ /**
2691
+ * Enable magnetic disturbance detection.
2692
+ * When enabled, temporarily reduces compass influence during erratic readings.
2693
+ * @default true
2694
+ */
2695
+ magneticDisturbanceGating: boolean;
2696
+ /**
2697
+ * Minimum heading change (degrees) before emitting update.
2698
+ * Range: 1-10 degrees
2699
+ * - Higher values = reduce noise but feel less responsive
2700
+ * - Lower values = more updates but may jitter
2701
+ * @default 2
2702
+ */
2703
+ headingChangeThreshold: number;
2704
+ }
2705
+ /**
2706
+ * DeviceMotion (PDR/steps) tuning options.
2707
+ * Controls step detection and dead reckoning behavior.
2708
+ */
2709
+ interface MotionTuningConfig {
2710
+ /**
2711
+ * Controls how easily steps are detected.
2712
+ * Range: 0-100 (percentage)
2713
+ * - Higher values = detect more steps, may create false positives
2714
+ * - Lower values = only detect strong steps, may miss gentle walking
2715
+ * @default 50
2716
+ */
2717
+ stepSensitivity: number;
2718
+ /**
2719
+ * Average distance per step in meters.
2720
+ * Range: 0.4-1.2 meters
2721
+ * - Adjust based on user demographics (adults ~0.7m, shorter stride ~0.5m)
2722
+ * @default 0.7
2723
+ */
2724
+ averageStepLength: number;
2725
+ /**
2726
+ * Allow step length to vary with walking cadence.
2727
+ * Range: 0-100 (percentage)
2728
+ * - Higher values = adapt stride to walking speed (faster = longer steps)
2729
+ * - Lower values = fixed step length
2730
+ * @default 0
2731
+ */
2732
+ strideVariability: number;
2733
+ /**
2734
+ * Controls how quickly motion state changes between stationary/moving.
2735
+ * Range: 0-100 (percentage)
2736
+ * - Higher values = react faster to motion changes
2737
+ * - Lower values = require sustained motion before changing state
2738
+ * @default 50
2739
+ */
2740
+ motionResponsiveness: number;
2741
+ /**
2742
+ * Master toggle for step-based dead reckoning.
2743
+ * When disabled, PDR displacement is not calculated.
2744
+ * @default true
2745
+ */
2746
+ pdrEnabled: boolean;
2747
+ }
2748
+ /**
2749
+ * Complete tuning configuration for indoor positioning.
2750
+ */
2751
+ interface TuningConfig {
2752
+ heading: HeadingTuningConfig;
2753
+ motion: MotionTuningConfig;
2754
+ }
2755
+ /**
2756
+ * Default tuning configuration values.
2757
+ */
2758
+ declare const DEFAULT_TUNING_CONFIG: TuningConfig;
2759
+ /**
2760
+ * Convert human-readable heading config to internal filter parameters.
2761
+ */
2762
+ declare function headingConfigToFilterParams(config: HeadingTuningConfig): {
2763
+ complementaryAlpha: number;
2764
+ gyroNoiseThreshold: number;
2765
+ maxHeadingError: number;
2766
+ magneticGatingEnabled: boolean;
2767
+ deltaThreshold: number;
2768
+ };
2769
+ /**
2770
+ * Convert human-readable motion config to internal sensor parameters.
2771
+ */
2772
+ declare function motionConfigToSensorParams(config: MotionTuningConfig): {
2773
+ stepDetectionThreshold: number;
2774
+ stepLength: number;
2775
+ strideAdaptation: number;
2776
+ motionThreshold: number;
2777
+ pdrEnabled: boolean;
2778
+ };
2779
+ /**
2780
+ * Validate and normalize a tuning config, clamping values to valid ranges.
2781
+ */
2782
+ declare function normalizeTuningConfig(config: Partial<TuningConfig>): TuningConfig;
2783
+ //#endregion
2784
+ //#region src/debug/debug-hud.d.ts
2785
+ /**
2786
+ * Mobile-friendly debug HUD for BlueDot.
2787
+ * Shows a minimal collapsed bar at the bottom of the screen that expands to show full details.
2788
+ */
2789
+ declare class DebugHUD {
2790
+ #private;
2791
+ constructor(blueDot: BlueDot);
2792
+ /**
2793
+ * Clear all log entries from the console.
2794
+ */
2795
+ clearConsole(): void;
2796
+ /**
2797
+ * Get the current tuning configuration.
2798
+ */
2799
+ getTuningConfig(): TuningConfig;
2800
+ /**
2801
+ * Set the tuning configuration.
2802
+ */
2803
+ setTuningConfig(config: Partial<TuningConfig>): void;
2804
+ /**
2805
+ * Show the HUD (if hidden).
2806
+ */
2807
+ show(): void;
2808
+ /**
2809
+ * Hide the HUD.
2810
+ */
2811
+ hide(): void;
2812
+ /**
2813
+ * Whether the HUD is currently expanded (full-screen mode).
2814
+ */
2815
+ get isExpanded(): boolean;
2816
+ /**
2817
+ * Expand the HUD to full-screen mode.
2818
+ * Use this to programmatically show the detailed view.
2819
+ */
2820
+ expand(): void;
2821
+ /**
2822
+ * Collapse the HUD to the minimal bar.
2823
+ * Use this to programmatically hide the detailed view.
2824
+ */
2825
+ collapse(): void;
2826
+ /**
2827
+ * Toggle between expanded and collapsed states.
2828
+ * @returns The new expanded state (true = expanded, false = collapsed)
2829
+ */
2830
+ toggleExpanded(): boolean;
2831
+ /**
2832
+ * Clean up the HUD and remove it from the DOM.
2833
+ */
2834
+ destroy(): void;
2835
+ }
2836
+ //#endregion
2837
+ //#region src/debug/telemetry.d.ts
2838
+ /**
2839
+ * Debug telemetry for tracking sensor and fusion events.
2840
+ * Used internally by the debug panel to display real-time diagnostics.
2841
+ */
2842
+ /**
2843
+ * Telemetry event types.
2844
+ */
2845
+ interface TelemetryEvents {
2846
+ /** Compass update received */
2847
+ 'compass-update': {
2848
+ heading: number;
2849
+ timestamp: number;
2850
+ };
2851
+ /** Gyroscope update received */
2852
+ 'gyro-update': {
2853
+ angularVelocity: number;
2854
+ timestamp: number;
2855
+ };
2856
+ /** Step detected by PDR */
2857
+ 'step-detected': {
2858
+ stepLength: number;
2859
+ heading: number;
2860
+ timestamp: number;
2861
+ };
2862
+ /** Motion state changed */
2863
+ 'motion-state': {
2864
+ isMoving: boolean;
2865
+ timestamp: number;
2866
+ };
2867
+ /** Magnetic disturbance detected/cleared */
2868
+ 'magnetic-disturbance': {
2869
+ active: boolean;
2870
+ timestamp: number;
2871
+ };
2872
+ /** Heading fused */
2873
+ 'heading-fused': {
2874
+ heading: number;
2875
+ compassHeading: number | null;
2876
+ timestamp: number;
2877
+ };
2878
+ /** Position update */
2879
+ 'position-update': {
2880
+ latitude: number;
2881
+ longitude: number;
2882
+ accuracy: number;
2883
+ timestamp: number;
2884
+ };
2885
+ }
2886
+ type TelemetryEventName = keyof TelemetryEvents;
2887
+ type TelemetryCallback<T extends TelemetryEventName> = (data: TelemetryEvents[T]) => void;
2888
+ /**
2889
+ * Rolling statistics tracker for a numeric metric.
2890
+ */
2891
+ declare class MetricTracker {
2892
+ #private;
2893
+ constructor(maxSamples?: number);
2894
+ /**
2895
+ * Record a sample value.
2896
+ */
2897
+ record(value: number, timestamp?: number): void;
2898
+ /**
2899
+ * Get the rate of events per second over the sample window.
2900
+ */
2901
+ getRate(): number;
2902
+ /**
2903
+ * Get the average of recorded samples.
2904
+ */
2905
+ getAverage(): number;
2906
+ /**
2907
+ * Get the latest sample.
2908
+ */
2909
+ getLatest(): number | undefined;
2910
+ /**
2911
+ * Get the sample count.
2912
+ */
2913
+ getCount(): number;
2914
+ /**
2915
+ * Clear all samples.
2916
+ */
2917
+ clear(): void;
2918
+ }
2919
+ /**
2920
+ * Event counter for tracking event frequency.
2921
+ */
2922
+ declare class EventCounter {
2923
+ #private;
2924
+ constructor(windowMs?: number);
2925
+ /**
2926
+ * Record an event occurrence.
2927
+ */
2928
+ tick(timestamp?: number): void;
2929
+ /**
2930
+ * Get events per second in the window.
2931
+ */
2932
+ getRate(now?: number): number;
2933
+ /**
2934
+ * Get count of events in the window.
2935
+ */
2936
+ getCount(now?: number): number;
2937
+ /**
2938
+ * Clear all events.
2939
+ */
2940
+ clear(): void;
2941
+ }
2942
+ /**
2943
+ * Telemetry collector for BlueDot debug diagnostics.
2944
+ */
2945
+ declare class Telemetry {
2946
+ #private;
2947
+ /** Event counters */
2948
+ compassUpdates: EventCounter;
2949
+ gyroUpdates: EventCounter;
2950
+ stepsDetected: EventCounter;
2951
+ positionUpdates: EventCounter;
2952
+ /** Metric trackers */
2953
+ compassHeading: MetricTracker;
2954
+ gyroAngularVelocity: MetricTracker;
2955
+ stepLength: MetricTracker;
2956
+ positionAccuracy: MetricTracker;
2957
+ /** State flags */
2958
+ isMoving: boolean;
2959
+ magneticDisturbanceActive: boolean;
2960
+ lastFusedHeading: number | null;
2961
+ /**
2962
+ * Enable telemetry collection.
2963
+ */
2964
+ enable(): void;
2965
+ /**
2966
+ * Disable telemetry collection.
2967
+ */
2968
+ disable(): void;
2969
+ /**
2970
+ * Check if telemetry is enabled.
2971
+ */
2972
+ get isEnabled(): boolean;
2973
+ /**
2974
+ * Emit a telemetry event.
2975
+ */
2976
+ emit<T extends TelemetryEventName>(event: T, data: TelemetryEvents[T]): void;
2977
+ /**
2978
+ * Subscribe to a telemetry event.
2979
+ */
2980
+ on<T extends TelemetryEventName>(event: T, callback: TelemetryCallback<T>): () => void;
2981
+ /**
2982
+ * Get a summary of current telemetry state.
2983
+ */
2984
+ getSummary(): TelemetrySummary;
2985
+ /**
2986
+ * Clear all telemetry data.
2987
+ */
2988
+ clear(): void;
2989
+ /**
2990
+ * Destroy the telemetry instance.
2991
+ */
2992
+ destroy(): void;
2993
+ }
2994
+ /**
2995
+ * Telemetry summary for display.
2996
+ */
2997
+ interface TelemetrySummary {
2998
+ compassRate: number;
2999
+ gyroRate: number;
3000
+ stepRate: number;
3001
+ positionRate: number;
3002
+ avgCompassHeading: number;
3003
+ avgGyroVelocity: number;
3004
+ avgStepLength: number;
3005
+ avgAccuracy: number;
3006
+ isMoving: boolean;
3007
+ magneticDisturbanceActive: boolean;
3008
+ lastFusedHeading: number | null;
3009
+ }
3010
+ //#endregion
3011
+ //#region src/debug/index.d.ts
3012
+ /**
3013
+ * Enable the debug HUD overlay for a BlueDot instance.
3014
+ * Shows real-time sensor data, fusion state, and position information in a mobile-friendly overlay.
3015
+ *
3016
+ * The HUD appears as a small bar at the bottom of the screen that can be tapped to expand
3017
+ * and show full details including Position, Fusion state, and Sensor status.
3018
+ *
3019
+ * @param blueDot - The BlueDot instance to debug
3020
+ * @returns The DebugHUD instance. Call `.destroy()` to remove the HUD.
3021
+ *
3022
+ * @example
3023
+ * ```ts
3024
+ * import { BlueDot } from '@mappedin/blue-dot';
3025
+ * import { enableDebugHUD } from '@mappedin/blue-dot/debug';
3026
+ *
3027
+ * const blueDot = new BlueDot(mapView);
3028
+ * blueDot.enable();
3029
+ *
3030
+ * // Enable debug HUD
3031
+ * const debugHUD = enableDebugHUD(blueDot);
3032
+ *
3033
+ * // Later, to remove the HUD:
3034
+ * debugHUD.destroy();
3035
+ * ```
3036
+ */
3037
+ declare function enableDebugHUD(blueDot: BlueDot): DebugHUD;
3038
+ //#endregion
3039
+ export { DEFAULT_TUNING_CONFIG, type DebugHUD, EventCounter, type HeadingTuningConfig, MetricTracker, type MotionTuningConfig, Telemetry, type TelemetrySummary, type TuningConfig, enableDebugHUD, headingConfigToFilterParams, motionConfigToSensorParams, normalizeTuningConfig };