ring-client-api 13.0.0-beta.1 → 13.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api.js +10 -2
- package/lib/rest-client.d.ts +6 -1
- package/lib/rest-client.js +75 -19
- package/lib/ring-camera.d.ts +2 -2
- package/lib/ring-camera.js +7 -5
- package/lib/ring-intercom.d.ts +2 -2
- package/lib/ring-intercom.js +5 -3
- package/lib/ring-types.d.ts +31 -5
- package/lib/ring-types.js +6 -1
- package/lib/util.d.ts +1 -0
- package/lib/util.js +8 -0
- package/package.json +9 -13
package/lib/api.js
CHANGED
|
@@ -200,13 +200,21 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
200
200
|
messageData[p] = message.data[p];
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
const notification = messageData
|
|
203
|
+
const notification = messageData;
|
|
204
|
+
if (!('android_config' in notification)) {
|
|
205
|
+
// This is not a v2 ding style notification, so we can't process it
|
|
206
|
+
(0, util_1.logInfo)('Received push notification in unknown format');
|
|
207
|
+
(0, util_1.logInfo)(JSON.stringify(message));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const deviceId = notification.data?.device?.id;
|
|
204
211
|
if (deviceId) {
|
|
205
212
|
sendToDevice(deviceId, notification);
|
|
206
213
|
}
|
|
207
214
|
const eventCategory = notification.android_config.category;
|
|
208
215
|
if (eventCategory !== ring_types_1.PushNotificationAction.Ding &&
|
|
209
|
-
eventCategory !== ring_types_1.PushNotificationAction.Motion
|
|
216
|
+
eventCategory !== ring_types_1.PushNotificationAction.Motion &&
|
|
217
|
+
eventCategory !== ring_types_1.PushNotificationAction.IntercomDing) {
|
|
210
218
|
(0, util_1.logInfo)('Received push notification with unknown category: ' +
|
|
211
219
|
eventCategory);
|
|
212
220
|
(0, util_1.logInfo)(JSON.stringify(message));
|
package/lib/rest-client.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { Options as RequestOptions } from 'got';
|
|
2
1
|
import { AuthTokenResponse, SessionResponse } from './ring-types';
|
|
3
2
|
import { ReplaySubject } from 'rxjs';
|
|
4
3
|
import type { Credentials } from '@eneris/push-receiver/dist/types';
|
|
4
|
+
interface RequestOptions extends RequestInit {
|
|
5
|
+
responseType?: 'json' | 'buffer';
|
|
6
|
+
timeout?: number;
|
|
7
|
+
json?: object;
|
|
8
|
+
}
|
|
5
9
|
export declare function clientApi(path: string): string;
|
|
6
10
|
export declare function deviceApi(path: string): string;
|
|
7
11
|
export declare function commandsApi(path: string): string;
|
|
@@ -59,3 +63,4 @@ export declare class RingRestClient {
|
|
|
59
63
|
get _internalOnly_pushNotificationCredentials(): Credentials | undefined;
|
|
60
64
|
set _internalOnly_pushNotificationCredentials(credentials: Credentials | undefined);
|
|
61
65
|
}
|
|
66
|
+
export {};
|
package/lib/rest-client.js
CHANGED
|
@@ -8,14 +8,12 @@ exports.clientApi = clientApi;
|
|
|
8
8
|
exports.deviceApi = deviceApi;
|
|
9
9
|
exports.commandsApi = commandsApi;
|
|
10
10
|
exports.appApi = appApi;
|
|
11
|
-
const got_1 = __importDefault(require("got"));
|
|
12
11
|
const util_1 = require("./util");
|
|
13
12
|
const rxjs_1 = require("rxjs");
|
|
14
13
|
const assert_1 = __importDefault(require("assert"));
|
|
15
14
|
const defaultRequestOptions = {
|
|
16
15
|
responseType: 'json',
|
|
17
16
|
method: 'GET',
|
|
18
|
-
retry: 0,
|
|
19
17
|
timeout: 20000,
|
|
20
18
|
}, ringErrorCodes = {
|
|
21
19
|
7050: 'NO_ASSET',
|
|
@@ -36,18 +34,76 @@ function commandsApi(path) {
|
|
|
36
34
|
function appApi(path) {
|
|
37
35
|
return appApiBaseUrl + path;
|
|
38
36
|
}
|
|
37
|
+
async function responseToError(response) {
|
|
38
|
+
const error = new Error();
|
|
39
|
+
error.response = {
|
|
40
|
+
headers: response.headers,
|
|
41
|
+
status: response.status,
|
|
42
|
+
body: null,
|
|
43
|
+
};
|
|
44
|
+
try {
|
|
45
|
+
const bodyText = await response.text();
|
|
46
|
+
try {
|
|
47
|
+
error.response.body = JSON.parse(bodyText);
|
|
48
|
+
}
|
|
49
|
+
catch (_) {
|
|
50
|
+
error.response.body = bodyText;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (_) {
|
|
54
|
+
// ignore
|
|
55
|
+
}
|
|
56
|
+
return error;
|
|
57
|
+
}
|
|
39
58
|
async function requestWithRetry(requestOptions) {
|
|
40
59
|
try {
|
|
60
|
+
if (requestOptions.json || requestOptions.responseType === 'json') {
|
|
61
|
+
requestOptions.headers = {
|
|
62
|
+
...requestOptions.headers,
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
Accept: 'application/json',
|
|
65
|
+
};
|
|
66
|
+
if (requestOptions.json) {
|
|
67
|
+
requestOptions.body = JSON.stringify(requestOptions.json);
|
|
68
|
+
}
|
|
69
|
+
delete requestOptions.json;
|
|
70
|
+
}
|
|
41
71
|
const options = {
|
|
42
72
|
...defaultRequestOptions,
|
|
43
73
|
...requestOptions,
|
|
44
|
-
}
|
|
74
|
+
};
|
|
75
|
+
// If a timeout is provided, create an AbortSignal for it
|
|
76
|
+
if (options.timeout && !options.signal) {
|
|
77
|
+
options.signal = AbortSignal.timeout(options.timeout);
|
|
78
|
+
}
|
|
79
|
+
// make the fetch request
|
|
80
|
+
const response = await fetch(options.url, options), headers = response.headers;
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
const error = await responseToError(response);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
let data;
|
|
86
|
+
if (options.responseType === 'buffer') {
|
|
87
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
88
|
+
data = Buffer.from(arrayBuffer);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const text = await response.text();
|
|
92
|
+
try {
|
|
93
|
+
data = JSON.parse(text);
|
|
94
|
+
}
|
|
95
|
+
catch (_) {
|
|
96
|
+
data = text;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
45
99
|
if (data !== null && typeof data === 'object') {
|
|
46
|
-
|
|
47
|
-
|
|
100
|
+
const date = headers.get('date');
|
|
101
|
+
if (date) {
|
|
102
|
+
data.responseTimestamp = new Date(date).getTime();
|
|
48
103
|
}
|
|
49
|
-
|
|
50
|
-
|
|
104
|
+
const xTime = headers.get('x-time-millis');
|
|
105
|
+
if (xTime) {
|
|
106
|
+
data.timeMillis = Number(xTime);
|
|
51
107
|
}
|
|
52
108
|
}
|
|
53
109
|
return data;
|
|
@@ -186,12 +242,12 @@ class RingRestClient {
|
|
|
186
242
|
const response = requestError.response || {}, responseData = response.body || {}, responseError = 'error' in responseData && typeof responseData.error === 'string'
|
|
187
243
|
? responseData.error
|
|
188
244
|
: '';
|
|
189
|
-
if (response.
|
|
190
|
-
(response.
|
|
245
|
+
if (response.status === 412 || // need 2fa code
|
|
246
|
+
(response.status === 400 &&
|
|
191
247
|
responseError.startsWith('Verification Code')) // invalid 2fa code entered
|
|
192
248
|
) {
|
|
193
249
|
this.using2fa = true;
|
|
194
|
-
if (response.
|
|
250
|
+
if (response.status === 400) {
|
|
195
251
|
this.promptFor2fa = 'Invalid 2fa code entered. Please try again.';
|
|
196
252
|
throw new Error(responseError);
|
|
197
253
|
}
|
|
@@ -245,12 +301,12 @@ class RingRestClient {
|
|
|
245
301
|
}
|
|
246
302
|
catch (e) {
|
|
247
303
|
const response = e.response || {};
|
|
248
|
-
if (response.
|
|
304
|
+
if (response.status === 401) {
|
|
249
305
|
await this.refreshAuth();
|
|
250
306
|
return this.getSession();
|
|
251
307
|
}
|
|
252
|
-
if (response.
|
|
253
|
-
const retryAfter = e.response.headers
|
|
308
|
+
if (response.status === 429) {
|
|
309
|
+
const retryAfter = e.response.headers.get('retry-after'), waitSeconds = isNaN(retryAfter)
|
|
254
310
|
? 200
|
|
255
311
|
: Number.parseInt(retryAfter, 10);
|
|
256
312
|
(0, util_1.logError)(`Session response rate limited. Waiting to retry after ${waitSeconds} seconds`);
|
|
@@ -297,16 +353,16 @@ class RingRestClient {
|
|
|
297
353
|
}
|
|
298
354
|
catch (e) {
|
|
299
355
|
const response = e.response || {};
|
|
300
|
-
if (response.
|
|
356
|
+
if (response.status === 401) {
|
|
301
357
|
await this.refreshAuth();
|
|
302
358
|
return this.request(options);
|
|
303
359
|
}
|
|
304
|
-
if (response.
|
|
360
|
+
if (response.status === 504) {
|
|
305
361
|
// Gateway Timeout. These should be recoverable, but wait a few seconds just to be on the safe side
|
|
306
362
|
await (0, util_1.delay)(5000);
|
|
307
363
|
return this.request(options);
|
|
308
364
|
}
|
|
309
|
-
if (response.
|
|
365
|
+
if (response.status === 404 &&
|
|
310
366
|
response.body &&
|
|
311
367
|
Array.isArray(response.body.errors)) {
|
|
312
368
|
const errors = response.body.errors, errorText = errors
|
|
@@ -320,7 +376,7 @@ class RingRestClient {
|
|
|
320
376
|
}
|
|
321
377
|
(0, util_1.logError)(`http request failed. ${url} returned unknown errors: (${(0, util_1.stringify)(errors)}).`);
|
|
322
378
|
}
|
|
323
|
-
if (response.
|
|
379
|
+
if (response.status === 404 && url.startsWith(clientApiBaseUrl)) {
|
|
324
380
|
(0, util_1.logError)('404 from endpoint ' + url);
|
|
325
381
|
if (response.body?.error?.includes(hardwareId)) {
|
|
326
382
|
(0, util_1.logError)('Session hardware_id not found. Creating a new session and trying again.');
|
|
@@ -331,8 +387,8 @@ class RingRestClient {
|
|
|
331
387
|
}
|
|
332
388
|
throw new Error('Not found with response: ' + (0, util_1.stringify)(response.body));
|
|
333
389
|
}
|
|
334
|
-
if (response.
|
|
335
|
-
(0, util_1.logError)(`Request to ${url} failed with status ${response.
|
|
390
|
+
if (response.status) {
|
|
391
|
+
(0, util_1.logError)(`Request to ${url} failed with status ${response.status}. Response body: ${(0, util_1.stringify)(response.body)}`);
|
|
336
392
|
}
|
|
337
393
|
else if (!options.allowNoResponse) {
|
|
338
394
|
(0, util_1.logError)(`Request to ${url} failed:`);
|
package/lib/ring-camera.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CameraData, CameraDeviceSettingsData, CameraEventOptions, CameraEventResponse, CameraHealth, HistoryOptions, PeriodicFootageResponse,
|
|
1
|
+
import { CameraData, CameraDeviceSettingsData, CameraEventOptions, CameraEventResponse, CameraHealth, HistoryOptions, PeriodicFootageResponse, PushNotificationDingV2, VideoSearchResponse, OnvifCameraData, RingCameraKind } from './ring-types';
|
|
2
2
|
import { RingRestClient } from './rest-client';
|
|
3
3
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
4
|
import { DeepPartial } from './util';
|
|
@@ -61,7 +61,7 @@ export declare class RingCamera extends Subscribed {
|
|
|
61
61
|
private createStreamingConnection;
|
|
62
62
|
startLiveCall(options?: StreamingConnectionOptions): Promise<StreamingSession>;
|
|
63
63
|
private removeDingById;
|
|
64
|
-
processPushNotification(notification:
|
|
64
|
+
processPushNotification(notification: PushNotificationDingV2): void;
|
|
65
65
|
getEvents(options?: CameraEventOptions): Promise<CameraEventResponse & import("./rest-client").ExtendedResponse>;
|
|
66
66
|
videoSearch({ dateFrom, dateTo, order }?: {
|
|
67
67
|
dateFrom: number;
|
package/lib/ring-camera.js
CHANGED
|
@@ -38,7 +38,10 @@ function getBatteryLevel(data) {
|
|
|
38
38
|
parseBatteryLife(data.battery_life_2),
|
|
39
39
|
].filter((level) => level !== null), { health } = data;
|
|
40
40
|
if (!levels.length ||
|
|
41
|
-
(health &&
|
|
41
|
+
(health &&
|
|
42
|
+
!health.battery_percentage &&
|
|
43
|
+
!health.battery_present &&
|
|
44
|
+
!health.second_battery_percentage)) {
|
|
42
45
|
return null;
|
|
43
46
|
}
|
|
44
47
|
return Math.min(...levels);
|
|
@@ -374,14 +377,13 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
374
377
|
}
|
|
375
378
|
async getNextSnapshot({ afterMs, maxWaitMs, force, uuid, }) {
|
|
376
379
|
const response = await this.restClient.request({
|
|
377
|
-
url: `https://app-snaps.ring.com/snapshots/next/${this.id}
|
|
378
|
-
responseType: 'buffer',
|
|
379
|
-
searchParams: {
|
|
380
|
+
url: `https://app-snaps.ring.com/snapshots/next/${this.id}${(0, util_1.buildSearchString)({
|
|
380
381
|
'after-ms': afterMs,
|
|
381
382
|
'max-wait-ms': maxWaitMs,
|
|
382
383
|
extras: force ? 'force' : undefined,
|
|
383
384
|
uuid: cleanSnapshotUuid(uuid),
|
|
384
|
-
}
|
|
385
|
+
})}`,
|
|
386
|
+
responseType: 'buffer',
|
|
385
387
|
headers: {
|
|
386
388
|
accept: 'image/jpeg',
|
|
387
389
|
},
|
package/lib/ring-intercom.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IntercomHandsetAudioData,
|
|
1
|
+
import { IntercomHandsetAudioData, PushNotificationDingV2, PushNotificationIntercomUnlockV2 } from './ring-types';
|
|
2
2
|
import { RingRestClient } from './rest-client';
|
|
3
3
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
4
|
export declare class RingIntercom {
|
|
@@ -22,5 +22,5 @@ export declare class RingIntercom {
|
|
|
22
22
|
private doorbotUrl;
|
|
23
23
|
subscribeToDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
24
24
|
unsubscribeFromDingEvents(): Promise<void & import("./rest-client").ExtendedResponse>;
|
|
25
|
-
processPushNotification(notification:
|
|
25
|
+
processPushNotification(notification: PushNotificationDingV2 | PushNotificationIntercomUnlockV2): void;
|
|
26
26
|
}
|
package/lib/ring-intercom.js
CHANGED
|
@@ -76,11 +76,13 @@ class RingIntercom {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
processPushNotification(notification) {
|
|
79
|
-
if (
|
|
79
|
+
if ('android_config' in notification &&
|
|
80
|
+
notification.android_config.category ===
|
|
81
|
+
ring_types_1.PushNotificationAction.IntercomDing) {
|
|
80
82
|
this.onDing.next();
|
|
81
83
|
}
|
|
82
|
-
else if (notification.
|
|
83
|
-
ring_types_1.PushNotificationAction.IntercomUnlock) {
|
|
84
|
+
else if ('gcmData' in notification.data &&
|
|
85
|
+
notification.data.gcmData.action === ring_types_1.PushNotificationAction.IntercomUnlock) {
|
|
84
86
|
this.onUnlocked.next();
|
|
85
87
|
}
|
|
86
88
|
}
|
package/lib/ring-types.d.ts
CHANGED
|
@@ -469,6 +469,7 @@ export interface BaseCameraData {
|
|
|
469
469
|
rssi_category: 'good' | string;
|
|
470
470
|
battery_voltage_category: 'very_good' | string;
|
|
471
471
|
second_battery_voltage_category: 'unknown' | string;
|
|
472
|
+
second_battery_percentage?: number;
|
|
472
473
|
second_battery_percentage_category: 'unknown' | string;
|
|
473
474
|
battery_save: boolean;
|
|
474
475
|
firmware_version_status: 'Up to Date';
|
|
@@ -867,7 +868,12 @@ export declare enum NotificationDetectionType {
|
|
|
867
868
|
export declare enum PushNotificationAction {
|
|
868
869
|
Ding = "com.ring.pn.live-event.ding",
|
|
869
870
|
Motion = "com.ring.pn.live-event.motion",
|
|
870
|
-
|
|
871
|
+
IntercomDing = "com.ring.pn.live-event.intercom",
|
|
872
|
+
IntercomUnlock = "com.ring.push.INTERCOM_UNLOCK_FROM_APP",
|
|
873
|
+
AlarmModeNone = "com.ring.push.HANDLE_NEW_SECURITY_PANEL_MODE_NONE_NOTICE",
|
|
874
|
+
AlarmModeSome = "com.ring.push.HANDLE_NEW_SECURITY_PANEL_MODE_SOME_NOTICE",
|
|
875
|
+
AlarmSoundSiren = "com.ring.push.HANDLE_NEW_USER_SOUND_SIREN",
|
|
876
|
+
AlarmSilenceSiren = "com.ring.push.HANDLE_NEW_NON_ALARM_SIREN_SILENCED"
|
|
871
877
|
}
|
|
872
878
|
export interface PushNotificationDingV2 {
|
|
873
879
|
version: '2.0.0' | string;
|
|
@@ -888,7 +894,7 @@ export interface PushNotificationDingV2 {
|
|
|
888
894
|
device: {
|
|
889
895
|
e2ee_enabled: boolean;
|
|
890
896
|
id: number;
|
|
891
|
-
kind: RingCameraKind;
|
|
897
|
+
kind: RingCameraKind | RingDeviceType.IntercomHandsetAudio;
|
|
892
898
|
name: string;
|
|
893
899
|
};
|
|
894
900
|
event: {
|
|
@@ -896,7 +902,7 @@ export interface PushNotificationDingV2 {
|
|
|
896
902
|
id: string;
|
|
897
903
|
created_at: string;
|
|
898
904
|
subtype: 'other_motion' | 'motion' | 'ding' | 'human' | string;
|
|
899
|
-
detection_type
|
|
905
|
+
detection_type?: NotificationDetectionType;
|
|
900
906
|
};
|
|
901
907
|
eventito: {
|
|
902
908
|
type: NotificationDetectionType;
|
|
@@ -919,7 +925,7 @@ export interface PushNotificationDingV2 {
|
|
|
919
925
|
snapshot_uuid: string;
|
|
920
926
|
};
|
|
921
927
|
}
|
|
922
|
-
|
|
928
|
+
interface PushNotificationAlarm {
|
|
923
929
|
aps: {
|
|
924
930
|
alert: string;
|
|
925
931
|
};
|
|
@@ -929,7 +935,27 @@ export interface PushNotificationAlarm {
|
|
|
929
935
|
location_id: string;
|
|
930
936
|
};
|
|
931
937
|
}
|
|
932
|
-
export
|
|
938
|
+
export interface PushNotificationAlarmV2 {
|
|
939
|
+
data: {
|
|
940
|
+
gcmData: PushNotificationAlarm;
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
interface PushNotificationIntercomUnlock {
|
|
944
|
+
aps: {
|
|
945
|
+
alert: string;
|
|
946
|
+
};
|
|
947
|
+
action: PushNotificationAction.IntercomUnlock;
|
|
948
|
+
alarm_meta: {
|
|
949
|
+
device_zid: number;
|
|
950
|
+
location_id: string;
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
export interface PushNotificationIntercomUnlockV2 {
|
|
954
|
+
data: {
|
|
955
|
+
gcmData: PushNotificationIntercomUnlock;
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
export type PushNotification = PushNotificationDingV2 | PushNotificationAlarmV2 | PushNotificationIntercomUnlockV2;
|
|
933
959
|
export interface SocketTicketResponse {
|
|
934
960
|
ticket: string;
|
|
935
961
|
responseTimestampe: number;
|
package/lib/ring-types.js
CHANGED
|
@@ -188,7 +188,12 @@ var PushNotificationAction;
|
|
|
188
188
|
(function (PushNotificationAction) {
|
|
189
189
|
PushNotificationAction["Ding"] = "com.ring.pn.live-event.ding";
|
|
190
190
|
PushNotificationAction["Motion"] = "com.ring.pn.live-event.motion";
|
|
191
|
-
PushNotificationAction["
|
|
191
|
+
PushNotificationAction["IntercomDing"] = "com.ring.pn.live-event.intercom";
|
|
192
|
+
PushNotificationAction["IntercomUnlock"] = "com.ring.push.INTERCOM_UNLOCK_FROM_APP";
|
|
193
|
+
PushNotificationAction["AlarmModeNone"] = "com.ring.push.HANDLE_NEW_SECURITY_PANEL_MODE_NONE_NOTICE";
|
|
194
|
+
PushNotificationAction["AlarmModeSome"] = "com.ring.push.HANDLE_NEW_SECURITY_PANEL_MODE_SOME_NOTICE";
|
|
195
|
+
PushNotificationAction["AlarmSoundSiren"] = "com.ring.push.HANDLE_NEW_USER_SOUND_SIREN";
|
|
196
|
+
PushNotificationAction["AlarmSilenceSiren"] = "com.ring.push.HANDLE_NEW_NON_ALARM_SIREN_SILENCED";
|
|
192
197
|
})(PushNotificationAction || (exports.PushNotificationAction = PushNotificationAction = {}));
|
|
193
198
|
// eslint-disable-next-line no-shadow
|
|
194
199
|
var DispatchSignalType;
|
package/lib/util.d.ts
CHANGED
package/lib/util.js
CHANGED
|
@@ -19,6 +19,7 @@ exports.randomInteger = randomInteger;
|
|
|
19
19
|
exports.randomString = randomString;
|
|
20
20
|
exports.fromBase64 = fromBase64;
|
|
21
21
|
exports.toBase64 = toBase64;
|
|
22
|
+
exports.buildSearchString = buildSearchString;
|
|
22
23
|
const debug_1 = __importDefault(require("debug"));
|
|
23
24
|
const colors_1 = require("colors");
|
|
24
25
|
const readline_1 = require("readline");
|
|
@@ -143,3 +144,10 @@ function toBase64(input) {
|
|
|
143
144
|
const buff = Buffer.from(input);
|
|
144
145
|
return buff.toString('base64');
|
|
145
146
|
}
|
|
147
|
+
function buildSearchString(search) {
|
|
148
|
+
return ('?' +
|
|
149
|
+
Object.entries(search)
|
|
150
|
+
.filter(([, value]) => value !== undefined && value !== null)
|
|
151
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
152
|
+
.join('&'));
|
|
153
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ring-client-api",
|
|
3
|
-
"version": "13.0.0-beta.
|
|
3
|
+
"version": "13.0.0-beta.3",
|
|
4
4
|
"description": "Unofficial API for Ring doorbells, cameras, security alarm system and smart lighting",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -17,36 +17,32 @@
|
|
|
17
17
|
"test:watch": "jest --watch"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@eneris/push-receiver": "^4.1.
|
|
20
|
+
"@eneris/push-receiver": "^4.1.4",
|
|
21
21
|
"@homebridge/camera-utils": "^2.2.6",
|
|
22
|
-
"@peculiar/asn1-schema": "^2.3.8",
|
|
23
22
|
"@types/socket.io-client": "1.4.36",
|
|
24
23
|
"colors": "1.4.0",
|
|
25
24
|
"debug": "^4.3.5",
|
|
26
|
-
"got": "^11.8.5",
|
|
27
25
|
"json-bigint": "^1.0.0",
|
|
28
|
-
"msw": "^1.3.3",
|
|
29
|
-
"pvtsutils": "^1.3.5",
|
|
30
26
|
"rxjs": "^7.8.1",
|
|
31
27
|
"socket.io-client": "^2.5.0",
|
|
32
28
|
"systeminformation": "^5.22.11",
|
|
33
29
|
"uuid": "^10.0.0",
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"ws": "^8.17.1"
|
|
30
|
+
"werift": "0.19.4",
|
|
31
|
+
"ws": "^8.18.0"
|
|
37
32
|
},
|
|
38
33
|
"devDependencies": {
|
|
39
34
|
"@types/debug": "4.1.12",
|
|
40
35
|
"@types/jest": "29.5.12",
|
|
41
36
|
"@types/json-bigint": "^1.0.4",
|
|
42
|
-
"@types/node": "20.14.
|
|
37
|
+
"@types/node": "20.14.11",
|
|
43
38
|
"@types/uuid": "10.0.0",
|
|
44
|
-
"@types/ws": "^8.5.
|
|
39
|
+
"@types/ws": "^8.5.11",
|
|
45
40
|
"eslint-config-shared": "*",
|
|
46
41
|
"jest": "29.7.0",
|
|
47
|
-
"
|
|
42
|
+
"msw": "^1.3.3",
|
|
43
|
+
"ts-jest": "29.2.3",
|
|
48
44
|
"tsconfig": "*",
|
|
49
|
-
"typescript": "5.5.
|
|
45
|
+
"typescript": "5.5.3"
|
|
50
46
|
},
|
|
51
47
|
"engines": {
|
|
52
48
|
"node": "^18 || ^20"
|