ring-client-api 13.2.1 → 14.0.0-beta.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.
Files changed (39) hide show
  1. package/lib/api.d.ts +10 -8
  2. package/lib/api.js +57 -64
  3. package/lib/device-data.js +6 -9
  4. package/lib/ffmpeg.js +2 -6
  5. package/lib/index.d.ts +7 -7
  6. package/lib/index.js +7 -23
  7. package/lib/location.d.ts +32 -31
  8. package/lib/location.js +67 -72
  9. package/lib/refresh-token.js +6 -11
  10. package/lib/rest-client.d.ts +4 -4
  11. package/lib/rest-client.js +40 -51
  12. package/lib/ring-auth-cli.js +2 -4
  13. package/lib/ring-camera.d.ts +26 -23
  14. package/lib/ring-camera.js +64 -61
  15. package/lib/ring-chime.d.ts +7 -7
  16. package/lib/ring-chime.js +14 -18
  17. package/lib/ring-device-data-cli.js +2 -4
  18. package/lib/ring-device.d.ts +7 -7
  19. package/lib/ring-device.js +16 -20
  20. package/lib/ring-intercom.d.ts +8 -8
  21. package/lib/ring-intercom.js +23 -27
  22. package/lib/ring-types.d.ts +142 -133
  23. package/lib/ring-types.js +137 -153
  24. package/lib/streaming/peer-connection.d.ts +5 -3
  25. package/lib/streaming/peer-connection.js +25 -30
  26. package/lib/streaming/simple-webrtc-session.d.ts +3 -3
  27. package/lib/streaming/simple-webrtc-session.js +3 -7
  28. package/lib/streaming/streaming-messages.d.ts +6 -5
  29. package/lib/streaming/streaming-messages.js +6 -9
  30. package/lib/streaming/streaming-session.d.ts +5 -5
  31. package/lib/streaming/streaming-session.js +34 -38
  32. package/lib/streaming/webrtc-connection.d.ts +5 -5
  33. package/lib/streaming/webrtc-connection.js +39 -43
  34. package/lib/subscribed.d.ts +1 -1
  35. package/lib/subscribed.js +1 -5
  36. package/lib/test/rest-client.spec.js +44 -45
  37. package/lib/test/ring-camera.spec.js +12 -13
  38. package/lib/util.js +33 -54
  39. package/package.json +17 -19
package/lib/location.js CHANGED
@@ -1,34 +1,25 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Location = void 0;
4
- const socket_io_client_1 = require("socket.io-client");
5
- const rxjs_1 = require("rxjs");
6
- const operators_1 = require("rxjs/operators");
7
- const util_1 = require("./util");
8
- const ring_types_1 = require("./ring-types");
9
- const rest_client_1 = require("./rest-client");
10
- const ring_camera_1 = require("./ring-camera");
11
- const ring_device_1 = require("./ring-device");
12
- const subscribed_1 = require("./subscribed");
1
+ import { connect as connectSocketIo } from 'socket.io-client';
2
+ import { BehaviorSubject, firstValueFrom, merge, ReplaySubject, Subject, } from 'rxjs';
3
+ import { concatMap, debounceTime, distinctUntilChanged, filter, map, scan, shareReplay, skip, } from 'rxjs/operators';
4
+ import { delay, generateUuid, logDebug, logError, logInfo } from "./util.js";
5
+ import { DispatchSignalType, RingDeviceType, disabledLocationModes, isWebSocketSupportedAsset, } from "./ring-types.js";
6
+ import { appApi, clientApi } from "./rest-client.js";
7
+ import { getSearchQueryString } from "./ring-camera.js";
8
+ import { RingDevice } from "./ring-device.js";
9
+ import { Subscribed } from "./subscribed.js";
13
10
  const deviceListMessageType = 'DeviceInfoDocGetList';
14
11
  function flattenDeviceData(data) {
15
12
  return Object.assign({}, data.general && data.general.v2, data.device && data.device.v1);
16
13
  }
