ring-client-api 13.0.1 → 13.1.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.
@@ -42,7 +42,8 @@ export declare enum RingDeviceType {
42
42
  UnknownZWave = "unknown.zwave",
43
43
  OnvifCamera = "onvif_camera",
44
44
  ThirdPartyGarageDoorOpener = "third_party_gdo",
45
- IntercomHandsetAudio = "intercom_handset_audio"
45
+ IntercomHandsetAudio = "intercom_handset_audio",
46
+ WaterValve = "valve.water"
46
47
  }
47
48
  export declare enum RingDeviceCategory {
48
49
  Outlets = 1,
@@ -61,7 +62,8 @@ export declare enum RingDeviceCategory {
61
62
  RangeExtenders = 32,
62
63
  Keypads = 33,
63
64
  Sirens = 34,
64
- PanicButtons = 35
65
+ PanicButtons = 35,
66
+ WaterValves = 37
65
67
  }
66
68
  export declare enum RingCameraKind {
67
69
  doorbot = "doorbot",
@@ -187,6 +189,7 @@ export interface RingDeviceData {
187
189
  }[];
188
190
  motionSensorEnabled?: boolean;
189
191
  brightness?: number;
192
+ valveState?: 'open' | 'closed';
190
193
  }
191
194
  export declare const deviceTypesWithVolume: RingDeviceType[];
192
195
  export interface BaseStation {
package/lib/ring-types.js CHANGED
@@ -52,6 +52,7 @@ var RingDeviceType;
52
52
  RingDeviceType["OnvifCamera"] = "onvif_camera";
53
53
  RingDeviceType["ThirdPartyGarageDoorOpener"] = "third_party_gdo";
54
54
  RingDeviceType["IntercomHandsetAudio"] = "intercom_handset_audio";
55
+ RingDeviceType["WaterValve"] = "valve.water";
55
56
  })(RingDeviceType || (exports.RingDeviceType = RingDeviceType = {}));
56
57
  // eslint-disable-next-line no-shadow
57
58
  var RingDeviceCategory;
@@ -73,6 +74,7 @@ var RingDeviceCategory;
73
74
  RingDeviceCategory[RingDeviceCategory["Keypads"] = 33] = "Keypads";
74
75
  RingDeviceCategory[RingDeviceCategory["Sirens"] = 34] = "Sirens";
75
76
  RingDeviceCategory[RingDeviceCategory["PanicButtons"] = 35] = "PanicButtons";
77
+ RingDeviceCategory[RingDeviceCategory["WaterValves"] = 37] = "WaterValves";
76
78
  })(RingDeviceCategory || (exports.RingDeviceCategory = RingDeviceCategory = {}));
77
79
  // eslint-disable-next-line no-shadow
78
80
  var RingCameraKind;
@@ -110,6 +112,7 @@ var RingCameraKind;
110
112
  RingCameraKind["stickup_cam_mini"] = "stickup_cam_mini";
111
113
  RingCameraKind["onvif_camera"] = "onvif_camera";
112
114
  })(RingCameraKind || (exports.RingCameraKind = RingCameraKind = {}));
