ring-client-api 13.2.1-beta.1 → 14.0.0-beta.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.
Files changed (40) hide show
  1. package/lib/api.d.ts +9 -7
  2. package/lib/api.js +56 -63
  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 +22 -21
  8. package/lib/location.js +61 -65
  9. package/lib/refresh-token.js +6 -10
  10. package/lib/rest-client.d.ts +3 -3
  11. package/lib/rest-client.js +39 -50
  12. package/lib/ring-auth-cli.js +2 -4
  13. package/lib/ring-camera.d.ts +21 -18
  14. package/lib/ring-camera.js +57 -56
  15. package/lib/ring-chime.d.ts +5 -5
  16. package/lib/ring-chime.js +10 -14
  17. package/lib/ring-device-data-cli.js +2 -4
  18. package/lib/ring-device.d.ts +4 -4
  19. package/lib/ring-device.js +12 -16
  20. package/lib/ring-intercom.d.ts +6 -6
  21. package/lib/ring-intercom.js +19 -23
  22. package/lib/ring-types.d.ts +2 -0
  23. package/lib/ring-types.js +24 -24
  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 +2 -2
  27. package/lib/streaming/simple-webrtc-session.js +3 -7
  28. package/lib/streaming/streaming-messages.js +1 -2
  29. package/lib/streaming/streaming-session.d.ts +3 -3
  30. package/lib/streaming/streaming-session.js +34 -38
  31. package/lib/streaming/webrtc-connection.d.ts +4 -4
  32. package/lib/streaming/webrtc-connection.js +38 -42
  33. package/lib/subscribed.d.ts +1 -1
  34. package/lib/subscribed.js +1 -5
  35. package/lib/util.js +33 -54
  36. package/package.json +14 -16
  37. package/lib/test/rest-client.spec.d.ts +0 -1
  38. package/lib/test/rest-client.spec.js +0 -242
  39. package/lib/test/ring-camera.spec.d.ts +0 -1
  40. package/lib/test/ring-camera.spec.js +0 -37
package/lib/location.js CHANGED
@@ -1,20 +1,17 @@
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 {
14
+ export class Location extends Subscribed {
18
15
  locationDetails;
19
16
  cameras;
20
17
  chimes;
@@ -22,13 +19,13 @@ class Location extends subscribed_1.Subscribed {
22
19
  options;
23
20
  restClient;
24
21
  seq = 1;
25
- onMessage = new rxjs_1.Subject();
26
- onDataUpdate = new rxjs_1.Subject();
27
- onDeviceDataUpdate = this.onDataUpdate.pipe((0, operators_1.filter)((message) => {
22
+ onMessage = new Subject();
23
+ onDataUpdate = new Subject();
24
+ onDeviceDataUpdate = this.onDataUpdate.pipe(filter((message) => {
28
25
  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 }) => {
26
+ }), concatMap((message) => message.body), map(flattenDeviceData));
27
+ onDeviceList = this.onMessage.pipe(filter((m) => m.msg === deviceListMessageType));
28
+ onDevices = this.onDeviceList.pipe(scan((devices, { body: deviceList, src }) => {
32
29
  if (!deviceList) {
33
30
  return devices;
34
31
  }
@@ -41,16 +38,16 @@ class Location extends subscribed_1.Subscribed {
41
38
  existingDevice.updateData(flatData);
42
39
  return updatedDevices;
43
40
  }
44
- return [...updatedDevices, new ring_device_1.RingDevice(flatData, this, src)];
41
+ return [...updatedDevices, new RingDevice(flatData, this, src)];
45
42
  }, devices);
46
- }, []), (0, operators_1.distinctUntilChanged)((a, b) => a.length === b.length), (0, operators_1.filter)(() => {
43
+ }, []), distinctUntilChanged((a, b) => a.length === b.length), filter(() => {
47
44
  return Boolean(this.assets &&
48
45
  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();
46
+ }), shareReplay(1));
47
+ onSessionInfo = this.onDataUpdate.pipe(filter((m) => m.msg === 'SessionInfo'), map((m) => m.body));
48
+ onConnected = new BehaviorSubject(false);
49
+ onLocationMode = new ReplaySubject(1);
50
+ onLocationModeRequested = new Subject();
54
51
  reconnecting = false;
55
52
  disconnected = false;
56
53
  connectionPromise;
@@ -86,20 +83,20 @@ class Location extends subscribed_1.Subscribed {
86
83
  // eslint-disable-next-line @typescript-eslint/no-empty-function
87
84
  this.requestList(deviceListMessageType, assetUuid).catch(() => { });
88
85
  this.offlineAssets = this.offlineAssets.filter((id) => id !== assetUuid);
89
- (0, util_1.logInfo)(`Ring ${asset.kind} ${assetUuid} has come back online`);
86
+ logInfo(`Ring ${asset.kind} ${assetUuid} has come back online`);
90
87
  }
91
88
  }
92
89
  else if (!assetWasOffline) {
93
- (0, util_1.logError)(`Ring ${asset.kind} ${assetUuid} is offline or on cellular backup. Waiting for status to change`);
90
+ logError(`Ring ${asset.kind} ${assetUuid} is offline or on cellular backup. Waiting for status to change`);
94
91
  this.offlineAssets.push(assetUuid);
95
92
  }
96
93
  });
97
94
  }));