17
- class Location extends subscribed_1.Subscribed {
18
- locationDetails;
19
- cameras;
20
- chimes;
21
- intercoms;
22
- options;
23
- restClient;
14
+ export class Location extends Subscribed {
24
15
  seq = 1;
25
- onMessage = new rxjs_1.Subject();
26
- onDataUpdate = new rxjs_1.Subject();
27
- onDeviceDataUpdate = this.onDataUpdate.pipe((0, operators_1.filter)((message) => {
16
+ onMessage = new Subject();
17
+ onDataUpdate = new Subject();
18
+ onDeviceDataUpdate = this.onDataUpdate.pipe(filter((message) => {
28
19
  return message.datatype === 'DeviceInfoDocType' && Boolean(message.body);
29
- }), (0, operators_1.concatMap)((message) => message.body), (0, operators_1.map)(flattenDeviceData));
30
- onDeviceList = this.onMessage.pipe((0, operators_1.filter)((m) => m.msg === deviceListMessageType));
31
- onDevices = this.onDeviceList.pipe((0, operators_1.scan)((devices, { body: deviceList, src }) => {
20
+ }), concatMap((message) => message.body), map(flattenDeviceData));
21
+ onDeviceList = this.onMessage.pipe(filter((m) => m.msg === deviceListMessageType));
22
+ onDevices = this.onDeviceList.pipe(scan((devices, { body: deviceList, src }) => {
32
23
  if (!deviceList) {
33
24
  return devices;
34
25
  }
@@ -41,16 +32,16 @@ class Location extends subscribed_1.Subscribed {
41
32
  existingDevice.updateData(flatData);
42
33
  return updatedDevices;
43
34
  }
44
- return [...updatedDevices, new ring_device_1.RingDevice(flatData, this, src)];
35
+ return [...updatedDevices, new RingDevice(flatData, this, src)];
45
36
  }, devices);
46
- }, []), (0, operators_1.distinctUntilChanged)((a, b) => a.length === b.length), (0, operators_1.filter)(() => {
37
+ }, []), distinctUntilChanged((a, b) => a.length === b.length), filter(() => {
47
38
  return Boolean(this.assets &&
48
39
  this.assets.every((asset) => this.receivedAssetDeviceLists.includes(asset.uuid)));
49
- }), (0, operators_1.shareReplay)(1));
50
- onSessionInfo = this.onDataUpdate.pipe((0, operators_1.filter)((m) => m.msg === 'SessionInfo'), (0, operators_1.map)((m) => m.body));
51
- onConnected = new rxjs_1.BehaviorSubject(false);
52
- onLocationMode = new rxjs_1.ReplaySubject(1);
53
- onLocationModeRequested = new rxjs_1.Subject();
40
+ }), shareReplay(1));
41
+ onSessionInfo = this.onDataUpdate.pipe(filter((m) => m.msg === 'SessionInfo'), map((m) => m.body));
42
+ onConnected = new BehaviorSubject(false);
43
+ onLocationMode = new ReplaySubject(1);
44
+ onLocationModeRequested = new Subject();
54
45
  reconnecting = false;
55
46
  disconnected = false;
56
47
  connectionPromise;
@@ -60,6 +51,12 @@ class Location extends subscribed_1.Subscribed {
60
51
  offlineAssets = [];
61
52
  hasHubs;
62
53
  hasAlarmBaseStation;
54
+ locationDetails;
55
+ cameras;
56
+ chimes;
57
+ intercoms;
58
+ options;
59
+ restClient;
63
60
  constructor(locationDetails, cameras, chimes, intercoms, options, restClient) {
64
61
  super();
65
62
  this.locationDetails = locationDetails;
@@ -83,23 +80,22 @@ class Location extends subscribed_1.Subscribed {
83
80
  }
84
81
  if (connectionStatus === 'online') {
85
82
  if (assetWasOffline) {
86
- // eslint-disable-next-line @typescript-eslint/no-empty-function
87
83
  this.requestList(deviceListMessageType, assetUuid).catch(() => { });
88
84
  this.offlineAssets = this.offlineAssets.filter((id) => id !== assetUuid);
89
- (0, util_1.logInfo)(`Ring ${asset.kind} ${assetUuid} has come back online`);
85
+ logInfo(`Ring ${asset.kind} ${assetUuid} has come back online`);
90
86
  }
91
87
  }
92
88
  else if (!assetWasOffline) {
93
- (0, util_1.logError)(`Ring ${asset.kind} ${assetUuid} is offline or on cellular backup. Waiting for status to change`);
89
+ logError(`Ring ${asset.kind} ${assetUuid} is offline or on cellular backup. Waiting for status to change`);
94
90
  this.offlineAssets.push(assetUuid);
95
91
  }
96
92
  });
97
93
  }));
98
94
  if (!options.hasAlarmBaseStation && options.locationModePollingSeconds) {
99
- this.addSubscriptions((0, rxjs_1.merge)(this.onLocationModeRequested, this.onLocationMode)
100
- .pipe((0, operators_1.debounceTime)(options.locationModePollingSeconds * 1000))
95
+ this.addSubscriptions(merge(this.onLocationModeRequested, this.onLocationMode)
96
+ .pipe(debounceTime(options.locationModePollingSeconds * 1000))
101
97
  .subscribe(() => this.getLocationMode()));
102
- this.getLocationMode().catch(util_1.logError);
98
+ this.getLocationMode().catch(logError);
103
99
  }
104
100
  }
