@auxilium/datalynk-client 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/gps.d.ts CHANGED
@@ -41,6 +41,10 @@ export type GpsOptions = false | {
41
41
  maxStaleMs?: number;
42
42
  /** Restart watchPosition if no fresh fix arrives. Default is 60000 */
43
43
  watchdogMs?: number;
44
+ /** Wait for socket-server ack on manual send(). Default is false */
45
+ waitForAck?: boolean;
46
+ /** Ack wait timeout when waitForAck is true. Default is 15000 */
47
+ ackTimeoutMs?: number;
44
48
  };
45
49
  export type GpsPositionPayload = {
46
50
  lat: number;
@@ -68,9 +72,32 @@ export type GpsListenOptions = {
68
72
  trailLimit?: number;
69
73
  };
70
74
  export type GpsListener = (event: any) => any;
75
+ /** Server response body inside `{ gps: ... }` */
76
+ export type GpsAck = {
77
+ ok: boolean;
78
+ seq?: number | null;
79
+ error?: string;
80
+ stage?: string;
81
+ slice?: number | string;
82
+ field?: string;
83
+ trackingId?: string;
84
+ liveKey?: string;
85
+ dirtyKey?: string;
86
+ activeKey?: string;
87
+ trailKey?: string;
88
+ sessionId?: string | null;
89
+ deviceId?: string | null;
90
+ pending?: boolean;
91
+ };
92
+ export type GpsSendOptions = {
93
+ /** When true, wait for matching socket-server ack (matched by seq). Default false */
94
+ waitForAck?: boolean;
95
+ };
71
96
  /** Browser/manual GPS sender backed by socket-server Redis GPS storage */
72
97
  export declare class Gps {
73
98
  private readonly api;
99
+ private static readonly GPS_ACK_TIMEOUT_MS;
100
+ private ackResolvers;
74
101
  private deviceId;
75
102
  private heartbeat?;
76
103
  private lastFixAt;
@@ -93,12 +120,17 @@ export declare class Gps {
93
120
  start(): void;
94
121
  /** Stop sharing GPS and close the dedicated GPS socket */
95
122
  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;
123
+ /**
124
+ * Send a position from an app-owned GPS engine.
125
+ * By default returns after the message is queued/sent; set `waitForAck` to await server confirmation.
126
+ */
127
+ send(position: GpsManualPositionPayload, extra?: any, options?: GpsSendOptions): Promise<GpsAck>;
98
128
  /** Listen to GPS updates for the configured slice/field */
99
129
  listen(callback: GpsListener, options?: GpsListenOptions): Unsubscribe;
100
130
  private bindResumeEvents;
131
+ private clearAckResolvers;
101
132
  private connectSocket;
133
+ private onSocketMessage;
102
134
  private createId;
103
135
  private flushPendingPayloads;
104
136
  private getClientDetails;
package/dist/gps.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"gps.d.ts","sourceRoot":"","sources":["../src/gps.ts"],"names":[],"mappings":"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"}
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.4.0";
3777
+ const version = "1.4.1";
3778
3778
  class WebRtc {
3779
3779
  constructor(api) {
3780
3780
  __publicField(this, "ice");
@@ -3895,8 +3895,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3895
3895
  return session;
3896
3896
  }
3897
3897
  }
3898
- class Gps {
3898
+ const _Gps = class _Gps {
3899
3899
  constructor(api, options) {
3900
+ __publicField(this, "ackResolvers", /* @__PURE__ */ new Map());
3900
3901
  __publicField(this, "deviceId");
3901
3902
  __publicField(this, "heartbeat");
3902
3903
  __publicField(this, "lastFixAt", 0);
@@ -3914,6 +3915,15 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3914
3915
  __publicField(this, "watchId");
3915
3916
  __publicField(this, "watchStartedAt", 0);
3916
3917
  __publicField(this, "options");
3918
+ __publicField(this, "onSocketMessage", (event) => {
3919
+ const ack = event == null ? void 0 : event.gps;
3920
+ if (!ack || ack.seq == null) return;
3921
+ const pending = this.ackResolvers.get(Number(ack.seq));
3922
+ if (!pending) return;
3923
+ clearTimeout(pending.timeout);
3924
+ this.ackResolvers.delete(Number(ack.seq));
3925
+ pending.resolve(ack);
3926
+ });
3917
3927
  __publicField(this, "onPosition", (position) => {
3918
3928
  if (!this.options) return;
3919
3929
  if (!this.isFresh(position)) return;
@@ -3969,18 +3979,23 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3969
3979
  this.unsubs.forEach((unsub) => unsub());
3970
3980
  this.unsubs = [];
3971
3981
  this.pendingPayloads = [];
3982
+ this.clearAckResolvers("GPS stopped");
3972
3983
  (_a = this.socket) == null ? void 0 : _a.close();
3973
3984
  this.socket = void 0;
3974
3985
  }
3975
- /** Send a raw GPS message. Useful when an app already has its own GPS engine */
3976
- send(position, extra = {}) {
3986
+ /**
3987
+ * Send a position from an app-owned GPS engine.
3988
+ * By default returns after the message is queued/sent; set `waitForAck` to await server confirmation.
3989
+ */
3990
+ send(position, extra = {}, options = {}) {
3977
3991
  if (!this.options) throw new Error("Datalynk GPS is not configured");
3978
3992
  if (!this.api.token) throw new Error("Datalynk GPS cannot send before login");
3979
3993
  this.connectSocket();
3980
- this.sendPayload({
3994
+ const waitForAck = options.waitForAck ?? this.options.waitForAck ?? false;
3995
+ return this.sendPayload({
3981
3996
  ...extra,
3982
3997
  position: this.normalizePosition(position)
3983
- });
3998
+ }, waitForAck);
3984
3999
  }
3985
4000
  /** Listen to GPS updates for the configured slice/field */
3986
4001
  listen(callback, options = {}) {
@@ -4020,12 +4035,18 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4020
4035
  document.removeEventListener("visibilitychange", restart);
4021
4036
  });
4022
4037
  }
4038
+ clearAckResolvers(reason) {
4039
+ this.ackResolvers.forEach(({ timeout, resolve }) => {
4040
+ clearTimeout(timeout);
4041
+ resolve({ ok: false, error: reason });
4042
+ });
4043
+ this.ackResolvers.clear();
4044
+ }
4023
4045
  connectSocket() {
4024
4046
  if (!this.options || this.socket) return;
4025
4047
  if (!this.api.token) throw new Error("Datalynk GPS socket cannot connect before login");
4026
4048
  this.socket = new Socket(this.api, { url: this.options.socketUrl });
4027
- this.unsubs.push(this.socket.addListener(() => {
4028
- }, () => this.flushPendingPayloads()));
4049
+ this.unsubs.push(this.socket.addListener(this.onSocketMessage, () => this.flushPendingPayloads()));
4029
4050
  }
4030
4051
  createId() {
4031
4052
  if (typeof crypto != "undefined" && crypto.randomUUID) return crypto.randomUUID();
@@ -4142,10 +4163,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4142
4163
  this.watchId = void 0;
4143
4164
  this.startWatch();
4144
4165
  }
4145
- sendPayload(payload) {
4166
+ sendPayload(payload, waitForAck = false) {
4146
4167
  var _a, _b;
4147
- if (!this.options) return;
4168
+ if (!this.options) return Promise.resolve({ ok: false, error: "Datalynk GPS is not configured" });
4148
4169
  this.connectSocket();
4170
+ const seq = ++this.seq;
4149
4171
  const message = {
4150
4172
  gps: {
4151
4173
  slice: this.options.slice,
@@ -4154,7 +4176,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4154
4176
  trackerId: this.trackerId,
4155
4177
  sessionId: this.sessionId,
4156
4178
  deviceId: this.deviceId,
4157
- seq: ++this.seq,
4179
+ seq,
4158
4180
  client: this.getClientDetails(),
4159
4181
  sentAt: (/* @__PURE__ */ new Date()).toISOString(),
4160
4182
  gpsTimestamp: ((_a = payload.position) == null ? void 0 : _a.timestamp) || null,
@@ -4163,12 +4185,24 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4163
4185
  ...payload
4164
4186
  }
4165
4187
  };
4188
+ let ackPromise;
4189
+ if (waitForAck) {
4190
+ const timeoutMs = this.options.ackTimeoutMs ?? _Gps.GPS_ACK_TIMEOUT_MS;
4191
+ ackPromise = new Promise((resolve) => {
4192
+ const timeout = setTimeout(() => {
4193
+ this.ackResolvers.delete(seq);
4194
+ resolve({ ok: false, error: "GPS ack timeout", seq });
4195
+ }, timeoutMs);
4196
+ this.ackResolvers.set(seq, { resolve, timeout });
4197
+ });
4198
+ }
4166
4199
  if (!((_b = this.socket) == null ? void 0 : _b.open)) {
4167
4200
  this.pendingPayloads.push(message);
4168
4201
  this.pendingPayloads = this.pendingPayloads.slice(-25);
4169
- return;
4202
+ return ackPromise ?? Promise.resolve({ ok: true, seq, pending: true });
4170
4203
  }
4171
4204
  this.socket.send(message);
4205
+ return ackPromise ?? Promise.resolve({ ok: true, seq, pending: false });
4172
4206
  }
4173
4207
  sendPosition(position, force) {
4174
4208
  this.sendPayload({
@@ -4239,7 +4273,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4239
4273
  return;
4240
4274
  }
4241
4275
  const sub = this.api.token$.subscribe((token) => {
4242
- if (!token || this.started || !this.options || this.options.autoStart === false) return;
4276
+ if (!token) {
4277
+ if (this.started) this.stop();
4278
+ return;
4279
+ }
4280
+ if (this.started || !this.options || this.options.autoStart === false) return;
4243
4281
  try {
4244
4282
  this.start();
4245
4283
  } catch (error) {
@@ -4248,7 +4286,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
4248
4286
  });
4249
4287
  this.unsubs.push(() => sub.unsubscribe());
4250
4288
  }
4251
- }
4289
+ };
4290
+ __publicField(_Gps, "GPS_ACK_TIMEOUT_MS", 15e3);
4291
+ let Gps = _Gps;
4252
4292
  const _Api = class _Api {
4253
4293
  /**
4254
4294
  * Connect to Datalynk & send requests
package/dist/index.mjs CHANGED
@@ -3770,7 +3770,7 @@ class Superuser {
3770
3770
  } });
3771
3771
  }
3772
3772
  }
3773
- const version = "1.4.0";
3773
+ const version = "1.4.1";
3774
3774
  class WebRtc {
3775
3775
  constructor(api) {
3776
3776
  __publicField(this, "ice");
@@ -3891,8 +3891,9 @@ class WebRtc {
3891
3891
  return session;
3892
3892
  }
3893
3893
  }
3894
- class Gps {
3894
+ const _Gps = class _Gps {
3895
3895
  constructor(api, options) {
3896
+ __publicField(this, "ackResolvers", /* @__PURE__ */ new Map());
3896
3897
  __publicField(this, "deviceId");
3897
3898
  __publicField(this, "heartbeat");
3898
3899
  __publicField(this, "lastFixAt", 0);
@@ -3910,6 +3911,15 @@ class Gps {
3910
3911
  __publicField(this, "watchId");
3911
3912
  __publicField(this, "watchStartedAt", 0);
3912
3913
  __publicField(this, "options");
3914
+ __publicField(this, "onSocketMessage", (event) => {
3915
+ const ack = event == null ? void 0 : event.gps;
3916
+ if (!ack || ack.seq == null) return;
3917
+ const pending = this.ackResolvers.get(Number(ack.seq));
3918
+ if (!pending) return;
3919
+ clearTimeout(pending.timeout);
3920
+ this.ackResolvers.delete(Number(ack.seq));
3921
+ pending.resolve(ack);
3922
+ });
3913
3923
  __publicField(this, "onPosition", (position) => {
3914
3924
  if (!this.options) return;
3915
3925
  if (!this.isFresh(position)) return;
@@ -3965,18 +3975,23 @@ class Gps {
3965
3975
  this.unsubs.forEach((unsub) => unsub());
3966
3976
  this.unsubs = [];
3967
3977
  this.pendingPayloads = [];
3978
+ this.clearAckResolvers("GPS stopped");
3968
3979
  (_a = this.socket) == null ? void 0 : _a.close();
3969
3980
  this.socket = void 0;
3970
3981
  }
3971
- /** Send a raw GPS message. Useful when an app already has its own GPS engine */
3972
- send(position, extra = {}) {
3982
+ /**
3983
+ * Send a position from an app-owned GPS engine.
3984
+ * By default returns after the message is queued/sent; set `waitForAck` to await server confirmation.
3985
+ */
3986
+ send(position, extra = {}, options = {}) {
3973
3987
  if (!this.options) throw new Error("Datalynk GPS is not configured");
3974
3988
  if (!this.api.token) throw new Error("Datalynk GPS cannot send before login");
3975
3989
  this.connectSocket();
3976
- this.sendPayload({
3990
+ const waitForAck = options.waitForAck ?? this.options.waitForAck ?? false;
3991
+ return this.sendPayload({
3977
3992
  ...extra,
3978
3993
  position: this.normalizePosition(position)
3979
- });
3994
+ }, waitForAck);
3980
3995
  }
3981
3996
  /** Listen to GPS updates for the configured slice/field */
3982
3997
  listen(callback, options = {}) {
@@ -4016,12 +4031,18 @@ class Gps {
4016
4031
  document.removeEventListener("visibilitychange", restart);
4017
4032
  });
4018
4033
  }
4034
+ clearAckResolvers(reason) {
4035
+ this.ackResolvers.forEach(({ timeout, resolve }) => {
4036
+ clearTimeout(timeout);
4037
+ resolve({ ok: false, error: reason });
4038
+ });
4039
+ this.ackResolvers.clear();
4040
+ }
4019
4041
  connectSocket() {
4020
4042
  if (!this.options || this.socket) return;
4021
4043
  if (!this.api.token) throw new Error("Datalynk GPS socket cannot connect before login");
4022
4044
  this.socket = new Socket(this.api, { url: this.options.socketUrl });
4023
- this.unsubs.push(this.socket.addListener(() => {
4024
- }, () => this.flushPendingPayloads()));
4045
+ this.unsubs.push(this.socket.addListener(this.onSocketMessage, () => this.flushPendingPayloads()));
4025
4046
  }
4026
4047
  createId() {
4027
4048
  if (typeof crypto != "undefined" && crypto.randomUUID) return crypto.randomUUID();
@@ -4138,10 +4159,11 @@ class Gps {
4138
4159
  this.watchId = void 0;
4139
4160
  this.startWatch();
4140
4161
  }
4141
- sendPayload(payload) {
4162
+ sendPayload(payload, waitForAck = false) {
4142
4163
  var _a, _b;
4143
- if (!this.options) return;
4164
+ if (!this.options) return Promise.resolve({ ok: false, error: "Datalynk GPS is not configured" });
4144
4165
  this.connectSocket();
4166
+ const seq = ++this.seq;
4145
4167
  const message = {
4146
4168
  gps: {
4147
4169
  slice: this.options.slice,
@@ -4150,7 +4172,7 @@ class Gps {
4150
4172
  trackerId: this.trackerId,
4151
4173
  sessionId: this.sessionId,
4152
4174
  deviceId: this.deviceId,
4153
- seq: ++this.seq,
4175
+ seq,
4154
4176
  client: this.getClientDetails(),
4155
4177
  sentAt: (/* @__PURE__ */ new Date()).toISOString(),
4156
4178
  gpsTimestamp: ((_a = payload.position) == null ? void 0 : _a.timestamp) || null,
@@ -4159,12 +4181,24 @@ class Gps {
4159
4181
  ...payload
4160
4182
  }
4161
4183
  };
4184
+ let ackPromise;
4185
+ if (waitForAck) {
4186
+ const timeoutMs = this.options.ackTimeoutMs ?? _Gps.GPS_ACK_TIMEOUT_MS;
4187
+ ackPromise = new Promise((resolve) => {
4188
+ const timeout = setTimeout(() => {
4189
+ this.ackResolvers.delete(seq);
4190
+ resolve({ ok: false, error: "GPS ack timeout", seq });
4191
+ }, timeoutMs);
4192
+ this.ackResolvers.set(seq, { resolve, timeout });
4193
+ });
4194
+ }
4162
4195
  if (!((_b = this.socket) == null ? void 0 : _b.open)) {
4163
4196
  this.pendingPayloads.push(message);
4164
4197
  this.pendingPayloads = this.pendingPayloads.slice(-25);
4165
- return;
4198
+ return ackPromise ?? Promise.resolve({ ok: true, seq, pending: true });
4166
4199
  }
4167
4200
  this.socket.send(message);
4201
+ return ackPromise ?? Promise.resolve({ ok: true, seq, pending: false });
4168
4202
  }
4169
4203
  sendPosition(position, force) {
4170
4204
  this.sendPayload({
@@ -4235,7 +4269,11 @@ class Gps {
4235
4269
  return;
4236
4270
  }
4237
4271
  const sub = this.api.token$.subscribe((token) => {
4238
- if (!token || this.started || !this.options || this.options.autoStart === false) return;
4272
+ if (!token) {
4273
+ if (this.started) this.stop();
4274
+ return;
4275
+ }
4276
+ if (this.started || !this.options || this.options.autoStart === false) return;
4239
4277
  try {
4240
4278
  this.start();
4241
4279
  } catch (error) {
@@ -4244,7 +4282,9 @@ class Gps {
4244
4282
  });
4245
4283
  this.unsubs.push(() => sub.unsubscribe());
4246
4284
  }
4247
- }
4285
+ };
4286
+ __publicField(_Gps, "GPS_ACK_TIMEOUT_MS", 15e3);
4287
+ let Gps = _Gps;
4248
4288
  const _Api = class _Api {
4249
4289
  /**
4250
4290
  * Connect to Datalynk & send requests
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.4.0",
5
+ "version": "1.4.1",
6
6
  "author": "Zak Timson <zaktimson@gmail.com>",
7
7
  "private": false,
8
8
  "main": "./dist/index.cjs",