98
95
  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))
96
+ this.addSubscriptions(merge(this.onLocationModeRequested, this.onLocationMode)
97
+ .pipe(debounceTime(options.locationModePollingSeconds * 1000))
101
98
  .subscribe(() => this.getLocationMode()));
102
- this.getLocationMode().catch(util_1.logError);
99
+ this.getLocationMode().catch(logError);
103
100
  }
104
101
  }
105
102
  get id() {
@@ -115,39 +112,39 @@ class Location extends subscribed_1.Subscribed {
115
112
  if (this.disconnected) {
116
113
  return Promise.resolve({ disconnected: true });
117
114
  }
118
- (0, util_1.logInfo)('Creating location socket.io connection - ' + this.name);
115
+ logInfo('Creating location socket.io connection - ' + this.name);
119
116
  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.');
117
+ 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
118
  }
122
119
  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);
120
+ url: appApi('clap/tickets?locationID=' + this.id),
121
+ }), supportedAssets = assets.filter(isWebSocketSupportedAsset);
125
122
  this.assets = supportedAssets;
126
123
  this.receivedAssetDeviceLists.length = 0;
127
124
  this.offlineAssets.length = 0;
128
125
  if (!supportedAssets.length) {
129
126
  const errorMessage = `No assets (alarm hubs or beam bridges) found for location ${this.name} - ${this.id}`;
130
- (0, util_1.logError)(errorMessage);
127
+ logError(errorMessage);
131
128
  throw new Error(errorMessage);
132
129
  }