105
101
  get id() {
@@ -115,39 +111,39 @@ class Location extends subscribed_1.Subscribed {
115
111
  if (this.disconnected) {
116
112
  return Promise.resolve({ disconnected: true });
117
113
  }
118
- (0, util_1.logInfo)('Creating location socket.io connection - ' + this.name);
114
+ logInfo('Creating location socket.io connection - ' + this.name);
119
115
  if (process.version.startsWith('v15.')) {
120
- (0, util_1.logError)('Node 15 is not currently supported by the Ring client. Please install the latest Node 14 instead. May not be able to fetch devices from Ring Alarm and Smart Lighting Hubs on this version of node.');
116
+ logError('Node 15 is not currently supported by the Ring client. Please install the latest Node 14 instead. May not be able to fetch devices from Ring Alarm and Smart Lighting Hubs on this version of node.');
121
117
  }
122
118
  const { assets, ticket, host } = await this.restClient.request({
123
- url: (0, rest_client_1.appApi)('clap/tickets?locationID=' + this.id),
124
- }), supportedAssets = assets.filter(ring_types_1.isWebSocketSupportedAsset);
119
+ url: appApi('clap/tickets?locationID=' + this.id),
120
+ }), supportedAssets = assets.filter(isWebSocketSupportedAsset);
125
121
  this.assets = supportedAssets;
126
122
  this.receivedAssetDeviceLists.length = 0;
127
123
  this.offlineAssets.length = 0;
128
124
  if (!supportedAssets.length) {
129
125
  const errorMessage = `No assets (alarm hubs or beam bridges) found for location ${this.name} - ${this.id}`;
130
- (0, util_1.logError)(errorMessage);
126
+ logError(errorMessage);
131
127
  throw new Error(errorMessage);
132
128
  }
