@auxilium/datalynk-client 1.3.22 → 1.4.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.
- package/dist/api.d.ts +5 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/gps.d.ts +124 -0
- package/dist/gps.d.ts.map +1 -0
- package/dist/index.cjs +359 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +359 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { ApiCall, Slice } from './slice';
|
|
|
9
9
|
import { Socket } from './socket';
|
|
10
10
|
import { Superuser } from './superuser';
|
|
11
11
|
import { WebRtc } from './webrtc';
|
|
12
|
+
import { Gps, GpsOptions } from './gps';
|
|
12
13
|
export type JwtPayload = {
|
|
13
14
|
aud: string;
|
|
14
15
|
email: string;
|
|
@@ -45,6 +46,8 @@ export type ApiOptions = {
|
|
|
45
46
|
serviceWorker?: string;
|
|
46
47
|
/** Disable sockets with false or override socket URL */
|
|
47
48
|
socket?: false | string;
|
|
49
|
+
/** GPS live tracking over socket-server/Redis */
|
|
50
|
+
gps?: GpsOptions;
|
|
48
51
|
/** WebRTC TURN server URL */
|
|
49
52
|
webrtc?: {
|
|
50
53
|
/** Additional ICE servers */
|
|
@@ -122,6 +125,8 @@ export declare class Api {
|
|
|
122
125
|
readonly pwa: PWA;
|
|
123
126
|
/** Socket */
|
|
124
127
|
readonly socket: Socket;
|
|
128
|
+
/** GPS */
|
|
129
|
+
readonly gps: Gps;
|
|
125
130
|
/** Superuser */
|
|
126
131
|
readonly superuser: Superuser;
|
|
127
132
|
/** WebRTC */
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoD,QAAQ,EAAQ,MAAM,gBAAgB,CAAC;AAClG,OAAO,EAAC,eAAe,EAAuB,MAAM,MAAM,CAAC;AAC3D,OAAO,EAAC,IAAI,EAAC,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAC,IAAI,EAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,MAAM,SAAS,CAAC;AACvC,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAC;AAChC,OAAO,EAAC,SAAS,EAAC,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAC,MAAM,EAAC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/gps.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Api } from './api';
|
|
2
|
+
import { Unsubscribe } from './socket';
|
|
3
|
+
/** GPS connection options */
|
|
4
|
+
export type GpsOptions = false | {
|
|
5
|
+
/**
|
|
6
|
+
* Start browser GPS automatically after a token is available.
|
|
7
|
+
* Set false when an app already owns GPS collection and only wants api.gps.send(...).
|
|
8
|
+
*/
|
|
9
|
+
autoStart?: boolean;
|
|
10
|
+
/** Dedicated GPS socket URL override. Defaults to the standard socket-server URL */
|
|
11
|
+
socketUrl?: string;
|
|
12
|
+
/** Slice used by socket-server GPS storage */
|
|
13
|
+
slice: number | string;
|
|
14
|
+
/** Field key used by socket-server GPS storage. Default is coords */
|
|
15
|
+
field?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Stable tracking ID for the object/person/vehicle being tracked.
|
|
18
|
+
*
|
|
19
|
+
* If omitted, datalynk-client generates a unique tracker ID for this Gps
|
|
20
|
+
* instance. The default tracking ID is intentionally not based on sessionId,
|
|
21
|
+
* because one logged-in session/device may start more than one active tracker.
|
|
22
|
+
*/
|
|
23
|
+
trackingId?: string;
|
|
24
|
+
/** Stable device ID. Default is stored in localStorage */
|
|
25
|
+
deviceId?: string;
|
|
26
|
+
/** Human-readable label passed through to listeners */
|
|
27
|
+
label?: string;
|
|
28
|
+
/** Source/app label passed through to listeners */
|
|
29
|
+
source?: string;
|
|
30
|
+
/** Send a heartbeat even when the GPS position has not changed. Default is 5000 */
|
|
31
|
+
heartbeatMs?: number;
|
|
32
|
+
/** Minimum movement before sending a non-heartbeat update. Default is 3 */
|
|
33
|
+
minDistanceMeters?: number;
|
|
34
|
+
/** Do not send non-heartbeat positions worse than this accuracy. Default is 200 */
|
|
35
|
+
maxAccuracyMeters?: number;
|
|
36
|
+
/** Use browser high-accuracy GPS. Default is true */
|
|
37
|
+
highAccuracy?: boolean;
|
|
38
|
+
/** Browser geolocation timeout. Default is 10000 */
|
|
39
|
+
timeoutMs?: number;
|
|
40
|
+
/** Reject GPS fixes older than this. Default is 4000 */
|
|
41
|
+
maxStaleMs?: number;
|
|
42
|
+
/** Restart watchPosition if no fresh fix arrives. Default is 60000 */
|
|
43
|
+
watchdogMs?: number;
|
|
44
|
+
};
|
|
45
|
+
export type GpsPositionPayload = {
|
|
46
|
+
lat: number;
|
|
47
|
+
lng: number;
|
|
48
|
+
accuracy: number | null;
|
|
49
|
+
altitude: number | null;
|
|
50
|
+
altitudeAccuracy: number | null;
|
|
51
|
+
heading: number | null;
|
|
52
|
+
speed: number | null;
|
|
53
|
+
timestamp: string;
|
|
54
|
+
timestampMs: number;
|
|
55
|
+
};
|
|
56
|
+
export type GpsManualPositionPayload = Omit<Partial<GpsPositionPayload>, 'lat' | 'lng' | 'timestampMs'> & {
|
|
57
|
+
lat?: number | string;
|
|
58
|
+
lng?: number | string;
|
|
59
|
+
lon?: number | string;
|
|
60
|
+
latitude?: number | string;
|
|
61
|
+
longitude?: number | string;
|
|
62
|
+
timestampMs?: number | string;
|
|
63
|
+
};
|
|
64
|
+
export type GpsListenOptions = {
|
|
65
|
+
slice?: number | string;
|
|
66
|
+
field?: string;
|
|
67
|
+
includeTrails?: boolean;
|
|
68
|
+
trailLimit?: number;
|
|
69
|
+
};
|
|
70
|
+
export type GpsListener = (event: any) => any;
|
|
71
|
+
/** Browser/manual GPS sender backed by socket-server Redis GPS storage */
|
|
72
|
+
export declare class Gps {
|
|
73
|
+
private readonly api;
|
|
74
|
+
private deviceId;
|
|
75
|
+
private heartbeat?;
|
|
76
|
+
private lastFixAt;
|
|
77
|
+
private lastPosition?;
|
|
78
|
+
private lastSentAt;
|
|
79
|
+
private lastSentPosition?;
|
|
80
|
+
private pendingPayloads;
|
|
81
|
+
private retryWatchdog?;
|
|
82
|
+
private seq;
|
|
83
|
+
private sessionId;
|
|
84
|
+
private socket?;
|
|
85
|
+
private trackerId;
|
|
86
|
+
private started;
|
|
87
|
+
private unsubs;
|
|
88
|
+
private watchId?;
|
|
89
|
+
private watchStartedAt;
|
|
90
|
+
readonly options?: Exclude<GpsOptions, false>;
|
|
91
|
+
constructor(api: Api, options?: GpsOptions);
|
|
92
|
+
/** Start sharing browser GPS to socket-server */
|
|
93
|
+
start(): void;
|
|
94
|
+
/** Stop sharing GPS and close the dedicated GPS socket */
|
|
95
|
+
stop(): void;
|
|
96
|
+
/** Send a raw GPS message. Useful when an app already has its own GPS engine */
|
|
97
|
+
send(position: GpsManualPositionPayload, extra?: any): void;
|
|
98
|
+
/** Listen to GPS updates for the configured slice/field */
|
|
99
|
+
listen(callback: GpsListener, options?: GpsListenOptions): Unsubscribe;
|
|
100
|
+
private bindResumeEvents;
|
|
101
|
+
private connectSocket;
|
|
102
|
+
private createId;
|
|
103
|
+
private flushPendingPayloads;
|
|
104
|
+
private getClientDetails;
|
|
105
|
+
private getOrCreateDeviceId;
|
|
106
|
+
private getTrackingId;
|
|
107
|
+
private isFresh;
|
|
108
|
+
private metersBetween;
|
|
109
|
+
private normalizeNullableNumber;
|
|
110
|
+
private normalizeOptionalNumber;
|
|
111
|
+
private normalizePosition;
|
|
112
|
+
private onPosition;
|
|
113
|
+
private onPositionError;
|
|
114
|
+
private restartWatch;
|
|
115
|
+
private sendPayload;
|
|
116
|
+
private sendPosition;
|
|
117
|
+
private serializePosition;
|
|
118
|
+
private shouldSendPosition;
|
|
119
|
+
private startHeartbeat;
|
|
120
|
+
private startWatch;
|
|
121
|
+
private startWatchdog;
|
|
122
|
+
private startWhenAuthenticated;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=gps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gps.d.ts","sourceRoot":"","sources":["../src/gps.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -3774,7 +3774,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3774
3774
|
} });
|
|
3775
3775
|
}
|
|
3776
3776
|
}
|
|
3777
|
-
const version = "1.
|
|
3777
|
+
const version = "1.4.0";
|
|
3778
3778
|
class WebRtc {
|
|
3779
3779
|
constructor(api) {
|
|
3780
3780
|
__publicField(this, "ice");
|
|
@@ -3895,6 +3895,360 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3895
3895
|
return session;
|
|
3896
3896
|
}
|
|
3897
3897
|
}
|
|
3898
|
+
class Gps {
|
|
3899
|
+
constructor(api, options) {
|
|
3900
|
+
__publicField(this, "deviceId");
|
|
3901
|
+
__publicField(this, "heartbeat");
|
|
3902
|
+
__publicField(this, "lastFixAt", 0);
|
|
3903
|
+
__publicField(this, "lastPosition");
|
|
3904
|
+
__publicField(this, "lastSentAt", 0);
|
|
3905
|
+
__publicField(this, "lastSentPosition");
|
|
3906
|
+
__publicField(this, "pendingPayloads", []);
|
|
3907
|
+
__publicField(this, "retryWatchdog");
|
|
3908
|
+
__publicField(this, "seq", 0);
|
|
3909
|
+
__publicField(this, "sessionId");
|
|
3910
|
+
__publicField(this, "socket");
|
|
3911
|
+
__publicField(this, "trackerId");
|
|
3912
|
+
__publicField(this, "started", false);
|
|
3913
|
+
__publicField(this, "unsubs", []);
|
|
3914
|
+
__publicField(this, "watchId");
|
|
3915
|
+
__publicField(this, "watchStartedAt", 0);
|
|
3916
|
+
__publicField(this, "options");
|
|
3917
|
+
__publicField(this, "onPosition", (position) => {
|
|
3918
|
+
if (!this.options) return;
|
|
3919
|
+
if (!this.isFresh(position)) return;
|
|
3920
|
+
this.lastFixAt = Date.now();
|
|
3921
|
+
this.lastPosition = position;
|
|
3922
|
+
if (this.shouldSendPosition(position, false)) this.sendPosition(position, false);
|
|
3923
|
+
});
|
|
3924
|
+
__publicField(this, "onPositionError", (error) => {
|
|
3925
|
+
console.warn("Datalynk GPS error:", error.message);
|
|
3926
|
+
});
|
|
3927
|
+
this.api = api;
|
|
3928
|
+
if (options === false || options == null) return;
|
|
3929
|
+
this.options = {
|
|
3930
|
+
autoStart: true,
|
|
3931
|
+
field: "coords",
|
|
3932
|
+
heartbeatMs: 5e3,
|
|
3933
|
+
minDistanceMeters: 3,
|
|
3934
|
+
maxAccuracyMeters: 200,
|
|
3935
|
+
highAccuracy: true,
|
|
3936
|
+
timeoutMs: 1e4,
|
|
3937
|
+
maxStaleMs: 4e3,
|
|
3938
|
+
watchdogMs: 6e4,
|
|
3939
|
+
...options
|
|
3940
|
+
};
|
|
3941
|
+
this.deviceId = this.options.deviceId || this.getOrCreateDeviceId();
|
|
3942
|
+
this.sessionId = this.createId();
|
|
3943
|
+
this.trackerId = this.options.trackingId || this.createId();
|
|
3944
|
+
if (this.options.autoStart !== false) this.startWhenAuthenticated();
|
|
3945
|
+
}
|
|
3946
|
+
/** Start sharing browser GPS to socket-server */
|
|
3947
|
+
start() {
|
|
3948
|
+
if (!this.options) throw new Error("Datalynk GPS is not configured");
|
|
3949
|
+
if (this.started) return;
|
|
3950
|
+
if (!this.api.token) throw new Error("Datalynk GPS cannot start before login");
|
|
3951
|
+
if (typeof navigator == "undefined" || !navigator.geolocation) throw new Error("Browser geolocation is not available");
|
|
3952
|
+
this.started = true;
|
|
3953
|
+
this.connectSocket();
|
|
3954
|
+
this.startWatch();
|
|
3955
|
+
this.startHeartbeat();
|
|
3956
|
+
this.startWatchdog();
|
|
3957
|
+
this.bindResumeEvents();
|
|
3958
|
+
}
|
|
3959
|
+
/** Stop sharing GPS and close the dedicated GPS socket */
|
|
3960
|
+
stop() {
|
|
3961
|
+
var _a;
|
|
3962
|
+
this.started = false;
|
|
3963
|
+
if (this.watchId != null && typeof navigator != "undefined") navigator.geolocation.clearWatch(this.watchId);
|
|
3964
|
+
this.watchId = void 0;
|
|
3965
|
+
if (this.heartbeat) clearInterval(this.heartbeat);
|
|
3966
|
+
this.heartbeat = void 0;
|
|
3967
|
+
if (this.retryWatchdog) clearInterval(this.retryWatchdog);
|
|
3968
|
+
this.retryWatchdog = void 0;
|
|
3969
|
+
this.unsubs.forEach((unsub) => unsub());
|
|
3970
|
+
this.unsubs = [];
|
|
3971
|
+
this.pendingPayloads = [];
|
|
3972
|
+
(_a = this.socket) == null ? void 0 : _a.close();
|
|
3973
|
+
this.socket = void 0;
|
|
3974
|
+
}
|
|
3975
|
+
/** Send a raw GPS message. Useful when an app already has its own GPS engine */
|
|
3976
|
+
send(position, extra = {}) {
|
|
3977
|
+
if (!this.options) throw new Error("Datalynk GPS is not configured");
|
|
3978
|
+
if (!this.api.token) throw new Error("Datalynk GPS cannot send before login");
|
|
3979
|
+
this.connectSocket();
|
|
3980
|
+
this.sendPayload({
|
|
3981
|
+
...extra,
|
|
3982
|
+
position: this.normalizePosition(position)
|
|
3983
|
+
});
|
|
3984
|
+
}
|
|
3985
|
+
/** Listen to GPS updates for the configured slice/field */
|
|
3986
|
+
listen(callback, options = {}) {
|
|
3987
|
+
if (!this.options) throw new Error("Datalynk GPS is not configured");
|
|
3988
|
+
if (!this.api.token) throw new Error("Datalynk GPS cannot listen before login");
|
|
3989
|
+
this.connectSocket();
|
|
3990
|
+
const request = {
|
|
3991
|
+
gpsListen: {
|
|
3992
|
+
slice: options.slice || this.options.slice,
|
|
3993
|
+
field: options.field || this.options.field || "coords",
|
|
3994
|
+
includeTrails: options.includeTrails ?? false,
|
|
3995
|
+
trailLimit: options.trailLimit ?? 0
|
|
3996
|
+
}
|
|
3997
|
+
};
|
|
3998
|
+
return this.socket.addListener((event) => {
|
|
3999
|
+
var _a, _b;
|
|
4000
|
+
const payload = event;
|
|
4001
|
+
const gps = ((_a = payload == null ? void 0 : payload.data) == null ? void 0 : _a.gps) || (payload == null ? void 0 : payload.gps);
|
|
4002
|
+
if ((payload == null ? void 0 : payload.type) == "sliceEvents" && ((_b = payload == null ? void 0 : payload.data) == null ? void 0 : _b.type) == "gps.position" && gps) callback(gps);
|
|
4003
|
+
else if ((payload == null ? void 0 : payload.type) == "gps.position" && gps) callback(gps);
|
|
4004
|
+
else if ((payload == null ? void 0 : payload.type) == "gpsListen" || (payload == null ? void 0 : payload.gpsListen)) callback(payload);
|
|
4005
|
+
}, () => this.socket.send(request));
|
|
4006
|
+
}
|
|
4007
|
+
bindResumeEvents() {
|
|
4008
|
+
if (typeof window == "undefined" || typeof document == "undefined") return;
|
|
4009
|
+
const restart = () => {
|
|
4010
|
+
if (!this.started) return;
|
|
4011
|
+
if (document.visibilityState && document.visibilityState !== "visible") return;
|
|
4012
|
+
this.restartWatch();
|
|
4013
|
+
};
|
|
4014
|
+
window.addEventListener("focus", restart);
|
|
4015
|
+
window.addEventListener("pageshow", restart);
|
|
4016
|
+
document.addEventListener("visibilitychange", restart);
|
|
4017
|
+
this.unsubs.push(() => {
|
|
4018
|
+
window.removeEventListener("focus", restart);
|
|
4019
|
+
window.removeEventListener("pageshow", restart);
|
|
4020
|
+
document.removeEventListener("visibilitychange", restart);
|
|
4021
|
+
});
|
|
4022
|
+
}
|
|
4023
|
+
connectSocket() {
|
|
4024
|
+
if (!this.options || this.socket) return;
|
|
4025
|
+
if (!this.api.token) throw new Error("Datalynk GPS socket cannot connect before login");
|
|
4026
|
+
this.socket = new Socket(this.api, { url: this.options.socketUrl });
|
|
4027
|
+
this.unsubs.push(this.socket.addListener(() => {
|
|
4028
|
+
}, () => this.flushPendingPayloads()));
|
|
4029
|
+
}
|
|
4030
|
+
createId() {
|
|
4031
|
+
if (typeof crypto != "undefined" && crypto.randomUUID) return crypto.randomUUID();
|
|
4032
|
+
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
4033
|
+
}
|
|
4034
|
+
flushPendingPayloads() {
|
|
4035
|
+
var _a;
|
|
4036
|
+
if (!((_a = this.socket) == null ? void 0 : _a.open)) return;
|
|
4037
|
+
while (this.pendingPayloads.length) {
|
|
4038
|
+
this.socket.send(this.pendingPayloads.shift());
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
getClientDetails() {
|
|
4042
|
+
if (typeof navigator == "undefined") return {};
|
|
4043
|
+
return {
|
|
4044
|
+
userAgent: navigator.userAgent,
|
|
4045
|
+
language: navigator.language,
|
|
4046
|
+
platform: navigator.platform,
|
|
4047
|
+
vendor: navigator.vendor,
|
|
4048
|
+
screen: typeof screen == "undefined" ? void 0 : {
|
|
4049
|
+
width: screen.width,
|
|
4050
|
+
height: screen.height,
|
|
4051
|
+
pixelRatio: typeof devicePixelRatio == "undefined" ? void 0 : devicePixelRatio
|
|
4052
|
+
},
|
|
4053
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
4054
|
+
};
|
|
4055
|
+
}
|
|
4056
|
+
getOrCreateDeviceId() {
|
|
4057
|
+
const key = "datalynk-gps-device-id";
|
|
4058
|
+
if (typeof localStorage != "undefined") {
|
|
4059
|
+
const existing = localStorage.getItem(key);
|
|
4060
|
+
if (existing) return existing;
|
|
4061
|
+
const id = this.createId();
|
|
4062
|
+
localStorage.setItem(key, id);
|
|
4063
|
+
return id;
|
|
4064
|
+
}
|
|
4065
|
+
return this.createId();
|
|
4066
|
+
}
|
|
4067
|
+
getTrackingId() {
|
|
4068
|
+
var _a;
|
|
4069
|
+
if (!this.options) return this.trackerId || this.createId();
|
|
4070
|
+
if (this.options.trackingId) return this.options.trackingId;
|
|
4071
|
+
const uid = (_a = this.api.jwtPayload) == null ? void 0 : _a.uid;
|
|
4072
|
+
return uid ? `user:${uid}:tracker:${this.trackerId}` : `device:${this.deviceId}:tracker:${this.trackerId}`;
|
|
4073
|
+
}
|
|
4074
|
+
isFresh(position) {
|
|
4075
|
+
if (!this.options) return false;
|
|
4076
|
+
if (this.lastPosition && position.timestamp <= this.lastPosition.timestamp) return false;
|
|
4077
|
+
return Date.now() - position.timestamp <= (this.options.maxStaleMs || 4e3);
|
|
4078
|
+
}
|
|
4079
|
+
metersBetween(a, b) {
|
|
4080
|
+
const earthRadius = 6371e3;
|
|
4081
|
+
const lat1 = a.coords.latitude * Math.PI / 180;
|
|
4082
|
+
const lat2 = b.coords.latitude * Math.PI / 180;
|
|
4083
|
+
const dLat = (b.coords.latitude - a.coords.latitude) * Math.PI / 180;
|
|
4084
|
+
const dLng = (b.coords.longitude - a.coords.longitude) * Math.PI / 180;
|
|
4085
|
+
const x = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
|
|
4086
|
+
return earthRadius * 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));
|
|
4087
|
+
}
|
|
4088
|
+
normalizeNullableNumber(value, field) {
|
|
4089
|
+
if (value == null || value === "") return null;
|
|
4090
|
+
const number = Number(value);
|
|
4091
|
+
if (!Number.isFinite(number)) throw new Error(`GPS ${field} must be a valid number`);
|
|
4092
|
+
return number;
|
|
4093
|
+
}
|
|
4094
|
+
normalizeOptionalNumber(value, field) {
|
|
4095
|
+
if (value == null || value === "") return void 0;
|
|
4096
|
+
const number = Number(value);
|
|
4097
|
+
if (!Number.isFinite(number)) throw new Error(`GPS ${field} must be a valid number`);
|
|
4098
|
+
return number;
|
|
4099
|
+
}
|
|
4100
|
+
normalizePosition(position) {
|
|
4101
|
+
const lat = Number(position.lat ?? position.latitude);
|
|
4102
|
+
const lng = Number(position.lng ?? position.lon ?? position.longitude);
|
|
4103
|
+
if (!Number.isFinite(lat) || lat < -90 || lat > 90) {
|
|
4104
|
+
throw new Error("GPS position must include a valid lat/latitude between -90 and 90");
|
|
4105
|
+
}
|
|
4106
|
+
if (!Number.isFinite(lng) || lng < -180 || lng > 180) {
|
|
4107
|
+
throw new Error("GPS position must include a valid lng/lon/longitude between -180 and 180");
|
|
4108
|
+
}
|
|
4109
|
+
const accuracy = this.normalizeNullableNumber(position.accuracy, "accuracy");
|
|
4110
|
+
if (accuracy != null && accuracy < 0) throw new Error("GPS accuracy must be zero or greater");
|
|
4111
|
+
const altitude = this.normalizeNullableNumber(position.altitude, "altitude");
|
|
4112
|
+
const altitudeAccuracy = this.normalizeNullableNumber(position.altitudeAccuracy, "altitudeAccuracy");
|
|
4113
|
+
if (altitudeAccuracy != null && altitudeAccuracy < 0) throw new Error("GPS altitudeAccuracy must be zero or greater");
|
|
4114
|
+
const heading = this.normalizeNullableNumber(position.heading, "heading");
|
|
4115
|
+
if (heading != null && (heading < 0 || heading >= 360)) throw new Error("GPS heading must be between 0 and 360");
|
|
4116
|
+
const speed = this.normalizeNullableNumber(position.speed, "speed");
|
|
4117
|
+
if (speed != null && speed < 0) throw new Error("GPS speed must be zero or greater");
|
|
4118
|
+
const timestampMs = this.normalizeOptionalNumber(position.timestampMs, "timestampMs") ?? Date.now();
|
|
4119
|
+
if (timestampMs <= 0) throw new Error("GPS timestampMs must be greater than zero");
|
|
4120
|
+
let timestamp = position.timestamp;
|
|
4121
|
+
if (timestamp) {
|
|
4122
|
+
const parsed = Date.parse(timestamp);
|
|
4123
|
+
if (!Number.isFinite(parsed)) throw new Error("GPS timestamp must be a valid date string");
|
|
4124
|
+
} else {
|
|
4125
|
+
timestamp = new Date(timestampMs).toISOString();
|
|
4126
|
+
}
|
|
4127
|
+
return {
|
|
4128
|
+
lat,
|
|
4129
|
+
lng,
|
|
4130
|
+
accuracy,
|
|
4131
|
+
altitude,
|
|
4132
|
+
altitudeAccuracy,
|
|
4133
|
+
heading,
|
|
4134
|
+
speed,
|
|
4135
|
+
timestamp,
|
|
4136
|
+
timestampMs
|
|
4137
|
+
};
|
|
4138
|
+
}
|
|
4139
|
+
restartWatch() {
|
|
4140
|
+
if (!this.options || !this.started || typeof navigator == "undefined" || !navigator.geolocation) return;
|
|
4141
|
+
if (this.watchId != null) navigator.geolocation.clearWatch(this.watchId);
|
|
4142
|
+
this.watchId = void 0;
|
|
4143
|
+
this.startWatch();
|
|
4144
|
+
}
|
|
4145
|
+
sendPayload(payload) {
|
|
4146
|
+
var _a, _b;
|
|
4147
|
+
if (!this.options) return;
|
|
4148
|
+
this.connectSocket();
|
|
4149
|
+
const message = {
|
|
4150
|
+
gps: {
|
|
4151
|
+
slice: this.options.slice,
|
|
4152
|
+
field: this.options.field || "coords",
|
|
4153
|
+
trackingId: this.getTrackingId(),
|
|
4154
|
+
trackerId: this.trackerId,
|
|
4155
|
+
sessionId: this.sessionId,
|
|
4156
|
+
deviceId: this.deviceId,
|
|
4157
|
+
seq: ++this.seq,
|
|
4158
|
+
client: this.getClientDetails(),
|
|
4159
|
+
sentAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4160
|
+
gpsTimestamp: ((_a = payload.position) == null ? void 0 : _a.timestamp) || null,
|
|
4161
|
+
label: this.options.label,
|
|
4162
|
+
source: this.options.source,
|
|
4163
|
+
...payload
|
|
4164
|
+
}
|
|
4165
|
+
};
|
|
4166
|
+
if (!((_b = this.socket) == null ? void 0 : _b.open)) {
|
|
4167
|
+
this.pendingPayloads.push(message);
|
|
4168
|
+
this.pendingPayloads = this.pendingPayloads.slice(-25);
|
|
4169
|
+
return;
|
|
4170
|
+
}
|
|
4171
|
+
this.socket.send(message);
|
|
4172
|
+
}
|
|
4173
|
+
sendPosition(position, force) {
|
|
4174
|
+
this.sendPayload({
|
|
4175
|
+
force,
|
|
4176
|
+
position: this.serializePosition(position)
|
|
4177
|
+
});
|
|
4178
|
+
this.lastSentPosition = position;
|
|
4179
|
+
this.lastSentAt = Date.now();
|
|
4180
|
+
}
|
|
4181
|
+
serializePosition(position) {
|
|
4182
|
+
return {
|
|
4183
|
+
lat: position.coords.latitude,
|
|
4184
|
+
lng: position.coords.longitude,
|
|
4185
|
+
accuracy: position.coords.accuracy,
|
|
4186
|
+
altitude: position.coords.altitude,
|
|
4187
|
+
altitudeAccuracy: position.coords.altitudeAccuracy,
|
|
4188
|
+
heading: position.coords.heading,
|
|
4189
|
+
speed: position.coords.speed,
|
|
4190
|
+
timestamp: new Date(position.timestamp).toISOString(),
|
|
4191
|
+
timestampMs: position.timestamp
|
|
4192
|
+
};
|
|
4193
|
+
}
|
|
4194
|
+
shouldSendPosition(position, force) {
|
|
4195
|
+
if (!this.options) return false;
|
|
4196
|
+
if (force) return true;
|
|
4197
|
+
const accuracy = Number(position.coords.accuracy || 0);
|
|
4198
|
+
if (accuracy && accuracy > (this.options.maxAccuracyMeters || 200)) return false;
|
|
4199
|
+
if (!this.lastSentPosition) return true;
|
|
4200
|
+
const movedMeters = this.metersBetween(this.lastSentPosition, position);
|
|
4201
|
+
const accuracyImproved = Number(position.coords.accuracy || 999999) < Number(this.lastSentPosition.coords.accuracy || 999999);
|
|
4202
|
+
const heartbeatDue = Date.now() - this.lastSentAt >= (this.options.heartbeatMs || 5e3);
|
|
4203
|
+
return movedMeters >= (this.options.minDistanceMeters || 3) || accuracyImproved || heartbeatDue;
|
|
4204
|
+
}
|
|
4205
|
+
startHeartbeat() {
|
|
4206
|
+
if (!this.options || this.heartbeat) return;
|
|
4207
|
+
this.heartbeat = setInterval(() => {
|
|
4208
|
+
if (!this.started || !this.lastPosition) return;
|
|
4209
|
+
this.sendPosition(this.lastPosition, true);
|
|
4210
|
+
}, this.options.heartbeatMs || 5e3);
|
|
4211
|
+
}
|
|
4212
|
+
startWatch() {
|
|
4213
|
+
if (!this.options || this.watchId != null) return;
|
|
4214
|
+
this.watchStartedAt = Date.now();
|
|
4215
|
+
this.watchId = navigator.geolocation.watchPosition(this.onPosition, this.onPositionError, {
|
|
4216
|
+
enableHighAccuracy: this.options.highAccuracy !== false,
|
|
4217
|
+
maximumAge: 0,
|
|
4218
|
+
timeout: this.options.timeoutMs || 1e4
|
|
4219
|
+
});
|
|
4220
|
+
}
|
|
4221
|
+
startWatchdog() {
|
|
4222
|
+
if (!this.options || this.retryWatchdog) return;
|
|
4223
|
+
this.retryWatchdog = setInterval(() => {
|
|
4224
|
+
if (!this.started) return;
|
|
4225
|
+
const lastActivity = this.lastFixAt || this.watchStartedAt;
|
|
4226
|
+
if (lastActivity && Date.now() - lastActivity >= (this.options.watchdogMs || 6e4)) this.restartWatch();
|
|
4227
|
+
}, Math.min(this.options.watchdogMs || 6e4, 15e3));
|
|
4228
|
+
}
|
|
4229
|
+
startWhenAuthenticated() {
|
|
4230
|
+
if (!this.options) return;
|
|
4231
|
+
if (this.api.token) {
|
|
4232
|
+
setTimeout(() => {
|
|
4233
|
+
try {
|
|
4234
|
+
this.start();
|
|
4235
|
+
} catch (error) {
|
|
4236
|
+
console.warn("Datalynk GPS auto-start failed:", error);
|
|
4237
|
+
}
|
|
4238
|
+
}, 0);
|
|
4239
|
+
return;
|
|
4240
|
+
}
|
|
4241
|
+
const sub = this.api.token$.subscribe((token) => {
|
|
4242
|
+
if (!token || this.started || !this.options || this.options.autoStart === false) return;
|
|
4243
|
+
try {
|
|
4244
|
+
this.start();
|
|
4245
|
+
} catch (error) {
|
|
4246
|
+
console.warn("Datalynk GPS auto-start failed:", error);
|
|
4247
|
+
}
|
|
4248
|
+
});
|
|
4249
|
+
this.unsubs.push(() => sub.unsubscribe());
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
3898
4252
|
const _Api = class _Api {
|
|
3899
4253
|
/**
|
|
3900
4254
|
* Connect to Datalynk & send requests
|
|
@@ -3933,6 +4287,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3933
4287
|
__publicField(this, "pwa");
|
|
3934
4288
|
/** Socket */
|
|
3935
4289
|
__publicField(this, "socket");
|
|
4290
|
+
/** GPS */
|
|
4291
|
+
__publicField(this, "gps");
|
|
3936
4292
|
/** Superuser */
|
|
3937
4293
|
__publicField(this, "superuser");
|
|
3938
4294
|
/** WebRTC */
|
|
@@ -3978,6 +4334,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3978
4334
|
});
|
|
3979
4335
|
}
|
|
3980
4336
|
this.socket = new Socket(this, { url: options.socket });
|
|
4337
|
+
this.gps = new Gps(this, options.gps);
|
|
3981
4338
|
this.auth = new Auth(this);
|
|
3982
4339
|
this.files = new Files(this);
|
|
3983
4340
|
this.pdf = new Pdf(this);
|
|
@@ -4283,6 +4640,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
4283
4640
|
exports2.ApiCall = ApiCall;
|
|
4284
4641
|
exports2.Auth = Auth;
|
|
4285
4642
|
exports2.Files = Files;
|
|
4643
|
+
exports2.Gps = Gps;
|
|
4286
4644
|
exports2.LoginPrompt = LoginPrompt;
|
|
4287
4645
|
exports2.PWA = PWA;
|
|
4288
4646
|
exports2.Pdf = Pdf;
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC;AACtB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,OAAO,CAAC;AACtB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
|
package/dist/index.mjs
CHANGED
|
@@ -3770,7 +3770,7 @@ class Superuser {
|
|
|
3770
3770
|
} });
|
|
3771
3771
|
}
|
|
3772
3772
|
}
|
|
3773
|
-
const version = "1.
|
|
3773
|
+
const version = "1.4.0";
|
|
3774
3774
|
class WebRtc {
|
|
3775
3775
|
constructor(api) {
|
|
3776
3776
|
__publicField(this, "ice");
|
|
@@ -3891,6 +3891,360 @@ class WebRtc {
|
|
|
3891
3891
|
return session;
|
|
3892
3892
|
}
|
|
3893
3893
|
}
|
|
3894
|
+
class Gps {
|
|
3895
|
+
constructor(api, options) {
|
|
3896
|
+
__publicField(this, "deviceId");
|
|
3897
|
+
__publicField(this, "heartbeat");
|
|
3898
|
+
__publicField(this, "lastFixAt", 0);
|
|
3899
|
+
__publicField(this, "lastPosition");
|
|
3900
|
+
__publicField(this, "lastSentAt", 0);
|
|
3901
|
+
__publicField(this, "lastSentPosition");
|
|
3902
|
+
__publicField(this, "pendingPayloads", []);
|
|
3903
|
+
__publicField(this, "retryWatchdog");
|
|
3904
|
+
__publicField(this, "seq", 0);
|
|
3905
|
+
__publicField(this, "sessionId");
|
|
3906
|
+
__publicField(this, "socket");
|
|
3907
|
+
__publicField(this, "trackerId");
|
|
3908
|
+
__publicField(this, "started", false);
|
|
3909
|
+
__publicField(this, "unsubs", []);
|
|
3910
|
+
__publicField(this, "watchId");
|
|
3911
|
+
__publicField(this, "watchStartedAt", 0);
|
|
3912
|
+
__publicField(this, "options");
|
|
3913
|
+
__publicField(this, "onPosition", (position) => {
|
|
3914
|
+
if (!this.options) return;
|
|
3915
|
+
if (!this.isFresh(position)) return;
|
|
3916
|
+
this.lastFixAt = Date.now();
|
|
3917
|
+
this.lastPosition = position;
|
|
3918
|
+
if (this.shouldSendPosition(position, false)) this.sendPosition(position, false);
|
|
3919
|
+
});
|
|
3920
|
+
__publicField(this, "onPositionError", (error) => {
|
|
3921
|
+
console.warn("Datalynk GPS error:", error.message);
|
|
3922
|
+
});
|
|
3923
|
+
this.api = api;
|
|
3924
|
+
if (options === false || options == null) return;
|
|
3925
|
+
this.options = {
|
|
3926
|
+
autoStart: true,
|
|
3927
|
+
field: "coords",
|
|
3928
|
+
heartbeatMs: 5e3,
|
|
3929
|
+
minDistanceMeters: 3,
|
|
3930
|
+
maxAccuracyMeters: 200,
|
|
3931
|
+
highAccuracy: true,
|
|
3932
|
+
timeoutMs: 1e4,
|
|
3933
|
+
maxStaleMs: 4e3,
|
|
3934
|
+
watchdogMs: 6e4,
|
|
3935
|
+
...options
|
|
3936
|
+
};
|
|
3937
|
+
this.deviceId = this.options.deviceId || this.getOrCreateDeviceId();
|
|
3938
|
+
this.sessionId = this.createId();
|
|
3939
|
+
this.trackerId = this.options.trackingId || this.createId();
|
|
3940
|
+
if (this.options.autoStart !== false) this.startWhenAuthenticated();
|
|
3941
|
+
}
|
|
3942
|
+
/** Start sharing browser GPS to socket-server */
|
|
3943
|
+
start() {
|
|
3944
|
+
if (!this.options) throw new Error("Datalynk GPS is not configured");
|
|
3945
|
+
if (this.started) return;
|
|
3946
|
+
if (!this.api.token) throw new Error("Datalynk GPS cannot start before login");
|
|
3947
|
+
if (typeof navigator == "undefined" || !navigator.geolocation) throw new Error("Browser geolocation is not available");
|
|
3948
|
+
this.started = true;
|
|
3949
|
+
this.connectSocket();
|
|
3950
|
+
this.startWatch();
|
|
3951
|
+
this.startHeartbeat();
|
|
3952
|
+
this.startWatchdog();
|
|
3953
|
+
this.bindResumeEvents();
|
|
3954
|
+
}
|
|
3955
|
+
/** Stop sharing GPS and close the dedicated GPS socket */
|
|
3956
|
+
stop() {
|
|
3957
|
+
var _a;
|
|
3958
|
+
this.started = false;
|
|
3959
|
+
if (this.watchId != null && typeof navigator != "undefined") navigator.geolocation.clearWatch(this.watchId);
|
|
3960
|
+
this.watchId = void 0;
|
|
3961
|
+
if (this.heartbeat) clearInterval(this.heartbeat);
|
|
3962
|
+
this.heartbeat = void 0;
|
|
3963
|
+
if (this.retryWatchdog) clearInterval(this.retryWatchdog);
|
|
3964
|
+
this.retryWatchdog = void 0;
|
|
3965
|
+
this.unsubs.forEach((unsub) => unsub());
|
|
3966
|
+
this.unsubs = [];
|
|
3967
|
+
this.pendingPayloads = [];
|
|
3968
|
+
(_a = this.socket) == null ? void 0 : _a.close();
|
|
3969
|
+
this.socket = void 0;
|
|
3970
|
+
}
|
|
3971
|
+
/** Send a raw GPS message. Useful when an app already has its own GPS engine */
|
|
3972
|
+
send(position, extra = {}) {
|
|
3973
|
+
if (!this.options) throw new Error("Datalynk GPS is not configured");
|
|
3974
|
+
if (!this.api.token) throw new Error("Datalynk GPS cannot send before login");
|
|
3975
|
+
this.connectSocket();
|
|
3976
|
+
this.sendPayload({
|
|
3977
|
+
...extra,
|
|
3978
|
+
position: this.normalizePosition(position)
|
|
3979
|
+
});
|
|
3980
|
+
}
|
|
3981
|
+
/** Listen to GPS updates for the configured slice/field */
|
|
3982
|
+
listen(callback, options = {}) {
|
|
3983
|
+
if (!this.options) throw new Error("Datalynk GPS is not configured");
|
|
3984
|
+
if (!this.api.token) throw new Error("Datalynk GPS cannot listen before login");
|
|
3985
|
+
this.connectSocket();
|
|
3986
|
+
const request = {
|
|
3987
|
+
gpsListen: {
|
|
3988
|
+
slice: options.slice || this.options.slice,
|
|
3989
|
+
field: options.field || this.options.field || "coords",
|
|
3990
|
+
includeTrails: options.includeTrails ?? false,
|
|
3991
|
+
trailLimit: options.trailLimit ?? 0
|
|
3992
|
+
}
|
|
3993
|
+
};
|
|
3994
|
+
return this.socket.addListener((event) => {
|
|
3995
|
+
var _a, _b;
|
|
3996
|
+
const payload = event;
|
|
3997
|
+
const gps = ((_a = payload == null ? void 0 : payload.data) == null ? void 0 : _a.gps) || (payload == null ? void 0 : payload.gps);
|
|
3998
|
+
if ((payload == null ? void 0 : payload.type) == "sliceEvents" && ((_b = payload == null ? void 0 : payload.data) == null ? void 0 : _b.type) == "gps.position" && gps) callback(gps);
|
|
3999
|
+
else if ((payload == null ? void 0 : payload.type) == "gps.position" && gps) callback(gps);
|
|
4000
|
+
else if ((payload == null ? void 0 : payload.type) == "gpsListen" || (payload == null ? void 0 : payload.gpsListen)) callback(payload);
|
|
4001
|
+
}, () => this.socket.send(request));
|
|
4002
|
+
}
|
|
4003
|
+
bindResumeEvents() {
|
|
4004
|
+
if (typeof window == "undefined" || typeof document == "undefined") return;
|
|
4005
|
+
const restart = () => {
|
|
4006
|
+
if (!this.started) return;
|
|
4007
|
+
if (document.visibilityState && document.visibilityState !== "visible") return;
|
|
4008
|
+
this.restartWatch();
|
|
4009
|
+
};
|
|
4010
|
+
window.addEventListener("focus", restart);
|
|
4011
|
+
window.addEventListener("pageshow", restart);
|
|
4012
|
+
document.addEventListener("visibilitychange", restart);
|
|
4013
|
+
this.unsubs.push(() => {
|
|
4014
|
+
window.removeEventListener("focus", restart);
|
|
4015
|
+
window.removeEventListener("pageshow", restart);
|
|
4016
|
+
document.removeEventListener("visibilitychange", restart);
|
|
4017
|
+
});
|
|
4018
|
+
}
|
|
4019
|
+
connectSocket() {
|
|
4020
|
+
if (!this.options || this.socket) return;
|
|
4021
|
+
if (!this.api.token) throw new Error("Datalynk GPS socket cannot connect before login");
|
|
4022
|
+
this.socket = new Socket(this.api, { url: this.options.socketUrl });
|
|
4023
|
+
this.unsubs.push(this.socket.addListener(() => {
|
|
4024
|
+
}, () => this.flushPendingPayloads()));
|
|
4025
|
+
}
|
|
4026
|
+
createId() {
|
|
4027
|
+
if (typeof crypto != "undefined" && crypto.randomUUID) return crypto.randomUUID();
|
|
4028
|
+
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
4029
|
+
}
|
|
4030
|
+
flushPendingPayloads() {
|
|
4031
|
+
var _a;
|
|
4032
|
+
if (!((_a = this.socket) == null ? void 0 : _a.open)) return;
|
|
4033
|
+
while (this.pendingPayloads.length) {
|
|
4034
|
+
this.socket.send(this.pendingPayloads.shift());
|
|
4035
|
+
}
|
|
4036
|
+
}
|
|
4037
|
+
getClientDetails() {
|
|
4038
|
+
if (typeof navigator == "undefined") return {};
|
|
4039
|
+
return {
|
|
4040
|
+
userAgent: navigator.userAgent,
|
|
4041
|
+
language: navigator.language,
|
|
4042
|
+
platform: navigator.platform,
|
|
4043
|
+
vendor: navigator.vendor,
|
|
4044
|
+
screen: typeof screen == "undefined" ? void 0 : {
|
|
4045
|
+
width: screen.width,
|
|
4046
|
+
height: screen.height,
|
|
4047
|
+
pixelRatio: typeof devicePixelRatio == "undefined" ? void 0 : devicePixelRatio
|
|
4048
|
+
},
|
|
4049
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
4050
|
+
};
|
|
4051
|
+
}
|
|
4052
|
+
getOrCreateDeviceId() {
|
|
4053
|
+
const key = "datalynk-gps-device-id";
|
|
4054
|
+
if (typeof localStorage != "undefined") {
|
|
4055
|
+
const existing = localStorage.getItem(key);
|
|
4056
|
+
if (existing) return existing;
|
|
4057
|
+
const id = this.createId();
|
|
4058
|
+
localStorage.setItem(key, id);
|
|
4059
|
+
return id;
|
|
4060
|
+
}
|
|
4061
|
+
return this.createId();
|
|
4062
|
+
}
|
|
4063
|
+
getTrackingId() {
|
|
4064
|
+
var _a;
|
|
4065
|
+
if (!this.options) return this.trackerId || this.createId();
|
|
4066
|
+
if (this.options.trackingId) return this.options.trackingId;
|
|
4067
|
+
const uid = (_a = this.api.jwtPayload) == null ? void 0 : _a.uid;
|
|
4068
|
+
return uid ? `user:${uid}:tracker:${this.trackerId}` : `device:${this.deviceId}:tracker:${this.trackerId}`;
|
|
4069
|
+
}
|
|
4070
|
+
isFresh(position) {
|
|
4071
|
+
if (!this.options) return false;
|
|
4072
|
+
if (this.lastPosition && position.timestamp <= this.lastPosition.timestamp) return false;
|
|
4073
|
+
return Date.now() - position.timestamp <= (this.options.maxStaleMs || 4e3);
|
|
4074
|
+
}
|
|
4075
|
+
metersBetween(a, b) {
|
|
4076
|
+
const earthRadius = 6371e3;
|
|
4077
|
+
const lat1 = a.coords.latitude * Math.PI / 180;
|
|
4078
|
+
const lat2 = b.coords.latitude * Math.PI / 180;
|
|
4079
|
+
const dLat = (b.coords.latitude - a.coords.latitude) * Math.PI / 180;
|
|
4080
|
+
const dLng = (b.coords.longitude - a.coords.longitude) * Math.PI / 180;
|
|
4081
|
+
const x = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
|
|
4082
|
+
return earthRadius * 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));
|
|
4083
|
+
}
|
|
4084
|
+
normalizeNullableNumber(value, field) {
|
|
4085
|
+
if (value == null || value === "") return null;
|
|
4086
|
+
const number = Number(value);
|
|
4087
|
+
if (!Number.isFinite(number)) throw new Error(`GPS ${field} must be a valid number`);
|
|
4088
|
+
return number;
|
|
4089
|
+
}
|
|
4090
|
+
normalizeOptionalNumber(value, field) {
|
|
4091
|
+
if (value == null || value === "") return void 0;
|
|
4092
|
+
const number = Number(value);
|
|
4093
|
+
if (!Number.isFinite(number)) throw new Error(`GPS ${field} must be a valid number`);
|
|
4094
|
+
return number;
|
|
4095
|
+
}
|
|
4096
|
+
normalizePosition(position) {
|
|
4097
|
+
const lat = Number(position.lat ?? position.latitude);
|
|
4098
|
+
const lng = Number(position.lng ?? position.lon ?? position.longitude);
|
|
4099
|
+
if (!Number.isFinite(lat) || lat < -90 || lat > 90) {
|
|
4100
|
+
throw new Error("GPS position must include a valid lat/latitude between -90 and 90");
|
|
4101
|
+
}
|
|
4102
|
+
if (!Number.isFinite(lng) || lng < -180 || lng > 180) {
|
|
4103
|
+
throw new Error("GPS position must include a valid lng/lon/longitude between -180 and 180");
|
|
4104
|
+
}
|
|
4105
|
+
const accuracy = this.normalizeNullableNumber(position.accuracy, "accuracy");
|
|
4106
|
+
if (accuracy != null && accuracy < 0) throw new Error("GPS accuracy must be zero or greater");
|
|
4107
|
+
const altitude = this.normalizeNullableNumber(position.altitude, "altitude");
|
|
4108
|
+
const altitudeAccuracy = this.normalizeNullableNumber(position.altitudeAccuracy, "altitudeAccuracy");
|
|
4109
|
+
if (altitudeAccuracy != null && altitudeAccuracy < 0) throw new Error("GPS altitudeAccuracy must be zero or greater");
|
|
4110
|
+
const heading = this.normalizeNullableNumber(position.heading, "heading");
|
|
4111
|
+
if (heading != null && (heading < 0 || heading >= 360)) throw new Error("GPS heading must be between 0 and 360");
|
|
4112
|
+
const speed = this.normalizeNullableNumber(position.speed, "speed");
|
|
4113
|
+
if (speed != null && speed < 0) throw new Error("GPS speed must be zero or greater");
|
|
4114
|
+
const timestampMs = this.normalizeOptionalNumber(position.timestampMs, "timestampMs") ?? Date.now();
|
|
4115
|
+
if (timestampMs <= 0) throw new Error("GPS timestampMs must be greater than zero");
|
|
4116
|
+
let timestamp = position.timestamp;
|
|
4117
|
+
if (timestamp) {
|
|
4118
|
+
const parsed = Date.parse(timestamp);
|
|
4119
|
+
if (!Number.isFinite(parsed)) throw new Error("GPS timestamp must be a valid date string");
|
|
4120
|
+
} else {
|
|
4121
|
+
timestamp = new Date(timestampMs).toISOString();
|
|
4122
|
+
}
|
|
4123
|
+
return {
|
|
4124
|
+
lat,
|
|
4125
|
+
lng,
|
|
4126
|
+
accuracy,
|
|
4127
|
+
altitude,
|
|
4128
|
+
altitudeAccuracy,
|
|
4129
|
+
heading,
|
|
4130
|
+
speed,
|
|
4131
|
+
timestamp,
|
|
4132
|
+
timestampMs
|
|
4133
|
+
};
|
|
4134
|
+
}
|
|
4135
|
+
restartWatch() {
|
|
4136
|
+
if (!this.options || !this.started || typeof navigator == "undefined" || !navigator.geolocation) return;
|
|
4137
|
+
if (this.watchId != null) navigator.geolocation.clearWatch(this.watchId);
|
|
4138
|
+
this.watchId = void 0;
|
|
4139
|
+
this.startWatch();
|
|
4140
|
+
}
|
|
4141
|
+
sendPayload(payload) {
|
|
4142
|
+
var _a, _b;
|
|
4143
|
+
if (!this.options) return;
|
|
4144
|
+
this.connectSocket();
|
|
4145
|
+
const message = {
|
|
4146
|
+
gps: {
|
|
4147
|
+
slice: this.options.slice,
|
|
4148
|
+
field: this.options.field || "coords",
|
|
4149
|
+
trackingId: this.getTrackingId(),
|
|
4150
|
+
trackerId: this.trackerId,
|
|
4151
|
+
sessionId: this.sessionId,
|
|
4152
|
+
deviceId: this.deviceId,
|
|
4153
|
+
seq: ++this.seq,
|
|
4154
|
+
client: this.getClientDetails(),
|
|
4155
|
+
sentAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4156
|
+
gpsTimestamp: ((_a = payload.position) == null ? void 0 : _a.timestamp) || null,
|
|
4157
|
+
label: this.options.label,
|
|
4158
|
+
source: this.options.source,
|
|
4159
|
+
...payload
|
|
4160
|
+
}
|
|
4161
|
+
};
|
|
4162
|
+
if (!((_b = this.socket) == null ? void 0 : _b.open)) {
|
|
4163
|
+
this.pendingPayloads.push(message);
|
|
4164
|
+
this.pendingPayloads = this.pendingPayloads.slice(-25);
|
|
4165
|
+
return;
|
|
4166
|
+
}
|
|
4167
|
+
this.socket.send(message);
|
|
4168
|
+
}
|
|
4169
|
+
sendPosition(position, force) {
|
|
4170
|
+
this.sendPayload({
|
|
4171
|
+
force,
|
|
4172
|
+
position: this.serializePosition(position)
|
|
4173
|
+
});
|
|
4174
|
+
this.lastSentPosition = position;
|
|
4175
|
+
this.lastSentAt = Date.now();
|
|
4176
|
+
}
|
|
4177
|
+
serializePosition(position) {
|
|
4178
|
+
return {
|
|
4179
|
+
lat: position.coords.latitude,
|
|
4180
|
+
lng: position.coords.longitude,
|
|
4181
|
+
accuracy: position.coords.accuracy,
|
|
4182
|
+
altitude: position.coords.altitude,
|
|
4183
|
+
altitudeAccuracy: position.coords.altitudeAccuracy,
|
|
4184
|
+
heading: position.coords.heading,
|
|
4185
|
+
speed: position.coords.speed,
|
|
4186
|
+
timestamp: new Date(position.timestamp).toISOString(),
|
|
4187
|
+
timestampMs: position.timestamp
|
|
4188
|
+
};
|
|
4189
|
+
}
|
|
4190
|
+
shouldSendPosition(position, force) {
|
|
4191
|
+
if (!this.options) return false;
|
|
4192
|
+
if (force) return true;
|
|
4193
|
+
const accuracy = Number(position.coords.accuracy || 0);
|
|
4194
|
+
if (accuracy && accuracy > (this.options.maxAccuracyMeters || 200)) return false;
|
|
4195
|
+
if (!this.lastSentPosition) return true;
|
|
4196
|
+
const movedMeters = this.metersBetween(this.lastSentPosition, position);
|
|
4197
|
+
const accuracyImproved = Number(position.coords.accuracy || 999999) < Number(this.lastSentPosition.coords.accuracy || 999999);
|
|
4198
|
+
const heartbeatDue = Date.now() - this.lastSentAt >= (this.options.heartbeatMs || 5e3);
|
|
4199
|
+
return movedMeters >= (this.options.minDistanceMeters || 3) || accuracyImproved || heartbeatDue;
|
|
4200
|
+
}
|
|
4201
|
+
startHeartbeat() {
|
|
4202
|
+
if (!this.options || this.heartbeat) return;
|
|
4203
|
+
this.heartbeat = setInterval(() => {
|
|
4204
|
+
if (!this.started || !this.lastPosition) return;
|
|
4205
|
+
this.sendPosition(this.lastPosition, true);
|
|
4206
|
+
}, this.options.heartbeatMs || 5e3);
|
|
4207
|
+
}
|
|
4208
|
+
startWatch() {
|
|
4209
|
+
if (!this.options || this.watchId != null) return;
|
|
4210
|
+
this.watchStartedAt = Date.now();
|
|
4211
|
+
this.watchId = navigator.geolocation.watchPosition(this.onPosition, this.onPositionError, {
|
|
4212
|
+
enableHighAccuracy: this.options.highAccuracy !== false,
|
|
4213
|
+
maximumAge: 0,
|
|
4214
|
+
timeout: this.options.timeoutMs || 1e4
|
|
4215
|
+
});
|
|
4216
|
+
}
|
|
4217
|
+
startWatchdog() {
|
|
4218
|
+
if (!this.options || this.retryWatchdog) return;
|
|
4219
|
+
this.retryWatchdog = setInterval(() => {
|
|
4220
|
+
if (!this.started) return;
|
|
4221
|
+
const lastActivity = this.lastFixAt || this.watchStartedAt;
|
|
4222
|
+
if (lastActivity && Date.now() - lastActivity >= (this.options.watchdogMs || 6e4)) this.restartWatch();
|
|
4223
|
+
}, Math.min(this.options.watchdogMs || 6e4, 15e3));
|
|
4224
|
+
}
|
|
4225
|
+
startWhenAuthenticated() {
|
|
4226
|
+
if (!this.options) return;
|
|
4227
|
+
if (this.api.token) {
|
|
4228
|
+
setTimeout(() => {
|
|
4229
|
+
try {
|
|
4230
|
+
this.start();
|
|
4231
|
+
} catch (error) {
|
|
4232
|
+
console.warn("Datalynk GPS auto-start failed:", error);
|
|
4233
|
+
}
|
|
4234
|
+
}, 0);
|
|
4235
|
+
return;
|
|
4236
|
+
}
|
|
4237
|
+
const sub = this.api.token$.subscribe((token) => {
|
|
4238
|
+
if (!token || this.started || !this.options || this.options.autoStart === false) return;
|
|
4239
|
+
try {
|
|
4240
|
+
this.start();
|
|
4241
|
+
} catch (error) {
|
|
4242
|
+
console.warn("Datalynk GPS auto-start failed:", error);
|
|
4243
|
+
}
|
|
4244
|
+
});
|
|
4245
|
+
this.unsubs.push(() => sub.unsubscribe());
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
3894
4248
|
const _Api = class _Api {
|
|
3895
4249
|
/**
|
|
3896
4250
|
* Connect to Datalynk & send requests
|
|
@@ -3929,6 +4283,8 @@ const _Api = class _Api {
|
|
|
3929
4283
|
__publicField(this, "pwa");
|
|
3930
4284
|
/** Socket */
|
|
3931
4285
|
__publicField(this, "socket");
|
|
4286
|
+
/** GPS */
|
|
4287
|
+
__publicField(this, "gps");
|
|
3932
4288
|
/** Superuser */
|
|
3933
4289
|
__publicField(this, "superuser");
|
|
3934
4290
|
/** WebRTC */
|
|
@@ -3974,6 +4330,7 @@ const _Api = class _Api {
|
|
|
3974
4330
|
});
|
|
3975
4331
|
}
|
|
3976
4332
|
this.socket = new Socket(this, { url: options.socket });
|
|
4333
|
+
this.gps = new Gps(this, options.gps);
|
|
3977
4334
|
this.auth = new Auth(this);
|
|
3978
4335
|
this.files = new Files(this);
|
|
3979
4336
|
this.pdf = new Pdf(this);
|
|
@@ -4280,6 +4637,7 @@ export {
|
|
|
4280
4637
|
ApiCall,
|
|
4281
4638
|
Auth,
|
|
4282
4639
|
Files,
|
|
4640
|
+
Gps,
|
|
4283
4641
|
LoginPrompt,
|
|
4284
4642
|
PWA,
|
|
4285
4643
|
Pdf,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@auxilium/datalynk-client",
|
|
3
3
|
"description": "Datalynk client library",
|
|
4
4
|
"repository": "https://gitlab.auxiliumgroup.com/auxilium/datalynk/datalynk-client",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.4.0",
|
|
6
6
|
"author": "Zak Timson <zaktimson@gmail.com>",
|
|
7
7
|
"private": false,
|
|
8
8
|
"main": "./dist/index.cjs",
|