133
- const connection = (0, socket_io_client_1.connect)(`wss://${host}/?authcode=${ticket}&ack=false&EIO=3`, { transports: ['websocket'] }), reconnect = () => {
130
+ const connection = connectSocketIo(`wss://${host}/?authcode=${ticket}&ack=false&EIO=3`, { transports: ['websocket'] }), reconnect = () => {
134
131
  if (this.reconnecting && this.connectionPromise) {
135
132
  return this.connectionPromise;
136
133
  }
137
134
  this.onConnected.next(false);
138
135
  if (!this.disconnected) {
139
- (0, util_1.logInfo)('Reconnecting location socket.io connection');
136
+ logInfo('Reconnecting location socket.io connection');
140
137
  }
141
138
  this.reconnecting = true;
142
139
  connection.close();
143
- return (this.connectionPromise = (0, util_1.delay)(1000).then(() => {
140
+ return (this.connectionPromise = delay(1000).then(() => {
144
141
  return this.createConnection();
145
142
  }));
146
143
  };
147
144
  this.reconnecting = false;
148
145
  connection.on('DataUpdate', (message) => {
149
146
  if (message.datatype === 'HubDisconnectionEventType') {
150
- (0, util_1.logInfo)('Location connection told to reconnect');
147
+ logInfo('Location connection told to reconnect');
151
148
  return reconnect();
152
149
  }
153
150
  this.onDataUpdate.next(message);
@@ -159,7 +156,7 @@ class Location extends subscribed_1.Subscribed {
159
156
  connection.once('connect', () => {
160
157
  resolve(connection);
161
158
  this.onConnected.next(true);
162
- (0, util_1.logInfo)('Ring connected to socket.io server');
159
+ logInfo('Ring connected to socket.io server');
163
160
  assets.forEach((asset) => this.requestList(deviceListMessageType, asset.uuid));
164
161
  });
165
162
  connection.once('error', reject);
@@ -184,7 +181,7 @@ class Location extends subscribed_1.Subscribed {
184
181
  securityPanel.sendCommand(commandType, data);
185
182
  }
186
183
  async setAlarmMode(alarmMode, bypassSensorZids) {
187
- const securityPanel = await this.getSecurityPanel(), updatedDataPromise = (0, rxjs_1.firstValueFrom)(securityPanel.onData.pipe((0, operators_1.skip)(1)));
184
+ const securityPanel = await this.getSecurityPanel(), updatedDataPromise = firstValueFrom(securityPanel.onData.pipe(skip(1)));
188
185
  await this.sendCommandToSecurityPanel('security-panel.switch-mode', {
189
186
  mode: alarmMode,
190
187
  bypass: bypassSensorZids,
@@ -217,7 +214,7 @@ class Location extends subscribed_1.Subscribed {
217
214
  });
218
215
  }
219
216
  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)));
217
+ return firstValueFrom(this.onMessage.pipe(filter((m) => m.msg === type && m.src === src), map((m) => m.body)));
221
218
  }
222
219
  requestList(listType, assetId) {
223
220
  return this.sendMessage({ msg: listType, dst: assetId });
@@ -233,7 +230,7 @@ class Location extends subscribed_1.Subscribed {
233
230
  if (!this.connectionPromise) {
234
231
  await this.getConnection();
235
232
  }
236
- return (0, rxjs_1.firstValueFrom)(this.onDevices);
233
+ return firstValueFrom(this.onDevices);
237
234
  }
238
235
  getRoomList(assetId) {
239
236
  return this.getList('RoomGetList', assetId);
@@ -243,7 +240,7 @@ class Location extends subscribed_1.Subscribed {
243
240
  return this.securityPanel;
244
241
  }
245
242
  const devices = await this.getDevices(), securityPanel = devices.find((device) => {
246
- return device.data.deviceType === ring_types_1.RingDeviceType.SecurityPanel;
243
+ return device.data.deviceType === RingDeviceType.SecurityPanel;
247
244
  });
248
245
  if (!securityPanel) {
249
246
  throw new Error(`Could not find a security panel for location ${this.name} - ${this.id}`);
@@ -262,7 +259,7 @@ class Location extends subscribed_1.Subscribed {
262
259
  getHistory(options = {}) {
263
260
  options.maxLevel = options.maxLevel || 50;
264
261
  return this.restClient.request({
265
- url: (0, rest_client_1.appApi)(`rs/history${(0, ring_camera_1.getSearchQueryString)({
262
+ url: appApi(`rs/history${getSearchQueryString({
266
263
  accountId: this.id,
267
264
  ...options,
268
265
  })}`),
@@ -270,22 +267,22 @@ class Location extends subscribed_1.Subscribed {
270
267
  }
271
268
  getCameraEvents(options = {}) {
272
269
  return this.restClient.request({
273
- url: (0, rest_client_1.clientApi)(`locations/${this.id}/events${(0, ring_camera_1.getSearchQueryString)(options)}`),
270
+ url: clientApi(`locations/${this.id}/events${getSearchQueryString(options)}`),
274
271
  });
275
272
  }
276
273
  getAccountMonitoringStatus() {
277
274
  return this.restClient.request({
278
- url: (0, rest_client_1.appApi)('rs/monitoring/accounts/' + this.id),
275
+ url: appApi('rs/monitoring/accounts/' + this.id),
279
276
  });
280
277
  }
281
278
  triggerAlarm(signalType) {
282
- const now = Date.now(), alarmSessionUuid = (0, util_1.generateUuid)(), baseStationAsset = this.assets && this.assets.find((x) => x.kind === 'base_station_v1');
279
+ const now = Date.now(), alarmSessionUuid = generateUuid(), baseStationAsset = this.assets && this.assets.find((x) => x.kind === 'base_station_v1');
283
280
  if (!baseStationAsset) {
284
281
  throw new Error('Cannot dispatch panic events without an alarm base station');
285
282
  }
286
283
  return this.restClient.request({
287
284
  method: 'POST',
288
- url: (0, rest_client_1.appApi)(`rs/monitoring/accounts/${this.id}/assets/${baseStationAsset.uuid}/userAlarm`),
285
+ url: appApi(`rs/monitoring/accounts/${this.id}/assets/${baseStationAsset.uuid}/userAlarm`),
289
286
  json: {
290
287
  alarmSessionUuid,
291
288
  currentTsMs: now,
@@ -295,16 +292,16 @@ class Location extends subscribed_1.Subscribed {
295
292
  });
296
293
  }
297
294
  triggerBurglarAlarm() {
298
- return this.triggerAlarm(ring_types_1.DispatchSignalType.Burglar);
295
+ return this.triggerAlarm(DispatchSignalType.Burglar);
299
296
  }
300
297
  triggerFireAlarm() {
301
- return this.triggerAlarm(ring_types_1.DispatchSignalType.Fire);
298
+ return this.triggerAlarm(DispatchSignalType.Fire);
302
299
  }
303
300
  async getLocationMode() {
304
301
  this.onLocationModeRequested.next(null);
305
302
  const response = await this.restClient.request({
306
303
  method: 'GET',
307
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}`),
304
+ url: appApi(`mode/location/${this.id}`),
308
305
  });
309
306
  this.onLocationMode.next(response.mode);
310
307
  return response;
@@ -312,7 +309,7 @@ class Location extends subscribed_1.Subscribed {
312
309
  async setLocationMode(mode) {
313
310
  const response = await this.restClient.request({
314
311
  method: 'POST',
315
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}`),
312
+ url: appApi(`mode/location/${this.id}`),
316
313
  json: { mode },
317
314
  });
318
315
  this.onLocationMode.next(response.mode);
@@ -321,14 +318,14 @@ class Location extends subscribed_1.Subscribed {
321
318
  async disableLocationModes() {
322
319
  await this.restClient.request({
323
320
  method: 'DELETE',
324
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings`),
321
+ url: appApi(`mode/location/${this.id}/settings`),
325
322
  });
326
323
  this.onLocationMode.next('disabled');
327
324
  }
328
325
  async enableLocationModes() {
329
326
  const response = await this.restClient.request({
330
327
  method: 'POST',
331
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings/setup`),
328
+ url: appApi(`mode/location/${this.id}/settings/setup`),
332
329
  });
333
330
  await this.getLocationMode();
334
331
  return response;
@@ -336,26 +333,26 @@ class Location extends subscribed_1.Subscribed {
336
333
  getLocationModeSettings() {
337
334
  return this.restClient.request({
338
335
  method: 'GET',
339
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings`),
336
+ url: appApi(`mode/location/${this.id}/settings`),
340
337
  });
341
338
  }
342
339
  setLocationModeSettings(settings) {
343
340
  return this.restClient.request({
344
341
  method: 'POST',
345
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/settings`),
342
+ url: appApi(`mode/location/${this.id}/settings`),
346
343
  json: settings,
347
344
  });
348
345
  }
349
346
  getLocationModeSharing() {
350
347
  return this.restClient.request({
351
348
  method: 'GET',
352
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/sharing`),
349
+ url: appApi(`mode/location/${this.id}/sharing`),
353
350
  });
354
351
  }
355
352
  setLocationModeSharing(sharedUsersEnabled) {
356
353
  return this.restClient.request({
357
354
  method: 'POST',
358
- url: (0, rest_client_1.appApi)(`mode/location/${this.id}/sharing`),
355
+ url: appApi(`mode/location/${this.id}/sharing`),
359
356
  json: { sharedUsersEnabled },
360
357
  });
361
358
  }
@@ -364,8 +361,8 @@ class Location extends subscribed_1.Subscribed {
364
361
  return false;
365
362
  }
366
363
  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);
364
+ logDebug('Location Mode: ' + JSON.stringify(modeResponse));
365
+ return !readOnly && !disabledLocationModes.includes(mode);
369
366
  }
370
367
  disconnect() {
371
368
  this.disconnected = true;
@@ -375,12 +372,11 @@ class Location extends subscribed_1.Subscribed {
375
372
  .then((devices) => {
376
373
  devices.forEach((device) => device.disconnect());
377
374
  })
378
- .catch(util_1.logError);
375
+ .catch(logError);
379
376
  if (this.connectionPromise) {
380
377
  this.connectionPromise
381
378
  .then((connection) => connection.close())
382
- .catch(util_1.logError);
379
+ .catch(logError);
383
380
  }
384
381
  }
385
382
  }
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,7 +21,7 @@ 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');
@@ -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';
@@ -44,7 +44,7 @@ export declare class RingRestClient {
44
44
  oldRefreshToken?: string;
45
45
  newRefreshToken: string;
46
46
  }>;
47
- onSession: ReplaySubject<import("./ring-types").ProfileResponse>;
47
+ onSession: ReplaySubject<import("./ring-types.ts").ProfileResponse>;
48
48
  readonly baseSessionMetadata: {
49
49
  api_version: number;
50
50
  device_model: string;
@@ -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,7 +141,7 @@ function parseAuthConfig(rawRefreshToken) {
151
141
  };
152
142
  }
153
143
  }
154
- class RingRestClient {
144
+ export class RingRestClient {
155
145
  authOptions;
156
146
  refreshToken;
157
147
  authConfig;
@@ -184,8 +174,8 @@ class RingRestClient {
184
174
  sessionPromise = undefined;
185
175
  using2fa = false;
186
176
  promptFor2fa;
187
- onRefreshTokenUpdated = new rxjs_1.ReplaySubject(1);
188
- onSession = new rxjs_1.ReplaySubject(1);
177
+ onRefreshTokenUpdated = new ReplaySubject(1);
178
+ onSession = new ReplaySubject(1);
189
179
  baseSessionMetadata;
190
180
  constructor(authOptions) {
191
181
  this.authOptions = authOptions;
@@ -193,7 +183,7 @@ class RingRestClient {
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);