133
- const connection = (0, socket_io_client_1.connect)(`wss://${host}/?authcode=${ticket}&ack=false&EIO=3`, { transports: ['websocket'] }), reconnect = () => {
129
+ const connection = connectSocketIo(`wss://${host}/?authcode=${ticket}&ack=false&EIO=3`, { transports: ['websocket'] }), reconnect = () => {
134
130
  if (this.reconnecting && this.connectionPromise) {
135
131
  return this.connectionPromise;
136
132
  }
137
133
  this.onConnected.next(false);
138
134
  if (!this.disconnected) {
139
- (0, util_1.logInfo)('Reconnecting location socket.io connection');
135
+ logInfo('Reconnecting location socket.io connection');
140
136
  }
141
137
  this.reconnecting = true;
142
138
  connection.close();
143
- return (this.connectionPromise = (0, util_1.delay)(1000).then(() => {
139
+ return (this.connectionPromise = delay(1000).then(() => {
144
140
  return this.createConnection();
145
141
  }));
146
142
  };
147
143
  this.reconnecting = false;
148
144
  connection.on('DataUpdate', (message) => {
149
145
  if (message.datatype === 'HubDisconnectionEventType') {
150
- (0, util_1.logInfo)('Location connection told to reconnect');
146
+ logInfo('Location connection told to reconnect');
151
147
  return reconnect();
152
148
  }
153
149
  this.onDataUpdate.next(message);
@@ -159,7 +155,7 @@ class Location extends subscribed_1.Subscribed {
159
155
  connection.once('connect', () => {
160
156
  resolve(connection);
161
157
  this.onConnected.next(true);
162
- (0, util_1.logInfo)('Ring connected to socket.io server');
158
+ logInfo('Ring connected to socket.io server');
163
159
  assets.forEach((asset) => this.requestList(deviceListMessageType, asset.uuid));
164
160
  });
165
161
  connection.once('error', reject);
@@ -184,7 +180,7 @@ class Location extends subscribed_1.Subscribed {
184
180
  securityPanel.sendCommand(commandType, data);
185
181
  }
186
182
  async setAlarmMode(alarmMode, bypassSensorZids) {
187
- const securityPanel = await this.getSecurityPanel(), updatedDataPromise = (0, rxjs_1.firstValueFrom)(securityPanel.onData.pipe((0, operators_1.skip)(1)));
183
+ const securityPanel = await this.getSecurityPanel(), updatedDataPromise = firstValueFrom(securityPanel.onData.pipe(skip(1)));
188
184
  await this.sendCommandToSecurityPanel('security-panel.switch-mode', {
189
185
  mode: alarmMode,
190
186
  bypass: bypassSensorZids,
@@ -217,7 +213,7 @@ class Location extends subscribed_1.Subscribed {
217
213
  });
218
214
  }
219
215
  getNextMessageOfType(type, src) {
220
- return (0, rxjs_1.firstValueFrom)(this.onMessage.pipe((0, operators_1.filter)((m) => m.msg === type && m.src === src), (0, operators_1.map)((m) => m.body)));
216
+ return firstValueFrom(this.onMessage.pipe(filter((m) => m.msg === type && m.src === src), map((m) => m.body)));
221
217
  }
222
218
  requestList(listType, assetId) {
223
219
  return this.sendMessage({ msg: listType, dst: assetId });
@@ -233,7 +229,7 @@ class Location extends subscribed_1.Subscribed {
233
229
  if (!this.connectionPromise) {
234
230
  await this.getConnection();
235
231
  }
236
- return (0, rxjs_1.firstValueFrom)(this.onDevices);
232
+ return firstValueFrom(this.onDevices);
237
233
  }
238
234
  getRoomList(assetId) {
239
235
  return this.getList('RoomGetList', assetId);
@@ -243,7 +239,7 @@ class Location extends subscribed_1.Subscribed {
243
239
  return this.securityPanel;
244
240
  }
245
241
  const devices = await this.getDevices(), securityPanel = devices.find((device) => {
246
- return device.data.deviceType === ring_types_1.RingDeviceType.SecurityPanel;
242
+ return device.data.deviceType === RingDeviceType.SecurityPanel;
247
243
  });
248
244
  if (!securityPanel) {
249
245
  throw new Error(`Could not find a security panel for location ${this.name} - ${this.id}`);
@@ -262,7 +258,7 @@ class Location extends subscribed_1.Subscribed {
262
258
  getHistory(options = {}) {
263
259
  options.maxLevel = options.maxLevel || 50;
264
260
  return this.restClient.request({
265
- url: (0, rest_client_1.appApi)(`rs/history${(0, ring_camera_1.getSearchQueryString)({
261
+ url: appApi(`rs/history${getSearchQueryString({
266
262
  accountId: this.id,
267
263
  ...options,
268
264
  })}`),
@@ -270,22 +266,22 @@ class Location extends subscribed_1.Subscribed {
270
266
  }
271
267
  getCameraEvents(options = {}) {
272
268
  return this.restClient.request({
273
- url: (0, rest_client_1.clientApi)(`locations/${this.id}/events${(0, ring_camera_1.getSearchQueryString)(options)}`),
269
+ url: clientApi(`locations/${this.id}/events${getSearchQueryString(options)}`),
274
270
  });
275
271
  }
276
272
  getAccountMonitoringStatus() {
277
273
  return this.restClient.request({
278
- url: (0, rest_client_1.appApi)('rs/monitoring/accounts/' + this.id),
274
+ url: appApi('rs/monitoring/accounts/' + this.id),
279
275
  });
280
276
  }
281
277
  triggerAlarm(signalType) {
282
- const now = Date.now(), alarmSessionUuid = (0, util_1.generateUuid)(), baseStationAsset = this.assets && this.assets.find((x) => x.kind === 'base_station_v1');
278
+ const now = Date.now(), alarmSessionUuid = generateUuid(), baseStationAsset = this.assets && this.assets.find((x) => x.kind === 'base_station_v1');
283
279
  if (!baseStationAsset) {
284
280
  throw new Error('Cannot dispatch panic events without an alarm base station');
285
281
  }
286
282
  return this.restClient.request({
287
283
  method: 'POST',
288
- url: (0, rest_client_1.appApi)(`rs/monitoring/accounts/${this.id}/assets/${baseStationAsset.uuid}/userAlarm`),
284
+ url: appApi(`rs/monitoring/accounts/${this.id}/assets/${baseStationAsset.uuid}/userAlarm`),
289
285
  json: {
290
286
  alarmSessionUuid,
291
287
  currentTsMs: now,
@@ -295,16 +291,16 @@ class Location extends subscribed_1.Subscribed {
295
291
  });
296
292
  }
297
293
  triggerBurglarAlarm() {
298
- return this.triggerAlarm(ring_types_1.DispatchSignalType.Burglar);
294
+ return this.triggerAlarm(DispatchSignalType.Burglar);
299
295
  }
300
296
  triggerFireAlarm() {
301
- return this.triggerAlarm(ring_types_1.DispatchSignalType.Fire);
297
+ return this.triggerAlarm(DispatchSignalType.Fire);
302
298
  }
303
299
  async getLocationMode() {
304
300
  this.onLocationModeRequested.next(null);
305
301
  const response = await this.restClient.request({
306
302
  method: 'GET',
307
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}`),
303
+ url: appApi(`mode/location/${this.id}`),
308
304
  });
309
305
  this.onLocationMode.next(response.mode);
310
306
  return response;
@@ -312,7 +308,7 @@ class Location extends subscribed_1.Subscribed {
312
308
  async setLocationMode(mode) {
313
309
  const response = await this.restClient.request({
314
310
  method: 'POST',
315
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}`),
311
+ url: appApi(`mode/location/${this.id}`),
316
312
  json: { mode },
317
313
  });
318
314
  this.onLocationMode.next(response.mode);
@@ -321,14 +317,14 @@ class Location extends subscribed_1.Subscribed {
321
317
  async disableLocationModes() {
322
318
  await this.restClient.request({
323
319
  method: 'DELETE',
324
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings`),
320
+ url: appApi(`mode/location/${this.id}/settings`),
325
321
  });
326
322
  this.onLocationMode.next('disabled');
327
323
  }
328
324
  async enableLocationModes() {
329
325
  const response = await this.restClient.request({
330
326
  method: 'POST',
331
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings/setup`),
327
+ url: appApi(`mode/location/${this.id}/settings/setup`),
332
328
  });
333
329
  await this.getLocationMode();
334
330
  return response;
@@ -336,26 +332,26 @@ class Location extends subscribed_1.Subscribed {
336
332
  getLocationModeSettings() {
337
333
  return this.restClient.request({
338
334
  method: 'GET',
339
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings`),
335
+ url: appApi(`mode/location/${this.id}/settings`),
340
336
  });
341
337
  }
342
338
  setLocationModeSettings(settings) {
343
339
  return this.restClient.request({
344
340
  method: 'POST',
345
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings`),
341
+ url: appApi(`mode/location/${this.id}/settings`),
346
342
  json: settings,
347
343
  });
348
344
  }
349
345
  getLocationModeSharing() {
350
346
  return this.restClient.request({
351
347
  method: 'GET',
352
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/sharing`),
348
+ url: appApi(`mode/location/${this.id}/sharing`),
353
349
  });
354
350
  }
355
351
  setLocationModeSharing(sharedUsersEnabled) {
356
352
  return this.restClient.request({
357
353
  method: 'POST',
358
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/sharing`),
354
+ url: appApi(`mode/location/${this.id}/sharing`),
359
355
  json: { sharedUsersEnabled },
360
356
  });
361
357
  }
@@ -364,8 +360,8 @@ class Location extends subscribed_1.Subscribed {
364
360
  return false;
365
361
  }
366
362
  const modeResponse = await this.getLocationMode(), { mode, readOnly } = modeResponse;
367
- (0, util_1.logDebug)('Location Mode: ' + JSON.stringify(modeResponse));
368
- return !readOnly && !ring_types_1.disabledLocationModes.includes(mode);
363
+ logDebug('Location Mode: ' + JSON.stringify(modeResponse));
364
+ return !readOnly && !disabledLocationModes.includes(mode);
369
365
  }
370
366
  disconnect() {
371
367
  this.disconnected = true;
@@ -375,12 +371,11 @@ class Location extends subscribed_1.Subscribed {
375
371
  .then((devices) => {
376
372
  devices.forEach((device) => device.disconnect());
377
373
  })
378
- .catch(util_1.logError);
374
+ .catch(logError);
379
375
  if (this.connectionPromise) {
380
376
  this.connectionPromise
381
377
  .then((connection) => connection.close())
382
- .catch(util_1.logError);
378
+ .catch(logError);
383
379
  }
384
380
  }
385
381
  }
386
- exports.Location = Location;
@@ -1,13 +1,9 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.acquireRefreshToken = acquireRefreshToken;
4
- exports.logRefreshToken = logRefreshToken;
5
1
  /* eslint-disable no-console */
6
- const rest_client_1 = require("./rest-client");
7
- const util_1 = require("./util");
8
- async function acquireRefreshToken() {
9
- const email = await (0, util_1.requestInput)('Email: '), password = await (0, util_1.requestInput)('Password: '), restClient = new rest_client_1.RingRestClient({ email, password }), getAuthWith2fa = async () => {
10
- const code = await (0, util_1.requestInput)('2fa Code: ');
2
+ import { RingRestClient } from "./rest-client.js";
3
+ import { requestInput } from "./util.js";
4
+ export async function acquireRefreshToken() {
5
+ const email = await requestInput('Email: '), password = await requestInput('Password: '), restClient = new RingRestClient({ email, password }), getAuthWith2fa = async () => {
6
+ const code = await requestInput('2fa Code: ');
11
7
  try {
12
8
  return await restClient.getAuth(code);
13
9
  }
@@ -25,11 +21,10 @@ async function acquireRefreshToken() {
25
21
  });
26
22
  return auth.refresh_token;
27
23
  }
28
- async function logRefreshToken() {
24
+ export async function logRefreshToken() {
29
25
  console.log('This CLI will provide you with a refresh token which you can use to configure ring-client-api and homebridge-ring.');
30
26
  const refreshToken = await acquireRefreshToken();
31
27
  console.log('\nSuccessfully logged in to Ring. Please add the following to your config:\n');
32
28
  console.log(`"refreshToken": "${refreshToken}"`);
33
29
  }
34
- // eslint-disable-next-line @typescript-eslint/no-empty-function
35
30
  process.on('unhandledRejection', () => { });
@@ -1,6 +1,6 @@
1
- import { AuthTokenResponse, SessionResponse } from './ring-types';
1
+ import type { AuthTokenResponse, SessionResponse } from './ring-types.ts';
2
2
  import { ReplaySubject } from 'rxjs';
3
- import type { Credentials } from '@eneris/push-receiver/dist/types';
3
+ import type { Credentials } from '@eneris/push-receiver/dist/types.d.js';
4
4
  import { Agent } from 'undici';
5
5
  interface RequestOptions extends RequestInit {
6
6
  responseType?: 'json' | 'buffer';
@@ -29,7 +29,6 @@ export interface SessionOptions {
29
29
  controlCenterDisplayName?: string;
30
30
  }
31
31
  export declare class RingRestClient {
32
- private authOptions;
33
32
  refreshToken: string | undefined;
34
33
  private authConfig;
35
34
  private hardwareIdPromise;
@@ -44,11 +43,12 @@ export declare class RingRestClient {
44
43
  oldRefreshToken?: string;
45
44
  newRefreshToken: string;
46
45
  }>;
47
- onSession: ReplaySubject<import("./ring-types").ProfileResponse>;
46
+ onSession: ReplaySubject<import("./ring-types.ts").ProfileResponse>;
48
47
  readonly baseSessionMetadata: {
49
48
  api_version: number;
50
49
  device_model: string;
51
50
  };
51
+ private authOptions;
52
52
  constructor(authOptions: (EmailAuth | RefreshTokenAuth) & SessionOptions);
53
53
  private getGrantData;
54
54
  getAuth(twoFactorAuthCode?: string): Promise<AuthTokenResponse>;
@@ -1,18 +1,8 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.RingRestClient = void 0;
7
- exports.clientApi = clientApi;
8
- exports.deviceApi = deviceApi;
9
- exports.commandsApi = commandsApi;
10
- exports.appApi = appApi;
11
- const util_1 = require("./util");
12
- const rxjs_1 = require("rxjs");
13
- const assert_1 = __importDefault(require("assert"));
14
- const undici_1 = require("undici");
15
- const fetchAgent = new undici_1.Agent({
1
+ import { delay, fromBase64, getHardwareId, logDebug, logError, logInfo, stringify, toBase64, } from "./util.js";
2
+ import { ReplaySubject } from 'rxjs';
3
+ import assert from 'assert';
4
+ import { Agent } from 'undici';
5
+ const fetchAgent = new Agent({
16
6
  connections: 6,
17
7
  pipelining: 1,
18
8
  keepAliveTimeout: 115000,
@@ -27,16 +17,16 @@ const fetchAgent = new undici_1.Agent({
27
17
  7062: 'UPDATING',
28
18
  7063: 'MAINTENANCE',
29
19
  }, clientApiBaseUrl = 'https://api.ring.com/clients_api/', deviceApiBaseUrl = 'https://api.ring.com/devices/v1/', commandsApiBaseUrl = 'https://api.ring.com/commands/v1/', appApiBaseUrl = 'https://prd-api-us.prd.rings.solutions/api/v1/', apiVersion = 11;
30
- function clientApi(path) {
20
+ export function clientApi(path) {
31
21
  return clientApiBaseUrl + path;
32
22
  }
33
- function deviceApi(path) {
23
+ export function deviceApi(path) {
34
24
  return deviceApiBaseUrl + path;
35
25
  }
36
- function commandsApi(path) {
26
+ export function commandsApi(path) {
37
27
  return commandsApiBaseUrl + path;
38
28
  }
39
- function appApi(path) {
29
+ export function appApi(path) {
40
30
  return appApiBaseUrl + path;
41
31
  }
42
32
  async function responseToError(response) {
@@ -123,13 +113,13 @@ async function requestWithRetry(requestOptions, retryCount = 0) {
123
113
  let detailedError = `Error: ${e.message}`;
124
114
  detailedError += e.cause?.message ? `, Cause: ${e.cause.message}` : '';
125
115
  detailedError += e.cause?.code ? `, Code: ${e.cause.code}` : '';
126
- (0, util_1.logError)(`Retry #${retryCount} failed to reach Ring server at ${requestOptions.url}. ${detailedError}. Trying again in 5 seconds...`);
116
+ logError(`Retry #${retryCount} failed to reach Ring server at ${requestOptions.url}. ${detailedError}. Trying again in 5 seconds...`);
127
117
  if (e.message.includes('NGHTTP2_ENHANCE_YOUR_CALM')) {
128
- (0, util_1.logError)(`There is a known issue with your current NodeJS version (${process.version}). Please see https://github.com/dgreif/ring/wiki/NGHTTP2_ENHANCE_YOUR_CALM-Error for details`);
118
+ logError(`There is a known issue with your current NodeJS version (${process.version}). Please see https://github.com/dgreif/ring/wiki/NGHTTP2_ENHANCE_YOUR_CALM-Error for details`);
129
119
  }
130
- (0, util_1.logDebug)(e);
120
+ logDebug(e);
131
121
  }
132
- await (0, util_1.delay)(5000);
122
+ await delay(5000);
133
123
  return requestWithRetry(requestOptions, retryCount + 1);
134
124
  }
135
125
  throw e;
@@ -140,9 +130,9 @@ function parseAuthConfig(rawRefreshToken) {
140
130
  return;
141
131
  }
142
132
  try {
143
- const config = JSON.parse((0, util_1.fromBase64)(rawRefreshToken));
144
- (0, assert_1.default)(config);
145
- (0, assert_1.default)(config.rt);
133
+ const config = JSON.parse(fromBase64(rawRefreshToken));
134
+ assert(config);
135
+ assert(config.rt);
146
136
  return config;
147
137
  }
148
138
  catch {
@@ -151,8 +141,7 @@ function parseAuthConfig(rawRefreshToken) {
151
141
  };
152
142
  }
153
143
  }
154
- class RingRestClient {
155
- authOptions;
144
+ export class RingRestClient {
156
145
  refreshToken;
157
146
  authConfig;
158
147
  hardwareIdPromise;
@@ -184,16 +173,17 @@ class RingRestClient {
184
173
  sessionPromise = undefined;
185
174
  using2fa = false;
186
175
  promptFor2fa;
187
- onRefreshTokenUpdated = new rxjs_1.ReplaySubject(1);
188
- onSession = new rxjs_1.ReplaySubject(1);
176
+ onRefreshTokenUpdated = new ReplaySubject(1);
177
+ onSession = new ReplaySubject(1);
189
178
  baseSessionMetadata;
179
+ authOptions;
190
180
  constructor(authOptions) {
191
181
  this.authOptions = authOptions;
192
182
  this.refreshToken =
193
183
  'refreshToken' in authOptions ? authOptions.refreshToken : undefined;
194
184
  this.authConfig = parseAuthConfig(this.refreshToken);
195
185
  this.hardwareIdPromise =
196
- this.authConfig?.hid || (0, util_1.getHardwareId)(authOptions.systemId);
186
+ this.authConfig?.hid || getHardwareId(authOptions.systemId);
197
187
  this.baseSessionMetadata = {
198
188
  api_version: apiVersion,
199
189
  device_model: authOptions.controlCenterDisplayName ?? 'ring-client-api',
@@ -240,7 +230,7 @@ class RingRestClient {
240
230
  rt: response.refresh_token,
241
231
  hid: hardwareId,
242
232
  };
243
- this.refreshToken = (0, util_1.toBase64)(JSON.stringify(this.authConfig));
233
+ this.refreshToken = toBase64(JSON.stringify(this.authConfig));
244
234
  // Emit an event with the new token
245
235
  this.onRefreshTokenUpdated.next({
246
236
  oldRefreshToken,
@@ -257,7 +247,7 @@ class RingRestClient {
257
247
  // failed request with refresh token
258
248
  this.refreshToken = undefined;
259
249
  this.authConfig = undefined;
260
- (0, util_1.logError)(requestError);
250
+ logError(requestError);
261
251
  return this.getAuth();
262
252
  }
263
253
  const response = requestError.response || {}, responseData = response.body || {}, responseError = 'error' in responseData && typeof responseData.error === 'string'
@@ -292,8 +282,8 @@ class RingRestClient {
292
282
  ? 'You have requested too many 2fa codes. Ring limits 2fa to 10 codes within 10 minutes. Please try again in 10 minutes.'
293
283
  : `Verify that your ${authTypeMessage} correct.`) +
294
284
  ` (error: ${responseError})`;
295
- (0, util_1.logError)(requestError.response || requestError);
296
- (0, util_1.logError)(errorMessage);
285
+ logError(requestError.response || requestError);
286
+ logError(errorMessage);
297
287
  throw new Error(errorMessage);
298
288
  }
299
289
  }
@@ -330,9 +320,9 @@ class RingRestClient {
330
320
  const retryAfter = e.response.headers.get('retry-after'), waitSeconds = isNaN(retryAfter)
331
321
  ? 200
332
322
  : Number.parseInt(retryAfter, 10);
333
- (0, util_1.logError)(`Session response rate limited. Waiting to retry after ${waitSeconds} seconds`);
334
- await (0, util_1.delay)((waitSeconds + 1) * 1000);
335
- (0, util_1.logInfo)('Retrying session request');
323
+ logError(`Session response rate limited. Waiting to retry after ${waitSeconds} seconds`);
324
+ await delay((waitSeconds + 1) * 1000);
325
+ logInfo('Retrying session request');
336
326
  return this.getSession();
337
327
  }
338
328
  throw e;
@@ -355,7 +345,7 @@ class RingRestClient {
355
345
  }, 12 * 60 * 60 * 1000); // 12 hours
356
346
  this.timeouts.push(timeout);
357
347
  })
358
- .catch((e) => (0, util_1.logError)(e));
348
+ .catch((e) => logError(e));
359
349
  }
360
350
  async request(options) {
361
351
  const hardwareId = await this.hardwareIdPromise, url = options.url, initialSessionPromise = this.sessionPromise;
@@ -380,7 +370,7 @@ class RingRestClient {
380
370
  }
381
371
  if (response.status === 504) {
382
372
  // Gateway Timeout. These should be recoverable, but wait a few seconds just to be on the safe side
383
- await (0, util_1.delay)(5000);
373
+ await delay(5000);
384
374
  return this.request(options);
385
375
  }
386
376
  if (response.status === 404 &&
@@ -391,29 +381,29 @@ class RingRestClient {
391
381
  .filter((x) => x)
392
382
  .join(', ');
393
383
  if (errorText) {
394
- (0, util_1.logError)(`http request failed. ${url} returned errors: (${errorText}). Trying again in 20 seconds`);
395
- await (0, util_1.delay)(20000);
384
+ logError(`http request failed. ${url} returned errors: (${errorText}). Trying again in 20 seconds`);
385
+ await delay(20000);
396
386
  return this.request(options);
397
387
  }
398
- (0, util_1.logError)(`http request failed. ${url} returned unknown errors: (${(0, util_1.stringify)(errors)}).`);
388
+ logError(`http request failed. ${url} returned unknown errors: (${stringify(errors)}).`);
399
389
  }
400
390
  if (response.status === 404 && url.startsWith(clientApiBaseUrl)) {
401
- (0, util_1.logError)('404 from endpoint ' + url);
391
+ logError('404 from endpoint ' + url);
402
392
  if (response.body?.error?.includes(hardwareId)) {
403
- (0, util_1.logError)('Session hardware_id not found. Creating a new session and trying again.');
393
+ logError('Session hardware_id not found. Creating a new session and trying again.');
404
394
  if (this.sessionPromise === initialSessionPromise) {
405
395
  this.refreshSession();
406
396
  }
407
397
  return this.request(options);
408
398
  }
409
- throw new Error('Not found with response: ' + (0, util_1.stringify)(response.body));
399
+ throw new Error('Not found with response: ' + stringify(response.body));
410
400
  }
411
401
  if (response.status) {
412
- (0, util_1.logError)(`Request to ${url} failed with status ${response.status}. Response body: ${(0, util_1.stringify)(response.body)}`);
402
+ logError(`Request to ${url} failed with status ${response.status}. Response body: ${stringify(response.body)}`);
413
403
  }
414
404
  else if (!options.allowNoResponse) {
415
- (0, util_1.logError)(`Request to ${url} failed:`);
416
- (0, util_1.logError)(e);
405
+ logError(`Request to ${url} failed:`);
406
+ logError(e);
417
407
  }
418
408
  throw e;
419
409
  }
@@ -437,7 +427,7 @@ class RingRestClient {
437
427
  pnc: credentials,
438
428
  };
439
429
  // SOMEDAY: refactor the conversion from auth config to refresh token - DRY from above
440
- const newRefreshToken = (0, util_1.toBase64)(JSON.stringify(this.authConfig));
430
+ const newRefreshToken = toBase64(JSON.stringify(this.authConfig));
441
431
  if (newRefreshToken === oldRefreshToken) {
442
432
  // No change, so we don't need to emit an updated refresh token
443
433
  return;
@@ -450,4 +440,3 @@ class RingRestClient {
450
440
  });
451
441
  }
452
442
  }
453
- exports.RingRestClient = RingRestClient;
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const refresh_token_1 = require("./refresh-token");
5
- (0, refresh_token_1.logRefreshToken)().catch((e) => {
2
+ import { logRefreshToken } from "./refresh-token.js";
3
+ logRefreshToken().catch((e) => {
6
4
  // eslint-disable-next-line no-console
7
5
  console.error(e);
8
6
  process.exit(1);