115
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
113
116
  exports.RingCameraModel = {
114
117
  doorbot: 'Doorbell',
115
118
  doorbell: 'Doorbell',
@@ -159,6 +162,7 @@ exports.deviceTypesWithVolume = [
159
162
  RingDeviceType.BaseStation,
160
163
  RingDeviceType.Keypad,
161
164
  ];
165
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
162
166
  exports.ChimeModel = {
163
167
  chime: 'Chime',
164
168
  chime_pro: 'Chime Pro',
@@ -22,7 +22,7 @@ export declare class WeriftPeerConnection extends Subscribed implements BasicPee
22
22
  onVideoRtp: Subject<RtpPacket>;
23
23
  onVideoRtcp: Subject<RtcpPacket>;
24
24
  onIceCandidate: Subject<RTCIceCandidate>;
25
- onConnectionState: ReplaySubject<"connected" | "closed" | "failed" | "disconnected" | "new" | "connecting">;
25
+ onConnectionState: ReplaySubject<"closed" | "connected" | "failed" | "disconnected" | "new" | "connecting">;
26
26
  returnAudioTrack: MediaStreamTrack;
27
27
  private onRequestKeyFrame;
28
28
  constructor();
@@ -6,105 +6,104 @@ const rest_client_1 = require("../rest-client");
6
6
  const util_1 = require("../util");
7
7
  const rxjs_1 = require("rxjs");
8
8
  let sessionCreatedCount = 0, client;
9
- const email = 'some@one.com', password = 'abc123!', phone = '+1xxxxxxxx89', twoFactorAuthCode = '123456', hardwareIdPromise = (0, util_1.getHardwareId)(), accessToken = 'ey__accees_token', secondAccessToken = 'ey__second_accees_token', refreshToken = 'ey__refresh_token', secondRefreshToken = 'ey__second_refresh_token', thirdRefreshToken = 'ey__third_refresh_token', server = (0, node_1.setupServer)(msw_1.rest.post('https://oauth.ring.com/oauth/token', async (req, res, ctx) => {
9
+ const email = 'some@one.com', password = 'abc123!', phone = '+1xxxxxxxx89', twoFactorAuthCode = '123456', hardwareIdPromise = (0, util_1.getHardwareId)(), accessToken = 'ey__accees_token', secondAccessToken = 'ey__second_accees_token', refreshToken = 'ey__refresh_token', secondRefreshToken = 'ey__second_refresh_token', thirdRefreshToken = 'ey__third_refresh_token', server = (0, node_1.setupServer)(msw_1.http.post('https://oauth.ring.com/oauth/token', async ({ request: req }) => {
10
10
  const body = await req.json();
11
11
  if (req.headers.get('2fa-support') !== 'true' ||
12
12
  req.headers.get('User-Agent') !== 'android:com.ringapp' ||
13
13
  req.headers.get('hardware_id') !== (await hardwareIdPromise)) {
14
- return res(ctx.status(400), ctx.json({
14
+ return msw_1.HttpResponse.json({
15
15
  code: 1,
16
- error: 'Invalid auth headers: ' +
17
- JSON.stringify(req.headers.raw(), null, 2),
18
- }));
16
+ error: 'Invalid auth headers: ' + JSON.stringify(req.headers, null, 2),
17
+ }, { status: 400 });
19
18
  }
20
19
  if (body.grant_type === 'refresh_token') {
21
20
  if (body.refresh_token === refreshToken) {
22
21
  // Valid refresh token
23
- return res(ctx.status(200), ctx.json({
22
+ return msw_1.HttpResponse.json({
24
23
  access_token: accessToken,
25
24
  expires_in: 3600,
26
25
  refresh_token: secondRefreshToken,
27
26
  scope: 'client',
28
27
  token_type: 'Bearer',
29
- }));
28
+ }, { status: 200 });
30
29
  }
31
30
  if (body.refresh_token === secondRefreshToken) {
32
31
  // Valid refresh token
33
- return res(ctx.status(200), ctx.json({
32
+ return msw_1.HttpResponse.json({
34
33
  access_token: secondAccessToken,
35
34
  expires_in: 3600,
36
35
  refresh_token: thirdRefreshToken,
37
36
  scope: 'client',
38
37
  token_type: 'Bearer',
39
- }));
38
+ }, { status: 200 });
40
39
  }
41
40
  // Invalid refresh token
42
- return res(ctx.status(401), ctx.json({
41
+ return msw_1.HttpResponse.json({
43
42
  error: 'invalid_grant',
44
43
  error_description: 'token is invalid or does not exists',
45
- }));
44
+ }, { status: 401 });
46
45
  }
47
46
  if (body.grant_type !== 'password' ||
48
47
  body.client_id !== 'ring_official_android' ||
49
48
  body.scope !== 'client') {
50
- return res(ctx.status(400), ctx.json({
49
+ return msw_1.HttpResponse.json({
51
50
  code: 1,
52
51
  error: 'Invalid auth request: ' + JSON.stringify(body),
53
- }));
52
+ }, { status: 400 });
54
53
  }
55
54
  if (body.username !== email || body.password !== password) {
56
55
  // Wrong username or password
57
- return res(ctx.status(401), ctx.json({
56
+ return msw_1.HttpResponse.json({
58
57
  error: 'access_denied',
59
58
  error_description: 'invalid user credentials',
60
- }));
59
+ }, { status: 401 });
61
60
  }
62
61
  if (req.headers.get('2fa-code') &&
63
62
  req.headers.get('2fa-code') !== twoFactorAuthCode) {
64
63
  // Wrong 2fa code
65
- return res(ctx.status(400), ctx.json({
64
+ return msw_1.HttpResponse.json({
66
65
  err_msg: 'bad request response from dependency service',
67
66
  error: 'Verification Code is invalid or expired',
68
- }));
67
+ }, { status: 400 });
69
68
  }
70
69
  if (req.headers.get('2fa-code') === twoFactorAuthCode) {
71
70
  // Successfull login with correct 2fa code
72
- return res(ctx.json({
71
+ return msw_1.HttpResponse.json({
73
72
  access_token: accessToken,
74
73
  expires_in: 3600,
75
74
  refresh_token: refreshToken,
76
75
  scope: 'client',
77
76
  token_type: 'Bearer',
78
77
  responseTimestamp: Date.now(),
79
- }));
78
+ });
80
79
  }
81
80
  // 2fa code not provided, so return the 2fa prompt
82
- return res(ctx.status(412), ctx.json({
81
+ return msw_1.HttpResponse.json({
83
82
  next_time_in_secs: 60,
84
83
  phone,
85
84
  tsv_state: 'sms',
86
- }));
87
- }), msw_1.rest.post('https://api.ring.com/clients_api/session', async (req, res, ctx) => {
85
+ }, { status: 412 });
86
+ }), msw_1.http.post('https://api.ring.com/clients_api/session', async ({ request: req }) => {
88
87
  const authHeader = req.headers.get('Authorization');
89
88
  if (authHeader !== `Bearer ${accessToken}` &&
90
89
  authHeader !== `Bearer ${secondAccessToken}`) {
91
90
  // Invalid access token used
92
- return res(ctx.status(401));
91
+ return msw_1.HttpResponse.json({}, { status: 401 });
93
92
  }
94
93
  const body = await req.json();
95
94
  if (body.device.hardware_id !== (await (0, util_1.getHardwareId)()) ||
96
95
  body.device.metadata.api_version !== 11 ||
97
96
  body.device.metadata.device_model !== 'ring-client-api' ||
98
97
  body.device.os !== 'android') {
99
- return res(ctx.status(400), ctx.body('Bad session request: ' + JSON.stringify(body, null, 2)));
98
+ return msw_1.HttpResponse.text('Bad session request: ' + JSON.stringify(body, null, 2), { status: 400 });
100
99
  }
101
100
  // Fake a response from the session endpoint, incrementing the sessionCreatedCount
102
101
  sessionCreatedCount++;
103
- return res(ctx.json({
102
+ return msw_1.HttpResponse.json({
104
103
  profile: {
105
104
  id: 1234,
106
105
  },
107
- }));
106
+ });
108
107
  }));
109
108
  async function wrapRefreshToken(rt) {
110
109
  return (0, util_1.toBase64)(JSON.stringify({
@@ -200,25 +199,25 @@ describe('fetch', () => {
200
199
  let invalidateFirstAccessToken = false;
201
200
  beforeEach(() => {
202
201
  invalidateFirstAccessToken = false;
203
- server.use(msw_1.rest.get('https://api.ring.com/clients_api/some_endpoint', (req, res, ctx) => {
202
+ server.use(msw_1.http.get('https://api.ring.com/clients_api/some_endpoint', ({ request: req }) => {
204
203
  const authHeader = req.headers.get('Authorization');
205
204
  if (invalidateFirstAccessToken &&
206
205
  authHeader === `Bearer ${accessToken}`) {
207
206
  // Original access token used, but no longer valid
208
- return res(ctx.status(401));
207
+ return msw_1.HttpResponse.json({}, { status: 401 });
209
208
  }
210
209
  if (authHeader !== `Bearer ${accessToken}` &&
211
210
  authHeader !== `Bearer ${secondAccessToken}`) {
212
211
  // Invalid access token used
213
- return res(ctx.status(401));
212
+ return msw_1.HttpResponse.json({}, { status: 401 });
214
213
  }
215
214
  if (sessionCreatedCount === 0) {
216
215
  // Session not created yet
217
- return res(ctx.status(404), ctx.json({
216
+ return msw_1.HttpResponse.json({
218
217
  error: 'Session not found for ' + req.headers.get('hardware_id'),
219
- }));
218
+ }, { status: 404 });
220
219
  }
221
- return res(ctx.json([]));
220
+ return msw_1.HttpResponse.json([]);
222
221
  }));
223
222
  });
224
223
  it('should include the auth token as a header', async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ring-client-api",
3
- "version": "13.0.1",
3
+ "version": "13.1.0",
4
4
  "description": "Unofficial API for Ring doorbells, cameras, security alarm system and smart lighting",
5
5
  "main": "lib/index.js",
6
6
  "exports": {
@@ -21,11 +21,11 @@
21
21
  "@homebridge/camera-utils": "^2.2.6",
22
22
  "@types/socket.io-client": "1.4.36",
23
23
  "colors": "1.4.0",
24
- "debug": "^4.3.5",
24
+ "debug": "^4.3.6",
25
25
  "json-bigint": "^1.0.0",
26
26
  "rxjs": "^7.8.1",
27
27
  "socket.io-client": "^2.5.0",
28
- "systeminformation": "^5.22.11",
28
+ "systeminformation": "^5.23.4",
29
29
  "uuid": "^10.0.0",
30
30
  "werift": "0.19.4",
31
31
  "ws": "^8.18.0"
@@ -34,15 +34,15 @@
34
34
  "@types/debug": "4.1.12",
35
35
  "@types/jest": "29.5.12",
36
36
  "@types/json-bigint": "^1.0.4",
37
- "@types/node": "20.14.11",
37
+ "@types/node": "22.1.0",
38
38
  "@types/uuid": "10.0.0",
39
- "@types/ws": "^8.5.11",
39
+ "@types/ws": "^8.5.12",
40
40
  "eslint-config-shared": "*",
41
41
  "jest": "29.7.0",
42
- "msw": "^1.3.3",
43
- "ts-jest": "29.2.3",
42
+ "msw": "^2.3.5",
43
+ "ts-jest": "29.2.4",
44
44
  "tsconfig": "*",
45
- "typescript": "5.5.3"
45
+ "typescript": "5.5.4"
46
46
  },
47
47
  "engines": {
48
48
  "node": "^18 || ^20"