@dronedeploy/rocos-js-sdk 4.4.10 → 4.4.12

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.
@@ -57,12 +57,9 @@ export interface GamepadButtonRef {
57
57
  type: GamepadButtonType;
58
58
  text: string;
59
59
  }
60
- export interface GamepadAction {
60
+ export interface GamepadActionBase {
61
61
  name: string;
62
62
  source: GamepadButtonRef;
63
- commandId: string;
64
- /** Absent on configs saved before Commands V2 existed. */
65
- commandVersion?: GamepadCommandVersion;
66
63
  triggerType: GamepadTriggerType;
67
64
  /** Milliseconds between repeats. Only meaningful for `continuously`. */
68
65
  frequency: number;
@@ -76,6 +73,26 @@ export interface GamepadAction {
76
73
  */
77
74
  modifiers?: GamepadButtonRef[];
78
75
  }
76
+ export type GamepadActionType = 'robot' | 'dashboard';
77
+ /** A robot-side action. `actionType` is absent on configurations saved before destinations existed. */
78
+ export interface GamepadRobotAction extends GamepadActionBase {
79
+ actionType?: 'robot';
80
+ commandId: string;
81
+ /** Absent on configs saved before Commands V2 existed. */
82
+ commandVersion?: GamepadCommandVersion;
83
+ }
84
+ /** A semantic action broadcast to widgets mounted on the current dashboard page. */
85
+ export interface GamepadDashboardAction extends GamepadActionBase {
86
+ actionType: 'dashboard';
87
+ actionName: string;
88
+ /** Custom-widget bundles that predate destinations skip any action without a `commandId`, so it must stay absent. */
89
+ commandId?: never;
90
+ commandVersion?: never;
91
+ }
92
+ export type GamepadAction = GamepadRobotAction | GamepadDashboardAction;
93
+ /** Prefer this over checking `actionType === 'robot'`, which misses configurations saved before destinations existed. */
94
+ export declare const isGamepadRobotAction: (action: GamepadAction) => action is GamepadRobotAction;
95
+ export declare const isGamepadDashboardAction: (action: GamepadAction) => action is GamepadDashboardAction;
79
96
  export interface GamepadVariable {
80
97
  name: string;
81
98
  source: GamepadButtonRef;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GamepadCommandVersion = exports.GamepadTriggerType = exports.MODIFIER_RELEASE_FRACTION = exports.DEFAULT_MODIFIER_THRESHOLD = exports.GamepadButtonType = void 0;
3
+ exports.isGamepadDashboardAction = exports.isGamepadRobotAction = exports.GamepadCommandVersion = exports.GamepadTriggerType = exports.MODIFIER_RELEASE_FRACTION = exports.DEFAULT_MODIFIER_THRESHOLD = exports.GamepadButtonType = void 0;
4
4
  // Ref: https://github.com/alaingilbert/GamepadJs
5
5
  var GamepadButtonType;
6
6
  (function (GamepadButtonType) {
@@ -55,3 +55,12 @@ var GamepadCommandVersion;
55
55
  GamepadCommandVersion["COMMANDS_V2"] = "commands-v2";
56
56
  GamepadCommandVersion["RUN_JS"] = "run-js";
57
57
  })(GamepadCommandVersion || (exports.GamepadCommandVersion = GamepadCommandVersion = {}));
58
+ /** Prefer this over checking `actionType === 'robot'`, which misses configurations saved before destinations existed. */
59
+ const isGamepadRobotAction = (action) => {
60
+ return action.actionType !== 'dashboard';
61
+ };
62
+ exports.isGamepadRobotAction = isGamepadRobotAction;
63
+ const isGamepadDashboardAction = (action) => {
64
+ return action.actionType === 'dashboard';
65
+ };
66
+ exports.isGamepadDashboardAction = isGamepadDashboardAction;
@@ -6,6 +6,7 @@ export declare class AuthService extends BaseServiceAbstract implements IBaseSer
6
6
  private token?;
7
7
  private tokenRefreshTimeoutId?;
8
8
  private tokenSubject$;
9
+ private pendingTokenRequest?;
9
10
  constructor(config: IRocosSDKConfig);
10
11
  /** Observable for token updates
11
12
  *
@@ -54,6 +55,8 @@ export declare class AuthService extends BaseServiceAbstract implements IBaseSer
54
55
  * This will return the current token if it is not expired, otherwise it will get a new token based on your config.
55
56
  */
56
57
  getToken(): Promise<Token>;
58
+ private getOrRequestToken;
59
+ private fetchNewToken;
57
60
  /**
58
61
  * Refresh the authentication token
59
62
  *
@@ -50,25 +50,27 @@ class AuthService extends BaseServiceAbstract_1.BaseServiceAbstract {
50
50
  if (expiresIn !== undefined) {
51
51
  this.logger.warn('setToken(value, expiresIn) is deprecated. Use setToken(value) instead');
52
52
  }
53
- if (typeof value === 'string') {
54
- this.token = new models_1.Token(value);
55
- }
56
- else {
57
- this.token = value;
53
+ const token = typeof value === 'string' ? new models_1.Token(value) : value;
54
+ if (token.value !== this.token?.value) {
55
+ this.pendingTokenRequest = undefined;
58
56
  }
57
+ this.token = token;
59
58
  this.config.token = this.token.value;
60
59
  // output a message for token change
61
60
  if (this.isTokenValid(this.token)) {
62
61
  this.tokenSubject$.next(this.token);
63
62
  }
64
63
  else {
65
- void this.getToken();
64
+ void this.getToken().catch((error) => {
65
+ this.logger.error('Failed to initialize auth token', error);
66
+ });
66
67
  }
67
68
  }
68
69
  /**
69
70
  * Clear token
70
71
  */
71
72
  clearToken() {
73
+ this.pendingTokenRequest = undefined;
72
74
  this.token = undefined;
73
75
  this.config.token = undefined;
74
76
  }
@@ -125,15 +127,38 @@ class AuthService extends BaseServiceAbstract_1.BaseServiceAbstract {
125
127
  * This will return the current token if it is not expired, otherwise it will get a new token based on your config.
126
128
  */
127
129
  async getToken() {
128
- if (this.token && this.isTokenValid(this.token)) {
129
- if (this.token.isExpiredIn(15, 'minutes')) {
130
- this.logger.info('Token expires within 15 minutes. Refreshing.');
131
- const newToken = await this.refreshToken();
132
- this.setToken(newToken);
133
- return newToken;
134
- }
130
+ if (this.token && this.isTokenValid(this.token) && !this.token.isExpiredIn(15, 'minutes')) {
135
131
  return this.token;
136
132
  }
133
+ return this.getOrRequestToken(() => this.fetchNewToken());
134
+ }
135
+ getOrRequestToken(fetchToken) {
136
+ if (this.pendingTokenRequest) {
137
+ return this.pendingTokenRequest;
138
+ }
139
+ const request = fetchToken()
140
+ .then((token) => {
141
+ if (this.pendingTokenRequest === request) {
142
+ this.setToken(token);
143
+ }
144
+ else if (this.token) {
145
+ return this.getToken();
146
+ }
147
+ return token;
148
+ })
149
+ .finally(() => {
150
+ if (this.pendingTokenRequest === request) {
151
+ this.pendingTokenRequest = undefined;
152
+ }
153
+ });
154
+ this.pendingTokenRequest = request;
155
+ return request;
156
+ }
157
+ async fetchNewToken() {
158
+ if (this.token && this.isTokenValid(this.token)) {
159
+ this.logger.info('Token expires within 15 minutes. Refreshing.');
160
+ return this.refreshToken();
161
+ }
137
162
  let token;
138
163
  try {
139
164
  if ('appId' in this.config && 'appKey' in this.config) {
@@ -159,7 +184,6 @@ class AuthService extends BaseServiceAbstract_1.BaseServiceAbstract {
159
184
  this.logger.error(message);
160
185
  throw new models_1.RocosError(message, models_1.errorCodes.AUTH_ERROR);
161
186
  }
162
- this.setToken(token);
163
187
  return token;
164
188
  }
165
189
  /**
@@ -192,9 +216,8 @@ class AuthService extends BaseServiceAbstract_1.BaseServiceAbstract {
192
216
  */
193
217
  async refreshTokenIfExpired(minutes) {
194
218
  if (this.token?.isExpiredIn(minutes, 'minutes')) {
195
- this.logger.info('Token expires in 15 minutes. Refreshing.');
196
- const newToken = await this.refreshToken();
197
- this.setToken(newToken);
219
+ this.logger.info(`Token expires in ${minutes} minutes. Refreshing.`);
220
+ await this.getOrRequestToken(() => this.refreshToken());
198
221
  return true;
199
222
  }
200
223
  return false;
@@ -57,12 +57,9 @@ export interface GamepadButtonRef {
57
57
  type: GamepadButtonType;
58
58
  text: string;
59
59
  }
60
- export interface GamepadAction {
60
+ export interface GamepadActionBase {
61
61
  name: string;
62
62
  source: GamepadButtonRef;
63
- commandId: string;
64
- /** Absent on configs saved before Commands V2 existed. */
65
- commandVersion?: GamepadCommandVersion;
66
63
  triggerType: GamepadTriggerType;
67
64
  /** Milliseconds between repeats. Only meaningful for `continuously`. */
68
65
  frequency: number;
@@ -76,6 +73,26 @@ export interface GamepadAction {
76
73
  */
77
74
  modifiers?: GamepadButtonRef[];
78
75
  }
76
+ export type GamepadActionType = 'robot' | 'dashboard';
77
+ /** A robot-side action. `actionType` is absent on configurations saved before destinations existed. */
78
+ export interface GamepadRobotAction extends GamepadActionBase {
79
+ actionType?: 'robot';
80
+ commandId: string;
81
+ /** Absent on configs saved before Commands V2 existed. */
82
+ commandVersion?: GamepadCommandVersion;
83
+ }
84
+ /** A semantic action broadcast to widgets mounted on the current dashboard page. */
85
+ export interface GamepadDashboardAction extends GamepadActionBase {
86
+ actionType: 'dashboard';
87
+ actionName: string;
88
+ /** Custom-widget bundles that predate destinations skip any action without a `commandId`, so it must stay absent. */
89
+ commandId?: never;
90
+ commandVersion?: never;
91
+ }
92
+ export type GamepadAction = GamepadRobotAction | GamepadDashboardAction;
93
+ /** Prefer this over checking `actionType === 'robot'`, which misses configurations saved before destinations existed. */
94
+ export declare const isGamepadRobotAction: (action: GamepadAction) => action is GamepadRobotAction;
95
+ export declare const isGamepadDashboardAction: (action: GamepadAction) => action is GamepadDashboardAction;
79
96
  export interface GamepadVariable {
80
97
  name: string;
81
98
  source: GamepadButtonRef;
@@ -52,3 +52,10 @@ export var GamepadCommandVersion;
52
52
  GamepadCommandVersion["COMMANDS_V2"] = "commands-v2";
53
53
  GamepadCommandVersion["RUN_JS"] = "run-js";
54
54
  })(GamepadCommandVersion || (GamepadCommandVersion = {}));
55
+ /** Prefer this over checking `actionType === 'robot'`, which misses configurations saved before destinations existed. */
56
+ export const isGamepadRobotAction = (action) => {
57
+ return action.actionType !== 'dashboard';
58
+ };
59
+ export const isGamepadDashboardAction = (action) => {
60
+ return action.actionType === 'dashboard';
61
+ };
@@ -6,6 +6,7 @@ export declare class AuthService extends BaseServiceAbstract implements IBaseSer
6
6
  private token?;
7
7
  private tokenRefreshTimeoutId?;
8
8
  private tokenSubject$;
9
+ private pendingTokenRequest?;
9
10
  constructor(config: IRocosSDKConfig);
10
11
  /** Observable for token updates
11
12
  *
@@ -54,6 +55,8 @@ export declare class AuthService extends BaseServiceAbstract implements IBaseSer
54
55
  * This will return the current token if it is not expired, otherwise it will get a new token based on your config.
55
56
  */
56
57
  getToken(): Promise<Token>;
58
+ private getOrRequestToken;
59
+ private fetchNewToken;
57
60
  /**
58
61
  * Refresh the authentication token
59
62
  *
@@ -47,25 +47,27 @@ export class AuthService extends BaseServiceAbstract {
47
47
  if (expiresIn !== undefined) {
48
48
  this.logger.warn('setToken(value, expiresIn) is deprecated. Use setToken(value) instead');
49
49
  }
50
- if (typeof value === 'string') {
51
- this.token = new Token(value);
52
- }
53
- else {
54
- this.token = value;
50
+ const token = typeof value === 'string' ? new Token(value) : value;
51
+ if (token.value !== this.token?.value) {
52
+ this.pendingTokenRequest = undefined;
55
53
  }
54
+ this.token = token;
56
55
  this.config.token = this.token.value;
57
56
  // output a message for token change
58
57
  if (this.isTokenValid(this.token)) {
59
58
  this.tokenSubject$.next(this.token);
60
59
  }
61
60
  else {
62
- void this.getToken();
61
+ void this.getToken().catch((error) => {
62
+ this.logger.error('Failed to initialize auth token', error);
63
+ });
63
64
  }
64
65
  }
65
66
  /**
66
67
  * Clear token
67
68
  */
68
69
  clearToken() {
70
+ this.pendingTokenRequest = undefined;
69
71
  this.token = undefined;
70
72
  this.config.token = undefined;
71
73
  }
@@ -122,15 +124,38 @@ export class AuthService extends BaseServiceAbstract {
122
124
  * This will return the current token if it is not expired, otherwise it will get a new token based on your config.
123
125
  */
124
126
  async getToken() {
125
- if (this.token && this.isTokenValid(this.token)) {
126
- if (this.token.isExpiredIn(15, 'minutes')) {
127
- this.logger.info('Token expires within 15 minutes. Refreshing.');
128
- const newToken = await this.refreshToken();
129
- this.setToken(newToken);
130
- return newToken;
131
- }
127
+ if (this.token && this.isTokenValid(this.token) && !this.token.isExpiredIn(15, 'minutes')) {
132
128
  return this.token;
133
129
  }
130
+ return this.getOrRequestToken(() => this.fetchNewToken());
131
+ }
132
+ getOrRequestToken(fetchToken) {
133
+ if (this.pendingTokenRequest) {
134
+ return this.pendingTokenRequest;
135
+ }
136
+ const request = fetchToken()
137
+ .then((token) => {
138
+ if (this.pendingTokenRequest === request) {
139
+ this.setToken(token);
140
+ }
141
+ else if (this.token) {
142
+ return this.getToken();
143
+ }
144
+ return token;
145
+ })
146
+ .finally(() => {
147
+ if (this.pendingTokenRequest === request) {
148
+ this.pendingTokenRequest = undefined;
149
+ }
150
+ });
151
+ this.pendingTokenRequest = request;
152
+ return request;
153
+ }
154
+ async fetchNewToken() {
155
+ if (this.token && this.isTokenValid(this.token)) {
156
+ this.logger.info('Token expires within 15 minutes. Refreshing.');
157
+ return this.refreshToken();
158
+ }
134
159
  let token;
135
160
  try {
136
161
  if ('appId' in this.config && 'appKey' in this.config) {
@@ -156,7 +181,6 @@ export class AuthService extends BaseServiceAbstract {
156
181
  this.logger.error(message);
157
182
  throw new RocosError(message, errorCodes.AUTH_ERROR);
158
183
  }
159
- this.setToken(token);
160
184
  return token;
161
185
  }
162
186
  /**
@@ -189,9 +213,8 @@ export class AuthService extends BaseServiceAbstract {
189
213
  */
190
214
  async refreshTokenIfExpired(minutes) {
191
215
  if (this.token?.isExpiredIn(minutes, 'minutes')) {
192
- this.logger.info('Token expires in 15 minutes. Refreshing.');
193
- const newToken = await this.refreshToken();
194
- this.setToken(newToken);
216
+ this.logger.info(`Token expires in ${minutes} minutes. Refreshing.`);
217
+ await this.getOrRequestToken(() => this.refreshToken());
195
218
  return true;
196
219
  }
197
220
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dronedeploy/rocos-js-sdk",
3
- "version": "4.4.10",
3
+ "version": "4.4.12",
4
4
  "description": "Javascript SDK for rocos",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",