@tak-ps/cloudtak 13.24.0 → 13.25.2

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.
@@ -6,7 +6,7 @@ import type { MenuItemConfig } from './src/stores/modules/menu.ts';
6
6
  import type { BottomBarItemConfig } from './src/stores/modules/bottombar.ts';
7
7
  import { type DBFeature } from './src/database.ts';
8
8
  import { type Observable } from 'rxjs';
9
- import mapgl from 'maplibre-gl';
9
+ import * as mapgl from 'maplibre-gl';
10
10
  export type { MenuItemConfig };
11
11
  export type { BottomBarItemConfig };
12
12
  export type { DBFeature };
@@ -5,16 +5,16 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
5
5
  default: number;
6
6
  };
7
7
  }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
8
- click: (...args: any[]) => void;
9
8
  close: (...args: any[]) => void;
9
+ click: (...args: any[]) => void;
10
10
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
11
11
  size: {
12
12
  type: NumberConstructor;
13
13
  default: number;
14
14
  };
15
15
  }>> & Readonly<{
16
- onClick?: ((...args: any[]) => any) | undefined;
17
16
  onClose?: ((...args: any[]) => any) | undefined;
17
+ onClick?: ((...args: any[]) => any) | undefined;
18
18
  }>, {
19
19
  size: number;
20
20
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -220,3 +220,11 @@ export type DatabaseType = Dexie & {
220
220
  contact: EntityTable<Contact, 'uid'>;
221
221
  };
222
222
  export declare const db: DatabaseType;
223
+ export declare function ensureDatabase(): Promise<void>;
224
+ /**
225
+ * Returns true for the transient IndexedDB errors that occur when an iOS
226
+ * WebView is suspended in the background and later resumed. The middleware
227
+ * already retries these automatically; use this helper to suppress them
228
+ * in global error handlers so users are not shown stale error banners.
229
+ */
230
+ export declare function isTransientDbError(err: unknown): boolean;
@@ -0,0 +1,93 @@
1
+ import type { Map as MapLibreMap, IControl, ControlPosition } from 'maplibre-gl';
2
+ export type GeolocateControlOptions = {
3
+ /**
4
+ * Draw a translucent circle representing the reported GPS accuracy.
5
+ * @defaultValue `true`
6
+ */
7
+ showAccuracyCircle?: boolean;
8
+ /**
9
+ * Draw the user location puck.
10
+ * @defaultValue `true`
11
+ */
12
+ showUserLocation?: boolean;
13
+ /**
14
+ * Draw a heading cone on the puck driven by the device compass.
15
+ * @defaultValue `true`
16
+ */
17
+ showHeading?: boolean;
18
+ /**
19
+ * Invoked when the user clicks the puck.
20
+ */
21
+ onClick?: () => void;
22
+ };
23
+ /**
24
+ * A MapLibre {@link IControl} that renders a live user-location puck (dot,
25
+ * accuracy circle and compass heading cone).
26
+ *
27
+ * Unlike the stock MapLibre `GeolocateControl`, this control does not own a
28
+ * geolocation watch. Position, accuracy and heading are pushed in via
29
+ * {@link GeolocateControl.setLocation} and {@link GeolocateControl.setHeading}
30
+ * so the existing CloudTAK location pipeline (Capacitor Geolocation in the
31
+ * device store) remains the single source of truth. The control renders a
32
+ * non-interactive puck only; recentring the camera is handled elsewhere.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import GeolocateControl from './geolocate/main.ts';
37
+ *
38
+ * const control = new GeolocateControl();
39
+ * map.addControl(control, 'top-right');
40
+ * control.setLocation({ lng, lat }, accuracy);
41
+ * control.setHeading(headingDegrees);
42
+ * ```
43
+ */
44
+ export declare class GeolocateControl implements IControl {
45
+ private readonly options;
46
+ private map?;
47
+ private container?;
48
+ private puckElement?;
49
+ private dotElement?;
50
+ private headingElement?;
51
+ private circleElement?;
52
+ private dotMarker?;
53
+ private accuracyMarker?;
54
+ private lastLngLat;
55
+ private accuracy;
56
+ private heading;
57
+ private color;
58
+ constructor(options?: GeolocateControlOptions);
59
+ onAdd(map: MapLibreMap): HTMLElement;
60
+ onRemove(): void;
61
+ getDefaultPosition(): ControlPosition;
62
+ /**
63
+ * Update the puck position and accuracy. Pass `null` to remove the puck
64
+ * (e.g. when location reporting is disabled).
65
+ */
66
+ setLocation(position: {
67
+ lng: number;
68
+ lat: number;
69
+ } | null, accuracy?: number): void;
70
+ /**
71
+ * Update the compass heading (degrees clockwise from true north) used to
72
+ * orient the puck's heading cone. Pass `null` to hide the cone.
73
+ */
74
+ setHeading(heading: number | null): void;
75
+ /**
76
+ * Set the puck colour from a TAK team/group name (e.g. `"Cyan"`). Unknown or
77
+ * missing teams fall back to white, matching the rendered self CoT marker.
78
+ */
79
+ setTeam(team?: string): void;
80
+ /**
81
+ * Set the puck colour directly as a `#rrggbb` hex string.
82
+ */
83
+ setColor(color: string): void;
84
+ private setupMarkers;
85
+ private render;
86
+ private updateCircleRadius;
87
+ private updateHeadingRotation;
88
+ private onMapUpdate;
89
+ private applyColor;
90
+ private static rgba;
91
+ private static injectStyles;
92
+ }
93
+ export default GeolocateControl;
@@ -15,7 +15,9 @@ export declare const useAppStore: import("pinia").StoreDefinition<"cloudtak-app"
15
15
  persistSession(opts: {
16
16
  token: string;
17
17
  username: string;
18
+ session: string;
18
19
  }): Promise<void>;
20
+ getSessionId(): Promise<string | undefined>;
19
21
  getUsername(): Promise<string | undefined>;
20
22
  clearSession(): Promise<void>;
21
23
  destroySession(): Promise<void>;
@@ -1,15 +1,20 @@
1
1
  import type { DevicePermissionContext } from './types.ts';
2
- type DeviceOrientationEventName = 'deviceorientationabsolute' | 'deviceorientation';
3
2
  export declare class OrientationPermission {
4
3
  private readonly context;
5
4
  constructor(context: DevicePermissionContext);
6
5
  hasSupport(): boolean;
7
6
  hasPermissionRequest(): boolean;
8
- getEventName(): DeviceOrientationEventName;
9
- getHeading(event: DeviceOrientationEvent): number | null;
10
- addListener(listener: (event: DeviceOrientationEvent) => void): void;
11
- removeListener(listener: (event: DeviceOrientationEvent) => void): void;
7
+ /**
8
+ * Register a listener that fires with the compass heading (degrees clockwise
9
+ * from true/magnetic north, 0–360) whenever the device orientation changes.
10
+ * On native (iOS/Android) the @capgo/capacitor-compass plugin is used; on
11
+ * web the DeviceOrientationEvent fallback is used.
12
+ *
13
+ * Returns an async cleanup function — call it to stop listening.
14
+ */
15
+ addListener(callback: (heading: number | null) => void): Promise<() => Promise<void>>;
12
16
  refreshStatus(): Promise<void>;
13
17
  request(): Promise<void>;
18
+ private webGetEventName;
19
+ private webGetHeading;
14
20
  }
15
- export {};
@@ -39,10 +39,6 @@ export declare const useDeviceStore: import("pinia").StoreDefinition<"device", P
39
39
  initializePermissionSubscriptions: (onLocationGranted?: () => void) => Promise<void>;
40
40
  hasOrientationSupport: () => boolean;
41
41
  hasOrientationPermissionRequest: () => boolean;
42
- getOrientationEventName: () => "deviceorientationabsolute" | "deviceorientation";
43
- getOrientationHeading: (event: DeviceOrientationEvent) => number | null;
44
- addOrientationListener: (listener: (event: DeviceOrientationEvent) => void) => void;
45
- removeOrientationListener: (listener: (event: DeviceOrientationEvent) => void) => void;
46
42
  refreshLocationPermissionStatus: () => Promise<void>;
47
43
  refreshNotificationPermissionStatus: () => Promise<void>;
48
44
  getMessagingToken: () => string | null;
@@ -84,10 +80,6 @@ export declare const useDeviceStore: import("pinia").StoreDefinition<"device", P
84
80
  initializePermissionSubscriptions: (onLocationGranted?: () => void) => Promise<void>;
85
81
  hasOrientationSupport: () => boolean;
86
82
  hasOrientationPermissionRequest: () => boolean;
87
- getOrientationEventName: () => "deviceorientationabsolute" | "deviceorientation";
88
- getOrientationHeading: (event: DeviceOrientationEvent) => number | null;
89
- addOrientationListener: (listener: (event: DeviceOrientationEvent) => void) => void;
90
- removeOrientationListener: (listener: (event: DeviceOrientationEvent) => void) => void;
91
83
  refreshLocationPermissionStatus: () => Promise<void>;
92
84
  refreshNotificationPermissionStatus: () => Promise<void>;
93
85
  getMessagingToken: () => string | null;
@@ -129,10 +121,6 @@ export declare const useDeviceStore: import("pinia").StoreDefinition<"device", P
129
121
  initializePermissionSubscriptions: (onLocationGranted?: () => void) => Promise<void>;
130
122
  hasOrientationSupport: () => boolean;
131
123
  hasOrientationPermissionRequest: () => boolean;
132
- getOrientationEventName: () => "deviceorientationabsolute" | "deviceorientation";
133
- getOrientationHeading: (event: DeviceOrientationEvent) => number | null;
134
- addOrientationListener: (listener: (event: DeviceOrientationEvent) => void) => void;
135
- removeOrientationListener: (listener: (event: DeviceOrientationEvent) => void) => void;
136
124
  refreshLocationPermissionStatus: () => Promise<void>;
137
125
  refreshNotificationPermissionStatus: () => Promise<void>;
138
126
  getMessagingToken: () => string | null;
@@ -151,4 +139,4 @@ export declare const useDeviceStore: import("pinia").StoreDefinition<"device", P
151
139
  requestWakeLockPermission: () => Promise<void>;
152
140
  requestFileSystemPermission: () => Promise<void>;
153
141
  releaseWakeLockSentinel: () => Promise<void>;
154
- }, "setPermissionStatus" | "refreshPermissionStatuses" | "initializePermissionSubscriptions" | "hasOrientationSupport" | "hasOrientationPermissionRequest" | "getOrientationEventName" | "getOrientationHeading" | "addOrientationListener" | "removeOrientationListener" | "refreshLocationPermissionStatus" | "refreshNotificationPermissionStatus" | "getMessagingToken" | "refreshMessagingToken" | "onMessagingToken" | "refreshOrientationPermissionStatus" | "refreshStoragePermissionStatus" | "refreshCameraPermissionStatus" | "refreshWakeLockPermissionStatus" | "refreshFileSystemPermissionStatus" | "requestLocationPermission" | "requestNotificationPermission" | "requestOrientationPermission" | "requestStoragePermission" | "requestCameraPermission" | "requestWakeLockPermission" | "requestFileSystemPermission" | "releaseWakeLockSentinel">>;
142
+ }, "setPermissionStatus" | "refreshPermissionStatuses" | "initializePermissionSubscriptions" | "hasOrientationSupport" | "hasOrientationPermissionRequest" | "refreshLocationPermissionStatus" | "refreshNotificationPermissionStatus" | "getMessagingToken" | "refreshMessagingToken" | "onMessagingToken" | "refreshOrientationPermissionStatus" | "refreshStoragePermissionStatus" | "refreshCameraPermissionStatus" | "refreshWakeLockPermissionStatus" | "refreshFileSystemPermissionStatus" | "requestLocationPermission" | "requestNotificationPermission" | "requestOrientationPermission" | "requestStoragePermission" | "requestCameraPermission" | "requestWakeLockPermission" | "requestFileSystemPermission" | "releaseWakeLockSentinel">>;
@@ -24,7 +24,7 @@ export declare const useMapStore: import("pinia").StoreDefinition<"cloudtak", {
24
24
  _icons?: IconManager;
25
25
  _menu?: unknown;
26
26
  _bottomBar?: unknown;
27
- _boundOnDeviceOrientation?: (event: DeviceOrientationEvent) => void;
27
+ _removeOrientationListener?: () => Promise<void>;
28
28
  _boundOnVisibilityChange?: () => Promise<void>;
29
29
  _removeBackgroundStateListener?: () => void;
30
30
  _removePushTokenListener?: () => void;
@@ -89,6 +89,8 @@ export declare const useMapStore: import("pinia").StoreDefinition<"cloudtak", {
89
89
  worker: () => Comlink.Remote<Atlas>;
90
90
  }, {
91
91
  startLocationWatch: () => Promise<void>;
92
+ syncGeolocateControl: () => void;
93
+ openSelfFeature: () => Promise<void>;
92
94
  startWorker: () => void;
93
95
  destroy: () => Promise<void>;
94
96
  makeActiveMission: (mission?: Subscription) => Promise<void>;
@@ -62,6 +62,24 @@ export default class IconManager {
62
62
  * MapLibre. Falls back to a generic point icon when the icon isn't cached.
63
63
  */
64
64
  private loadIconsetImage;
65
+ /**
66
+ * Decode an iconset blob into an `ImageBitmap`.
67
+ *
68
+ * Raster formats (PNG/JPEG/...) decode directly via `createImageBitmap`.
69
+ * SVG blobs need special handling: `createImageBitmap` cannot decode
70
+ * `image/svg+xml` blobs in some browsers (notably Firefox, which rejects
71
+ * with a `DOMException`), so those are rasterized through an
72
+ * `HTMLImageElement` + `<canvas>` instead.
73
+ */
74
+ private decodeIconBlob;
75
+ /**
76
+ * Rasterize an SVG blob into an `ImageBitmap` via an `HTMLImageElement`
77
+ * drawn onto a `<canvas>`. Many iconset SVGs only declare a `viewBox` and
78
+ * no intrinsic `width`/`height`; without an explicit size browsers fall
79
+ * back to a 300x150 default, so the size is derived from the viewBox and
80
+ * set explicitly before rasterizing.
81
+ */
82
+ private decodeSvgBlob;
65
83
  private reloadIconsetImages;
66
84
  private reloadRequestedIconsetImage;
67
85
  private removeRequestedImagesForIconset;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tak-ps/cloudtak",
3
3
  "type": "module",
4
- "version": "13.24.0",
4
+ "version": "13.25.2",
5
5
  "types": "dist/types/plugin.d.ts",
6
6
  "files": [
7
7
  "dist/types"
@@ -43,6 +43,7 @@
43
43
  "@capacitor/preferences": "^8.0.1",
44
44
  "@capacitor/status-bar": "^8.0.2",
45
45
  "@capgo/background-geolocation": "^8.0.39",
46
+ "@capgo/capacitor-compass": "^8.1.17",
46
47
  "@mapbox/tile-cover": "^3.0.2",
47
48
  "@simplewebauthn/browser": "^13.3.0",
48
49
  "@tabler/core": "^1.4.0",
@@ -81,7 +82,7 @@
81
82
  "hls.js": "^1.6.5",
82
83
  "imask": "^6.0.0",
83
84
  "jsonata": "^2.0.4",
84
- "maplibre-gl": "5.24.0",
85
+ "maplibre-gl": "v6.0.0-17",
85
86
  "milsymbol": "^3.0.2",
86
87
  "openapi-fetch": "^0.17.0",
87
88
  "phone": "^3.1.59",
@@ -96,6 +97,7 @@
96
97
  "uuid": "^14.0.0",
97
98
  "vue": "^3.2.31",
98
99
  "vue-component-type-helpers": "^3.0.7",
100
+ "vue-eslint-parser": "^10.4.1",
99
101
  "vue-mention": "^2.0.0-alpha.3",
100
102
  "vue-router": "^5.0.0",
101
103
  "yaml": "^2.8.2"