ring-client-api 14.3.0 → 15.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.
- package/lib/api.js +9 -9
- package/lib/device-data.d.ts +2 -0
- package/lib/device-data.js +81 -29
- package/lib/index.js +7 -7
- package/lib/location.js +7 -7
- package/lib/refresh-token.js +4 -4
- package/lib/rest-client.d.ts +4 -1
- package/lib/rest-client.js +33 -14
- package/lib/ring-auth-cli.js +1 -1
- package/lib/ring-camera.js +8 -8
- package/lib/ring-chime.js +2 -2
- package/lib/ring-device-data-cli.js +1 -1
- package/lib/ring-device.js +3 -3
- package/lib/ring-intercom.js +4 -4
- package/lib/ring-types.d.ts +96 -96
- package/lib/streaming/peer-connection.d.ts +2 -2
- package/lib/streaming/peer-connection.js +2 -2
- package/lib/streaming/simple-webrtc-session.js +1 -1
- package/lib/streaming/streaming-messages.d.ts +11 -7
- package/lib/streaming/streaming-messages.js +0 -9
- package/lib/streaming/streaming-session.js +3 -3
- package/lib/streaming/webrtc-connection.js +7 -4
- package/lib/util.d.ts +1 -0
- package/lib/util.js +23 -1
- package/package.json +40 -20
package/lib/api.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { clientApi, deviceApi, RingRestClient } from
|
|
2
|
-
import { Location } from
|
|
3
|
-
import { PushNotificationAction, RingDeviceType } from
|
|
4
|
-
import { RingCamera } from
|
|
5
|
-
import { RingChime } from
|
|
1
|
+
import { clientApi, deviceApi, RingRestClient } from './rest-client.js';
|
|
2
|
+
import { Location } from './location.js';
|
|
3
|
+
import { PushNotificationAction, RingDeviceType } from './ring-types.js';
|
|
4
|
+
import { RingCamera } from './ring-camera.js';
|
|
5
|
+
import { RingChime } from './ring-chime.js';
|
|
6
6
|
import { combineLatest, EMPTY, merge, Subject } from 'rxjs';
|
|
7
7
|
import { debounceTime, startWith, switchMap, throttleTime, } from 'rxjs/operators';
|
|
8
|
-
import { clearTimeouts, enableDebug, logDebug, logError, logInfo, } from
|
|
9
|
-
import { setFfmpegPath } from
|
|
10
|
-
import { Subscribed } from
|
|
8
|
+
import { clearTimeouts, enableDebug, logDebug, logError, logInfo, } from './util.js';
|
|
9
|
+
import { setFfmpegPath } from './ffmpeg.js';
|
|
10
|
+
import { Subscribed } from './subscribed.js';
|
|
11
11
|
import { PushReceiver } from '@eneris/push-receiver';
|
|
12
|
-
import { RingIntercom } from
|
|
12
|
+
import { RingIntercom } from './ring-intercom.js';
|
|
13
13
|
import JSONbig from 'json-bigint';
|
|
14
14
|
export class RingApi extends Subscribed {
|
|
15
15
|
restClient;
|
package/lib/device-data.d.ts
CHANGED
package/lib/device-data.js
CHANGED
|
@@ -1,50 +1,100 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
import { RingApi } from
|
|
3
|
-
import { acquireRefreshToken } from
|
|
4
|
-
import { mapAsync } from
|
|
2
|
+
import { RingApi } from './api.js';
|
|
3
|
+
import { acquireRefreshToken } from './refresh-token.js';
|
|
4
|
+
import { mapAsync } from './util.js';
|
|
5
5
|
const sensitiveFields = [
|
|
6
6
|
'id',
|
|
7
7
|
'device_id',
|
|
8
8
|
'latitude',
|
|
9
9
|
'longitude',
|
|
10
10
|
'address',
|
|
11
|
+
'address1',
|
|
12
|
+
'address2',
|
|
11
13
|
'email',
|
|
12
14
|
'time_zone',
|
|
15
|
+
'timezone',
|
|
13
16
|
'location_id',
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
+
'serialnumber',
|
|
18
|
+
'serial_number',
|
|
19
|
+
'catalogid',
|
|
20
|
+
'adapterzid',
|
|
17
21
|
'fingerprint',
|
|
18
22
|
'owner',
|
|
19
23
|
'ssid',
|
|
24
|
+
'wifi_name',
|
|
20
25
|
'ap_address',
|
|
26
|
+
'mac_address',
|
|
27
|
+
'macaddress',
|
|
21
28
|
'codes',
|
|
22
|
-
'
|
|
29
|
+
'groupid',
|
|
23
30
|
'group',
|
|
24
|
-
'
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
'groupmembers',
|
|
32
|
+
'first_name',
|
|
33
|
+
'last_name',
|
|
34
|
+
'phone',
|
|
35
|
+
'phone_number',
|
|
36
|
+
'third_party_dsn',
|
|
37
|
+
'amzn_dsn',
|
|
38
|
+
'refresh_token',
|
|
39
|
+
'access_token',
|
|
40
|
+
'password',
|
|
41
|
+
'token',
|
|
42
|
+
'cookie',
|
|
43
|
+
'city',
|
|
44
|
+
'zip_code',
|
|
45
|
+
'cross_street',
|
|
46
|
+
], sensitiveFieldSet = new Set(sensitiveFields), uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
47
|
+
export const redactedUuid = '[uuid]';
|
|
48
|
+
function isUuid(value) {
|
|
49
|
+
return value.length === 36 && uuidPattern.test(value);
|
|
50
|
+
}
|
|
51
|
+
function isSensitiveKey(key) {
|
|
52
|
+
const lower = key.toLowerCase();
|
|
53
|
+
return (sensitiveFieldSet.has(lower) ||
|
|
54
|
+
lower.endsWith('_id') ||
|
|
55
|
+
// camelCase ids such as roomId / doorbotId (but not zid — keep key, redact value)
|
|
56
|
+
(key.endsWith('Id') && key !== 'Id'));
|
|
57
|
+
}
|
|
58
|
+
export function stripSensitiveFields(input) {
|
|
59
|
+
if (input === null || typeof input !== 'object') {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (Array.isArray(input)) {
|
|
63
|
+
for (let i = 0; i < input.length; i++) {
|
|
64
|
+
const value = input[i];
|
|
65
|
+
if (typeof value === 'string' && isUuid(value)) {
|
|
66
|
+
input[i] = redactedUuid;
|
|
35
67
|
}
|
|
36
68
|
else {
|
|
37
|
-
|
|
38
|
-
if (key.length === 36) {
|
|
39
|
-
input[key.slice(0, 13) + '-uuid'] = data;
|
|
40
|
-
delete input[key];
|
|
41
|
-
}
|
|
42
|
-
if (typeof data === 'string' && data.length === 36) {
|
|
43
|
-
input[key] = data.slice(0, 13) + '-uuid';
|
|
44
|
-
}
|
|
45
|
-
stripSensitiveFields(data);
|
|
69
|
+
stripSensitiveFields(value);
|
|
46
70
|
}
|
|
47
71
|
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const record = input;
|
|
75
|
+
let uuidKeyIndex = 0;
|
|
76
|
+
// Snapshot keys so renames during iteration cannot re-introduce originals.
|
|
77
|
+
for (const key of Object.keys(record)) {
|
|
78
|
+
if (isSensitiveKey(key)) {
|
|
79
|
+
delete record[key];
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
let data = record[key];
|
|
83
|
+
if (isUuid(key)) {
|
|
84
|
+
delete record[key];
|
|
85
|
+
if (typeof data === 'string' && isUuid(data)) {
|
|
86
|
+
data = redactedUuid;
|
|
87
|
+
}
|
|
88
|
+
// Unique placeholder per key so sibling uuid keys do not clobber each other.
|
|
89
|
+
record[`${redactedUuid}:${uuidKeyIndex++}`] = data;
|
|
90
|
+
stripSensitiveFields(data);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (typeof data === 'string' && isUuid(data)) {
|
|
94
|
+
record[key] = redactedUuid;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
stripSensitiveFields(data);
|
|
48
98
|
}
|
|
49
99
|
}
|
|
50
100
|
export async function logDeviceData() {
|
|
@@ -61,10 +111,12 @@ export async function logDeviceData() {
|
|
|
61
111
|
intercoms: location.intercoms.map((intercom) => intercom.data),
|
|
62
112
|
devices: devices.map((device) => device.data),
|
|
63
113
|
};
|
|
64
|
-
}),
|
|
114
|
+
}),
|
|
115
|
+
// Clone so redaction does not mutate live RingApi device objects.
|
|
116
|
+
results = structuredClone({
|
|
65
117
|
locations: locationsWithDevices,
|
|
66
118
|
amazonKeyLocks,
|
|
67
|
-
};
|
|
119
|
+
});
|
|
68
120
|
stripSensitiveFields(results);
|
|
69
121
|
console.log('\nPlease copy and paste everything AFTER THIS LINE:\n\n');
|
|
70
122
|
console.log(JSON.stringify(results));
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
1
|
+
export * from './api.js';
|
|
2
|
+
export * from './location.js';
|
|
3
|
+
export * from './ring-camera.js';
|
|
4
|
+
export * from './ring-chime.js';
|
|
5
|
+
export * from './ring-device.js';
|
|
6
|
+
export * from './ring-intercom.js';
|
|
7
|
+
export * from './ring-types.js';
|
package/lib/location.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { WebSocket } from 'undici';
|
|
2
2
|
import { BehaviorSubject, firstValueFrom, merge, ReplaySubject, Subject, } from 'rxjs';
|
|
3
3
|
import { concatMap, debounceTime, distinctUntilChanged, filter, map, scan, shareReplay, skip, } from 'rxjs/operators';
|
|
4
|
-
import { delay, generateUuid, logDebug, logError, logInfo } from
|
|
5
|
-
import { DispatchSignalType, RingDeviceType, disabledLocationModes, isWebSocketSupportedAsset, } from
|
|
6
|
-
import { appApi, clientApi } from
|
|
7
|
-
import { getSearchQueryString } from
|
|
8
|
-
import { RingDevice } from
|
|
9
|
-
import { Subscribed } from
|
|
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';
|
|
10
10
|
const deviceListMessageType = 'DeviceInfoDocGetList';
|
|
11
11
|
function flattenDeviceData(data) {
|
|
12
12
|
return Object.assign({}, data.general && data.general.v2, data.device && data.device.v1);
|
|
@@ -152,7 +152,7 @@ export class Location extends Subscribed {
|
|
|
152
152
|
this.onDataUpdate.next(message);
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
catch
|
|
155
|
+
catch {
|
|
156
156
|
logError('Error parsing message from server: ' + event.data);
|
|
157
157
|
}
|
|
158
158
|
});
|
package/lib/refresh-token.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
import { RingRestClient } from
|
|
3
|
-
import { requestInput } from
|
|
2
|
+
import { RingRestClient } from './rest-client.js';
|
|
3
|
+
import { requestHiddenInput, requestInput } from './util.js';
|
|
4
4
|
export async function acquireRefreshToken() {
|
|
5
|
-
const email = await requestInput('Email: '), password = await
|
|
5
|
+
const email = await requestInput('Email: '), password = await requestHiddenInput('Password: '), restClient = new RingRestClient({ email, password }), getAuthWith2fa = async () => {
|
|
6
6
|
const code = await requestInput('2fa Code: ');
|
|
7
7
|
try {
|
|
8
8
|
return await restClient.getAuth(code);
|
|
9
9
|
}
|
|
10
|
-
catch
|
|
10
|
+
catch {
|
|
11
11
|
console.log('Incorrect 2fa code. Please try again.');
|
|
12
12
|
return getAuthWith2fa();
|
|
13
13
|
}
|
package/lib/rest-client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AuthTokenResponse, SessionResponse } from './ring-types.ts';
|
|
|
2
2
|
import { ReplaySubject } from 'rxjs';
|
|
3
3
|
import type { Credentials } from '@eneris/push-receiver/dist/types.d.js';
|
|
4
4
|
import { Agent } from 'undici';
|
|
5
|
-
interface RequestOptions extends RequestInit {
|
|
5
|
+
interface RequestOptions extends Omit<RequestInit, 'dispatcher'> {
|
|
6
6
|
responseType?: 'json' | 'buffer';
|
|
7
7
|
timeout?: number;
|
|
8
8
|
json?: object;
|
|
@@ -16,6 +16,9 @@ export interface ExtendedResponse {
|
|
|
16
16
|
responseTimestamp: number;
|
|
17
17
|
timeMillis: number;
|
|
18
18
|
}
|
|
19
|
+
export declare class InvalidAuthResponseError extends Error {
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
19
22
|
export interface EmailAuth {
|
|
20
23
|
email: string;
|
|
21
24
|
password: string;
|
package/lib/rest-client.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { delay, fromBase64, getHardwareId, logDebug, logError, logInfo, stringify, toBase64, } from
|
|
1
|
+
import { delay, fromBase64, getHardwareId, logDebug, logError, logInfo, stringify, toBase64, } from './util.js';
|
|
2
2
|
import { ReplaySubject } from 'rxjs';
|
|
3
3
|
import assert from 'assert';
|
|
4
|
-
|
|
4
|
+
// Import fetch from the same undici package as Agent. Node's global fetch is
|
|
5
|
+
// backed by a bundled undici that can be a different major than the npm
|
|
6
|
+
// dependency; passing an undici@8 Agent into global fetch then fails with
|
|
7
|
+
// UND_ERR_INVALID_ARG ("invalid onRequestStart method") on Node 22/24.
|
|
8
|
+
import { Agent, fetch as undiciFetch, } from 'undici';
|
|
5
9
|
const fetchAgent = new Agent({
|
|
6
10
|
connections: 6,
|
|
7
11
|
pipelining: 1,
|
|
@@ -29,6 +33,9 @@ export function commandsApi(path) {
|
|
|
29
33
|
export function appApi(path) {
|
|
30
34
|
return appApiBaseUrl + path;
|
|
31
35
|
}
|
|
36
|
+
export class InvalidAuthResponseError extends Error {
|
|
37
|
+
name = 'InvalidAuthResponseError';
|
|
38
|
+
}
|
|
32
39
|
async function responseToError(response) {
|
|
33
40
|
const error = new Error();
|
|
34
41
|
error.response = {
|
|
@@ -51,9 +58,6 @@ async function responseToError(response) {
|
|
|
51
58
|
return error;
|
|
52
59
|
}
|
|
53
60
|
async function requestWithRetry(requestOptions, retryCount = 0) {
|
|
54
|
-
if (typeof fetch !== 'function') {
|
|
55
|
-
throw new Error(`Your current NodeJS version (${process.version}) is too old to support this plugin. Please upgrade to the latest LTS version of NodeJS.`);
|
|
56
|
-
}
|
|
57
61
|
try {
|
|
58
62
|
if (requestOptions.json || requestOptions.responseType === 'json') {
|
|
59
63
|
requestOptions.headers = {
|
|
@@ -75,8 +79,8 @@ async function requestWithRetry(requestOptions, retryCount = 0) {
|
|
|
75
79
|
if (options.timeout && !options.signal) {
|
|
76
80
|
options.signal = AbortSignal.timeout(options.timeout);
|
|
77
81
|
}
|
|
78
|
-
//
|
|
79
|
-
const response = await
|
|
82
|
+
// undici fetch + undici Agent must stay paired (see import comment)
|
|
83
|
+
const response = await undiciFetch(options.url, options), headers = response.headers;
|
|
80
84
|
if (!response.ok) {
|
|
81
85
|
const error = await responseToError(response);
|
|
82
86
|
throw error;
|
|
@@ -223,7 +227,12 @@ export class RingRestClient {
|
|
|
223
227
|
hardware_id: hardwareId,
|
|
224
228
|
'User-Agent': 'android:com.ringapp',
|
|
225
229
|
},
|
|
226
|
-
}), oldRefreshToken = this.refreshToken;
|
|
230
|
+
}), oldRefreshToken = this.refreshToken, newRefreshToken = response?.refresh_token;
|
|
231
|
+
// Never replace the stored refresh token with one missing `rt` (e.g. an undecodable response body).
|
|
232
|
+
// Persisting it would guarantee `invalid_grant` on the next start, while the old token may still work.
|
|
233
|
+
if (typeof newRefreshToken !== 'string' || !newRefreshToken) {
|
|
234
|
+
throw new InvalidAuthResponseError('Received an oauth response from Ring without a refresh token. The existing refresh token has been kept. If this persists, make sure ring-client-api/homebridge-ring is up to date for your Node.js version.');
|
|
235
|
+
}
|
|
227
236
|
// Store the new refresh token and auth config
|
|
228
237
|
this.authConfig = {
|
|
229
238
|
...this.authConfig,
|
|
@@ -243,6 +252,10 @@ export class RingRestClient {
|
|
|
243
252
|
};
|
|
244
253
|
}
|
|
245
254
|
catch (requestError) {
|
|
255
|
+
if (requestError instanceof InvalidAuthResponseError) {
|
|
256
|
+
// Ring did not reject the credentials, so keep them in memory rather than clearing and retrying
|
|
257
|
+
throw requestError;
|
|
258
|
+
}
|
|
246
259
|
if (grantData.refresh_token) {
|
|
247
260
|
// failed request with refresh token
|
|
248
261
|
this.refreshToken = undefined;
|
|
@@ -250,9 +263,13 @@ export class RingRestClient {
|
|
|
250
263
|
logError(requestError);
|
|
251
264
|
return this.getAuth();
|
|
252
265
|
}
|
|
253
|
-
const response = requestError.response || {}, responseData = response.body
|
|
266
|
+
const response = requestError.response || {}, responseData = typeof response.body === 'object' && response.body !== null
|
|
267
|
+
? response.body
|
|
268
|
+
: {}, responseError = 'error' in responseData && typeof responseData.error === 'string'
|
|
254
269
|
? responseData.error
|
|
255
|
-
:
|
|
270
|
+
: response.status
|
|
271
|
+
? `HTTP ${response.status}`
|
|
272
|
+
: '';
|
|
256
273
|
if (response.status === 412 || // need 2fa code
|
|
257
274
|
(response.status === 400 &&
|
|
258
275
|
responseError.startsWith('Verification Code')) // invalid 2fa code entered
|
|
@@ -260,7 +277,7 @@ export class RingRestClient {
|
|
|
260
277
|
this.using2fa = true;
|
|
261
278
|
if (response.status === 400) {
|
|
262
279
|
this.promptFor2fa = 'Invalid 2fa code entered. Please try again.';
|
|
263
|
-
throw new Error(responseError);
|
|
280
|
+
throw new Error(responseError, { cause: requestError });
|
|
264
281
|
}
|
|
265
282
|
if ('tsv_state' in responseData) {
|
|
266
283
|
const { tsv_state, phone } = responseData, prompt = tsv_state === 'totp'
|
|
@@ -271,7 +288,7 @@ export class RingRestClient {
|
|
|
271
288
|
else {
|
|
272
289
|
this.promptFor2fa = 'Please enter the code sent to your text/email';
|
|
273
290
|
}
|
|
274
|
-
throw new Error('Your Ring account is configured to use 2-factor authentication (2fa). See https://github.com/dgreif/ring/wiki/Refresh-Tokens for details.');
|
|
291
|
+
throw new Error('Your Ring account is configured to use 2-factor authentication (2fa). See https://github.com/dgreif/ring/wiki/Refresh-Tokens for details.', { cause: requestError });
|
|
275
292
|
}
|
|
276
293
|
const authTypeMessage = 'refreshToken' in this.authOptions
|
|
277
294
|
? 'refresh token is'
|
|
@@ -284,7 +301,7 @@ export class RingRestClient {
|
|
|
284
301
|
` (error: ${responseError})`;
|
|
285
302
|
logError(requestError.response || requestError);
|
|
286
303
|
logError(errorMessage);
|
|
287
|
-
throw new Error(errorMessage);
|
|
304
|
+
throw new Error(errorMessage, { cause: requestError });
|
|
288
305
|
}
|
|
289
306
|
}
|
|
290
307
|
async fetchNewSession(authToken) {
|
|
@@ -396,7 +413,9 @@ export class RingRestClient {
|
|
|
396
413
|
}
|
|
397
414
|
return this.request(options);
|
|
398
415
|
}
|
|
399
|
-
throw new Error('Not found with response: ' + stringify(response.body)
|
|
416
|
+
throw new Error('Not found with response: ' + stringify(response.body), {
|
|
417
|
+
cause: e,
|
|
418
|
+
});
|
|
400
419
|
}
|
|
401
420
|
if (response.status) {
|
|
402
421
|
logError(`Request to ${url} failed with status ${response.status}. Response body: ${stringify(response.body)}`);
|
package/lib/ring-auth-cli.js
CHANGED
package/lib/ring-camera.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { RingCameraKind } from
|
|
2
|
-
import { DoorbellType, PushNotificationAction, RingCameraModel, } from
|
|
3
|
-
import { appApi, clientApi, deviceApi } from
|
|
1
|
+
import { RingCameraKind } from './ring-types.js';
|
|
2
|
+
import { DoorbellType, PushNotificationAction, RingCameraModel, } from './ring-types.js';
|
|
3
|
+
import { appApi, clientApi, deviceApi } from './rest-client.js';
|
|
4
4
|
import { BehaviorSubject, firstValueFrom, ReplaySubject, Subject } from 'rxjs';
|
|
5
5
|
import { distinctUntilChanged, filter, map, share, startWith, throttleTime, } from 'rxjs/operators';
|
|
6
|
-
import { buildSearchString, delay, logDebug, logError, } from
|
|
7
|
-
import { Subscribed } from
|
|
8
|
-
import { WebrtcConnection } from
|
|
9
|
-
import { StreamingSession } from
|
|
10
|
-
import { SimpleWebRtcSession } from
|
|
6
|
+
import { buildSearchString, delay, logDebug, logError, } from './util.js';
|
|
7
|
+
import { Subscribed } from './subscribed.js';
|
|
8
|
+
import { WebrtcConnection } from './streaming/webrtc-connection.js';
|
|
9
|
+
import { StreamingSession } from './streaming/streaming-session.js';
|
|
10
|
+
import { SimpleWebRtcSession } from './streaming/simple-webrtc-session.js';
|
|
11
11
|
const maxSnapshotRefreshSeconds = 15, fullDayMs = 24 * 60 * 60 * 1000;
|
|
12
12
|
function parseBatteryLife(batteryLife) {
|
|
13
13
|
if (batteryLife === null || batteryLife === undefined) {
|
package/lib/ring-chime.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChimeModel } from
|
|
2
|
-
import { clientApi, deviceApi } from
|
|
1
|
+
import { ChimeModel } from './ring-types.js';
|
|
2
|
+
import { clientApi, deviceApi } from './rest-client.js';
|
|
3
3
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
4
|
const settingsWhichRequireReboot = [
|
|
5
5
|
'ding_audio_id',
|
package/lib/ring-device.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import { deviceTypesWithVolume } from
|
|
2
|
+
import { deviceTypesWithVolume } from './ring-types.js';
|
|
3
3
|
import { filter, map } from 'rxjs/operators';
|
|
4
|
-
import { Subscribed } from
|
|
5
|
-
import { logError } from
|
|
4
|
+
import { Subscribed } from './subscribed.js';
|
|
5
|
+
import { logError } from './util.js';
|
|
6
6
|
export class RingDevice extends Subscribed {
|
|
7
7
|
onData;
|
|
8
8
|
zid;
|
package/lib/ring-intercom.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { PushNotificationAction } from
|
|
2
|
-
import { clientApi, commandsApi } from
|
|
1
|
+
import { PushNotificationAction } from './ring-types.js';
|
|
2
|
+
import { clientApi, commandsApi } from './rest-client.js';
|
|
3
3
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
4
4
|
import { distinctUntilChanged, map } from 'rxjs/operators';
|
|
5
|
-
import { getBatteryLevel } from
|
|
6
|
-
import { logError } from
|
|
5
|
+
import { getBatteryLevel } from './ring-camera.js';
|
|
6
|
+
import { logError } from './util.js';
|
|
7
7
|
export class RingIntercom {
|
|
8
8
|
id;
|
|
9
9
|
deviceType;
|
package/lib/ring-types.d.ts
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
1
|
type Firmware = string | 'Up To Date';
|
|
2
2
|
export declare const RingDeviceType: {
|
|
3
|
-
readonly BaseStation:
|
|
4
|
-
readonly BaseStationPro:
|
|
5
|
-
readonly Keypad:
|
|
6
|
-
readonly SecurityPanel:
|
|
7
|
-
readonly ContactSensor:
|
|
8
|
-
readonly MotionSensor:
|
|
9
|
-
readonly FloodFreezeSensor:
|
|
10
|
-
readonly FreezeSensor:
|
|
11
|
-
readonly TemperatureSensor:
|
|
12
|
-
readonly WaterSensor:
|
|
13
|
-
readonly TiltSensor:
|
|
14
|
-
readonly GlassbreakSensor:
|
|
15
|
-
readonly RangeExtender:
|
|
16
|
-
readonly ZigbeeAdapter:
|
|
17
|
-
readonly AccessCodeVault:
|
|
18
|
-
readonly AccessCode:
|
|
19
|
-
readonly SmokeAlarm:
|
|
20
|
-
readonly CoAlarm:
|
|
21
|
-
readonly SmokeCoListener:
|
|
22
|
-
readonly MultiLevelSwitch:
|
|
23
|
-
readonly Fan:
|
|
24
|
-
readonly MultiLevelBulb:
|
|
25
|
-
readonly Switch:
|
|
26
|
-
readonly BeamsMotionSensor:
|
|
27
|
-
readonly BeamsSwitch:
|
|
28
|
-
readonly BeamsMultiLevelSwitch:
|
|
29
|
-
readonly BeamsLightGroupSwitch:
|
|
30
|
-
readonly BeamsTransformerSwitch:
|
|
31
|
-
readonly BeamsDevice:
|
|
32
|
-
readonly RetrofitBridge:
|
|
33
|
-
readonly RetrofitZone:
|
|
34
|
-
readonly Thermostat:
|
|
35
|
-
readonly Sensor:
|
|
36
|
-
readonly RingNetAdapter:
|
|
37
|
-
readonly CodeVault:
|
|
38
|
-
readonly SecurityAccessCode:
|
|
39
|
-
readonly ZWaveAdapter:
|
|
40
|
-
readonly ZWaveExtender:
|
|
41
|
-
readonly PanicButton:
|
|
42
|
-
readonly UnknownZWave:
|
|
43
|
-
readonly OnvifCamera:
|
|
44
|
-
readonly ThirdPartyGarageDoorOpener:
|
|
45
|
-
readonly IntercomHandsetAudio:
|
|
46
|
-
readonly IntercomHandsetVideo:
|
|
47
|
-
readonly WaterValve:
|
|
48
|
-
readonly KiddeSmokeCoAlarm:
|
|
3
|
+
readonly BaseStation: 'hub.redsky';
|
|
4
|
+
readonly BaseStationPro: 'hub.kili';
|
|
5
|
+
readonly Keypad: 'security-keypad';
|
|
6
|
+
readonly SecurityPanel: 'security-panel';
|
|
7
|
+
readonly ContactSensor: 'sensor.contact';
|
|
8
|
+
readonly MotionSensor: 'sensor.motion';
|
|
9
|
+
readonly FloodFreezeSensor: 'sensor.flood-freeze';
|
|
10
|
+
readonly FreezeSensor: 'sensor.freeze';
|
|
11
|
+
readonly TemperatureSensor: 'sensor.temperature';
|
|
12
|
+
readonly WaterSensor: 'sensor.water';
|
|
13
|
+
readonly TiltSensor: 'sensor.tilt';
|
|
14
|
+
readonly GlassbreakSensor: 'sensor.glassbreak';
|
|
15
|
+
readonly RangeExtender: 'range-extender.zwave';
|
|
16
|
+
readonly ZigbeeAdapter: 'adapter.zigbee';
|
|
17
|
+
readonly AccessCodeVault: 'access-code.vault';
|
|
18
|
+
readonly AccessCode: 'access-code';
|
|
19
|
+
readonly SmokeAlarm: 'alarm.smoke';
|
|
20
|
+
readonly CoAlarm: 'alarm.co';
|
|
21
|
+
readonly SmokeCoListener: 'listener.smoke-co';
|
|
22
|
+
readonly MultiLevelSwitch: 'switch.multilevel';
|
|
23
|
+
readonly Fan: 'switch.multilevel';
|
|
24
|
+
readonly MultiLevelBulb: 'switch.multilevel.bulb';
|
|
25
|
+
readonly Switch: 'switch';
|
|
26
|
+
readonly BeamsMotionSensor: 'motion-sensor.beams';
|
|
27
|
+
readonly BeamsSwitch: 'switch.beams';
|
|
28
|
+
readonly BeamsMultiLevelSwitch: 'switch.multilevel.beams';
|
|
29
|
+
readonly BeamsLightGroupSwitch: 'group.light-group.beams';
|
|
30
|
+
readonly BeamsTransformerSwitch: 'switch.transformer.beams';
|
|
31
|
+
readonly BeamsDevice: 'device.beams';
|
|
32
|
+
readonly RetrofitBridge: 'bridge.flatline';
|
|
33
|
+
readonly RetrofitZone: 'sensor.zone';
|
|
34
|
+
readonly Thermostat: 'temperature-control.thermostat';
|
|
35
|
+
readonly Sensor: 'sensor';
|
|
36
|
+
readonly RingNetAdapter: 'adapter.ringnet';
|
|
37
|
+
readonly CodeVault: 'access-code.vault';
|
|
38
|
+
readonly SecurityAccessCode: 'access-code';
|
|
39
|
+
readonly ZWaveAdapter: 'adapter.zwave';
|
|
40
|
+
readonly ZWaveExtender: 'range-extender.zwave';
|
|
41
|
+
readonly PanicButton: 'security-panic';
|
|
42
|
+
readonly UnknownZWave: 'unknown.zwave';
|
|
43
|
+
readonly OnvifCamera: 'onvif_camera';
|
|
44
|
+
readonly ThirdPartyGarageDoorOpener: 'third_party_gdo';
|
|
45
|
+
readonly IntercomHandsetAudio: 'intercom_handset_audio';
|
|
46
|
+
readonly IntercomHandsetVideo: 'intercom_handset_video';
|
|
47
|
+
readonly WaterValve: 'valve.water';
|
|
48
|
+
readonly KiddeSmokeCoAlarm: 'comp.bluejay.sensor_bluejay_wsc';
|
|
49
49
|
};
|
|
50
50
|
export type RingDeviceType = (typeof RingDeviceType)[keyof typeof RingDeviceType];
|
|
51
51
|
export declare const RingDeviceCategory: {
|
|
@@ -70,40 +70,40 @@ export declare const RingDeviceCategory: {
|
|
|
70
70
|
};
|
|
71
71
|
export type RingDeviceCategory = (typeof RingDeviceCategory)[keyof typeof RingDeviceCategory];
|
|
72
72
|
export declare const RingCameraKind: {
|
|
73
|
-
readonly doorbot:
|
|
74
|
-
readonly doorbell:
|
|
75
|
-
readonly doorbell_v3:
|
|
76
|
-
readonly doorbell_v4:
|
|
77
|
-
readonly doorbell_v5:
|
|
78
|
-
readonly doorbell_oyster:
|
|
79
|
-
readonly doorbell_portal:
|
|
80
|
-
readonly doorbell_scallop:
|
|
81
|
-
readonly doorbell_scallop_lite:
|
|
82
|
-
readonly doorbell_graham_cracker:
|
|
83
|
-
readonly lpd_v1:
|
|
84
|
-
readonly lpd_v2:
|
|
85
|
-
readonly lpd_v4:
|
|
86
|
-
readonly jbox_v1:
|
|
87
|
-
readonly stickup_cam:
|
|
88
|
-
readonly stickup_cam_v3:
|
|
89
|
-
readonly stickup_cam_elite:
|
|
90
|
-
readonly stickup_cam_longfin:
|
|
91
|
-
readonly stickup_cam_lunar:
|
|
92
|
-
readonly spotlightw_v2:
|
|
93
|
-
readonly hp_cam_v1:
|
|
94
|
-
readonly hp_cam_v2:
|
|
95
|
-
readonly stickup_cam_v4:
|
|
96
|
-
readonly floodlight_v1:
|
|
97
|
-
readonly floodlight_v2:
|
|
98
|
-
readonly floodlight_pro:
|
|
99
|
-
readonly cocoa_camera:
|
|
100
|
-
readonly cocoa_doorbell:
|
|
101
|
-
readonly cocoa_doorbell_v2:
|
|
102
|
-
readonly cocoa_doorbell_v3:
|
|
103
|
-
readonly cocoa_floodlight:
|
|
104
|
-
readonly cocoa_spotlight:
|
|
105
|
-
readonly stickup_cam_mini:
|
|
106
|
-
readonly onvif_camera:
|
|
73
|
+
readonly doorbot: 'doorbot';
|
|
74
|
+
readonly doorbell: 'doorbell';
|
|
75
|
+
readonly doorbell_v3: 'doorbell_v3';
|
|
76
|
+
readonly doorbell_v4: 'doorbell_v4';
|
|
77
|
+
readonly doorbell_v5: 'doorbell_v5';
|
|
78
|
+
readonly doorbell_oyster: 'doorbell_oyster';
|
|
79
|
+
readonly doorbell_portal: 'doorbell_portal';
|
|
80
|
+
readonly doorbell_scallop: 'doorbell_scallop';
|
|
81
|
+
readonly doorbell_scallop_lite: 'doorbell_scallop_lite';
|
|
82
|
+
readonly doorbell_graham_cracker: 'doorbell_graham_cracker';
|
|
83
|
+
readonly lpd_v1: 'lpd_v1';
|
|
84
|
+
readonly lpd_v2: 'lpd_v2';
|
|
85
|
+
readonly lpd_v4: 'lpd_v4';
|
|
86
|
+
readonly jbox_v1: 'jbox_v1';
|
|
87
|
+
readonly stickup_cam: 'stickup_cam';
|
|
88
|
+
readonly stickup_cam_v3: 'stickup_cam_v3';
|
|
89
|
+
readonly stickup_cam_elite: 'stickup_cam_elite';
|
|
90
|
+
readonly stickup_cam_longfin: 'stickup_cam_longfin';
|
|
91
|
+
readonly stickup_cam_lunar: 'stickup_cam_lunar';
|
|
92
|
+
readonly spotlightw_v2: 'spotlightw_v2';
|
|
93
|
+
readonly hp_cam_v1: 'hp_cam_v1';
|
|
94
|
+
readonly hp_cam_v2: 'hp_cam_v2';
|
|
95
|
+
readonly stickup_cam_v4: 'stickup_cam_v4';
|
|
96
|
+
readonly floodlight_v1: 'floodlight_v1';
|
|
97
|
+
readonly floodlight_v2: 'floodlight_v2';
|
|
98
|
+
readonly floodlight_pro: 'floodlight_pro';
|
|
99
|
+
readonly cocoa_camera: 'cocoa_camera';
|
|
100
|
+
readonly cocoa_doorbell: 'cocoa_doorbell';
|
|
101
|
+
readonly cocoa_doorbell_v2: 'cocoa_doorbell_v2';
|
|
102
|
+
readonly cocoa_doorbell_v3: 'cocoa_doorbell_v3';
|
|
103
|
+
readonly cocoa_floodlight: 'cocoa_floodlight';
|
|
104
|
+
readonly cocoa_spotlight: 'cocoa_spotlight';
|
|
105
|
+
readonly stickup_cam_mini: 'stickup_cam_mini';
|
|
106
|
+
readonly onvif_camera: 'onvif_camera';
|
|
107
107
|
};
|
|
108
108
|
export type RingCameraKind = (typeof RingCameraKind)[keyof typeof RingCameraKind];
|
|
109
109
|
export declare const RingCameraModel: {
|
|
@@ -884,23 +884,23 @@ export interface RingDeviceHistoryEvent {
|
|
|
884
884
|
}
|
|
885
885
|
export type DingState = 'ringing' | 'connected' | 'timed_out' | 'completed';
|
|
886
886
|
export declare const NotificationDetectionType: {
|
|
887
|
-
readonly Human:
|
|
888
|
-
readonly Loitering:
|
|
889
|
-
readonly Motion:
|
|
890
|
-
readonly OtherMotion:
|
|
891
|
-
readonly NotAvailable:
|
|
892
|
-
readonly StreamBroken:
|
|
887
|
+
readonly Human: 'human';
|
|
888
|
+
readonly Loitering: 'loitering';
|
|
889
|
+
readonly Motion: 'motion';
|
|
890
|
+
readonly OtherMotion: 'other_motion';
|
|
891
|
+
readonly NotAvailable: 'null';
|
|
892
|
+
readonly StreamBroken: 'stream_broken';
|
|
893
893
|
};
|
|
894
894
|
export type NotificationDetectionType = (typeof NotificationDetectionType)[keyof typeof NotificationDetectionType];
|
|
895
895
|
export declare const PushNotificationAction: {
|
|
896
|
-
readonly Ding:
|
|
897
|
-
readonly Motion:
|
|
898
|
-
readonly IntercomDing:
|
|
899
|
-
readonly IntercomUnlock:
|
|
900
|
-
readonly AlarmModeNone:
|
|
901
|
-
readonly AlarmModeSome:
|
|
902
|
-
readonly AlarmSoundSiren:
|
|
903
|
-
readonly AlarmSilenceSiren:
|
|
896
|
+
readonly Ding: 'com.ring.pn.live-event.ding';
|
|
897
|
+
readonly Motion: 'com.ring.pn.live-event.motion';
|
|
898
|
+
readonly IntercomDing: 'com.ring.pn.live-event.intercom';
|
|
899
|
+
readonly IntercomUnlock: 'com.ring.push.INTERCOM_UNLOCK_FROM_APP';
|
|
900
|
+
readonly AlarmModeNone: 'com.ring.push.HANDLE_NEW_SECURITY_PANEL_MODE_NONE_NOTICE';
|
|
901
|
+
readonly AlarmModeSome: 'com.ring.push.HANDLE_NEW_SECURITY_PANEL_MODE_SOME_NOTICE';
|
|
902
|
+
readonly AlarmSoundSiren: 'com.ring.push.HANDLE_NEW_USER_SOUND_SIREN';
|
|
903
|
+
readonly AlarmSilenceSiren: 'com.ring.push.HANDLE_NEW_NON_ALARM_SIREN_SILENCED';
|
|
904
904
|
};
|
|
905
905
|
export type PushNotificationAction = (typeof PushNotificationAction)[keyof typeof PushNotificationAction];
|
|
906
906
|
export interface PushNotificationDingV2 {
|
|
@@ -1051,8 +1051,8 @@ export interface AccountMonitoringStatus {
|
|
|
1051
1051
|
dispatchSetupComplete: boolean;
|
|
1052
1052
|
}
|
|
1053
1053
|
export declare const DispatchSignalType: {
|
|
1054
|
-
readonly Burglar:
|
|
1055
|
-
readonly Fire:
|
|
1054
|
+
readonly Burglar: 'user-verified-burglar-xa';
|
|
1055
|
+
readonly Fire: 'user-verified-fire-xa';
|
|
1056
1056
|
};
|
|
1057
1057
|
export type DispatchSignalType = (typeof DispatchSignalType)[keyof typeof DispatchSignalType];
|
|
1058
1058
|
export type LocationModeInput = 'home' | 'away' | 'disarmed';
|
|
@@ -24,7 +24,7 @@ export declare class WeriftPeerConnection extends Subscribed implements BasicPee
|
|
|
24
24
|
onVideoRtp: Subject<RtpPacket>;
|
|
25
25
|
onVideoRtcp: Subject<RtcpPacket>;
|
|
26
26
|
onIceCandidate: Subject<RTCIceCandidate>;
|
|
27
|
-
onConnectionState: ReplaySubject<"closed" | "connected" | "
|
|
27
|
+
onConnectionState: ReplaySubject<"closed" | "connected" | "connecting" | "disconnected" | "failed" | "new">;
|
|
28
28
|
returnAudioTrack: MediaStreamTrack;
|
|
29
29
|
private onRequestKeyFrame;
|
|
30
30
|
constructor();
|
|
@@ -33,7 +33,7 @@ export declare class WeriftPeerConnection extends Subscribed implements BasicPee
|
|
|
33
33
|
type: 'answer';
|
|
34
34
|
sdp: string;
|
|
35
35
|
}): Promise<void>;
|
|
36
|
-
addIceCandidate(candidate: RTCIceCandidate): Promise<void>;
|
|
36
|
+
addIceCandidate(candidate: Partial<RTCIceCandidate>): Promise<void>;
|
|
37
37
|
requestKeyFrame(): void;
|
|
38
38
|
close(): void;
|
|
39
39
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MediaStreamTrack, RTCPeerConnection, RTCRtpCodecParameters, } from 'werift';
|
|
2
2
|
import { interval, merge, ReplaySubject, Subject } from 'rxjs';
|
|
3
|
-
import { logDebug, logError, logInfo } from
|
|
4
|
-
import { Subscribed } from
|
|
3
|
+
import { logDebug, logError, logInfo } from '../util.js';
|
|
4
|
+
import { Subscribed } from '../subscribed.js';
|
|
5
5
|
const ringIceServers = [
|
|
6
6
|
'stun:stun.kinesisvideo.us-east-1.amazonaws.com:443',
|
|
7
7
|
'stun:stun.kinesisvideo.us-east-2.amazonaws.com:443',
|
|
@@ -24,6 +24,10 @@ interface SessionStartedMessage {
|
|
|
24
24
|
method: 'session_started';
|
|
25
25
|
body: SessionBody;
|
|
26
26
|
}
|
|
27
|
+
interface PingMessage {
|
|
28
|
+
method: 'ping';
|
|
29
|
+
body: SessionBody;
|
|
30
|
+
}
|
|
27
31
|
interface PongMessage {
|
|
28
32
|
method: 'pong';
|
|
29
33
|
body: SessionBody;
|
|
@@ -46,12 +50,12 @@ interface StreamInfoMessage {
|
|
|
46
50
|
transcoding_reason: 'codec_mismatch' | string;
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
type CloseReasonCode =
|
|
53
|
+
interface CloseReasonCodes {
|
|
54
|
+
NormalClose: 0;
|
|
55
|
+
AuthenticationFailed: 5;
|
|
56
|
+
Timeout: 6;
|
|
57
|
+
}
|
|
58
|
+
type CloseReasonCode = CloseReasonCodes[keyof CloseReasonCodes];
|
|
55
59
|
interface CloseMessage {
|
|
56
60
|
method: 'close';
|
|
57
61
|
body: {
|
|
@@ -61,5 +65,5 @@ interface CloseMessage {
|
|
|
61
65
|
};
|
|
62
66
|
} & SessionBody;
|
|
63
67
|
}
|
|
64
|
-
export type IncomingMessage = AnswerMessage | IceCandidateMessage | SessionCreatedMessage | SessionStartedMessage | PongMessage | CloseMessage | NotificationMessage | CameraStartedMessage | StreamInfoMessage;
|
|
68
|
+
export type IncomingMessage = AnswerMessage | IceCandidateMessage | SessionCreatedMessage | SessionStartedMessage | PingMessage | PongMessage | CloseMessage | NotificationMessage | CameraStartedMessage | StreamInfoMessage;
|
|
65
69
|
export {};
|
|
@@ -1,10 +1 @@
|
|
|
1
|
-
const CloseReasonCode = {
|
|
2
|
-
NormalClose: 0,
|
|
3
|
-
// reason: { code: 5, text: '[rsl-apps/webrtc-liveview-server/Session.cpp:429] [Auth] [0xd540]: [rsl-apps/session-manager/Manager.cpp:227] [AppAuth] Unauthorized: invalid or expired token' }
|
|
4
|
-
// reason: { code: 5, text: 'Authentication failed: -1' }
|
|
5
|
-
// reason: { code: 5, text: 'Sessions with the provided ID not found' }
|
|
6
|
-
AuthenticationFailed: 5,
|
|
7
|
-
// reason: { code: 6, text: 'Timeout waiting for ping' }
|
|
8
|
-
Timeout: 6,
|
|
9
|
-
};
|
|
10
1
|
export {};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { RtpPacket } from 'werift';
|
|
2
2
|
import { FfmpegProcess, reservePorts, RtpSplitter, } from '@homebridge/camera-utils';
|
|
3
3
|
import { firstValueFrom, ReplaySubject, Subject } from 'rxjs';
|
|
4
|
-
import { getFfmpegPath } from
|
|
5
|
-
import { logDebug, logError } from
|
|
4
|
+
import { getFfmpegPath } from '../ffmpeg.js';
|
|
5
|
+
import { logDebug, logError } from '../util.js';
|
|
6
6
|
import { concatMap, map, mergeWith, take } from 'rxjs/operators';
|
|
7
|
-
import { Subscribed } from
|
|
7
|
+
import { Subscribed } from '../subscribed.js';
|
|
8
8
|
function getCleanSdp(sdp, includeVideo) {
|
|
9
9
|
return sdp
|
|
10
10
|
.split('\nm=')
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { WebSocket } from 'undici';
|
|
2
2
|
import { firstValueFrom, fromEvent, interval, ReplaySubject, Subject, } from 'rxjs';
|
|
3
3
|
import { concatMap, take } from 'rxjs/operators';
|
|
4
|
-
import { generateUuid, logDebug, logError, logInfo } from
|
|
5
|
-
import { WeriftPeerConnection, } from
|
|
6
|
-
import { Subscribed } from
|
|
4
|
+
import { generateUuid, logDebug, logError, logInfo } from '../util.js';
|
|
5
|
+
import { WeriftPeerConnection, } from './peer-connection.js';
|
|
6
|
+
import { Subscribed } from '../subscribed.js';
|
|
7
7
|
export class WebrtcConnection extends Subscribed {
|
|
8
8
|
onSessionId = new ReplaySubject(1);
|
|
9
9
|
onOfferSent = new ReplaySubject(1);
|
|
@@ -143,6 +143,9 @@ export class WebrtcConnection extends Subscribed {
|
|
|
143
143
|
sdpMLineIndex: message.body.mlineindex,
|
|
144
144
|
});
|
|
145
145
|
return;
|
|
146
|
+
case 'ping':
|
|
147
|
+
this.sendSessionMessage('pong');
|
|
148
|
+
return;
|
|
146
149
|
case 'pong':
|
|
147
150
|
return;
|
|
148
151
|
case 'notification': {
|
|
@@ -239,7 +242,7 @@ export class WebrtcConnection extends Subscribed {
|
|
|
239
242
|
});
|
|
240
243
|
this.ws.close();
|
|
241
244
|
}
|
|
242
|
-
catch
|
|
245
|
+
catch {
|
|
243
246
|
// ignore any errors since we are stopping the call
|
|
244
247
|
}
|
|
245
248
|
this.hasEnded = true;
|
package/lib/util.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare function enableDebug(): void;
|
|
|
12
12
|
export declare function generateUuid(seed?: string): string;
|
|
13
13
|
export declare function getHardwareId(systemId?: string): Promise<string>;
|
|
14
14
|
export declare function requestInput(question: string): Promise<string>;
|
|
15
|
+
export declare function requestHiddenInput(question: string): Promise<string>;
|
|
15
16
|
export declare function stringify(data: any): string;
|
|
16
17
|
export declare function mapAsync<T, U>(records: T[], asyncMapper: (record: T) => Promise<U>): Promise<U[]>;
|
|
17
18
|
export declare function randomInteger(): number;
|
package/lib/util.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import debug from 'debug';
|
|
2
2
|
import colors from 'colors';
|
|
3
3
|
import { createInterface } from 'readline';
|
|
4
|
+
import { Writable } from 'stream';
|
|
4
5
|
import { v4 as generateRandomUuid, v5 as generateUuidFromNamespace } from 'uuid';
|
|
5
6
|
import { uuid as getSystemUuid } from 'systeminformation';
|
|
6
7
|
import pushReceiverLogger from '@eneris/push-receiver/dist/utils/logger.js';
|
|
@@ -80,6 +81,27 @@ export async function requestInput(question) {
|
|
|
80
81
|
lineReader.close();
|
|
81
82
|
return answer.trim();
|
|
82
83
|
}
|
|
84
|
+
export async function requestHiddenInput(question) {
|
|
85
|
+
const lineReader = createInterface({
|
|
86
|
+
input: process.stdin,
|
|
87
|
+
// Discard readline's echo of each keystroke so the input stays hidden
|
|
88
|
+
output: new Writable({
|
|
89
|
+
write(_chunk, _encoding, callback) {
|
|
90
|
+
callback();
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
// Puts a TTY stdin in raw mode so the terminal doesn't echo the input either
|
|
94
|
+
terminal: true,
|
|
95
|
+
});
|
|
96
|
+
process.stdout.write(question);
|
|
97
|
+
const answer = await new Promise((resolve) => {
|
|
98
|
+
lineReader.question('', resolve);
|
|
99
|
+
});
|
|
100
|
+
lineReader.close();
|
|
101
|
+
// The newline readline writes when enter is pressed was discarded with the echo
|
|
102
|
+
process.stdout.write('\n');
|
|
103
|
+
return answer.trim();
|
|
104
|
+
}
|
|
83
105
|
export function stringify(data) {
|
|
84
106
|
if (typeof data === 'string') {
|
|
85
107
|
return data;
|
|
@@ -107,7 +129,7 @@ function logPushReceiver(...args) {
|
|
|
107
129
|
return;
|
|
108
130
|
}
|
|
109
131
|
}
|
|
110
|
-
catch
|
|
132
|
+
catch {
|
|
111
133
|
// proceed to log error
|
|
112
134
|
}
|
|
113
135
|
logDebug('[Push Receiver]');
|
package/package.json
CHANGED
|
@@ -1,48 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ring-client-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.0.0-beta.0",
|
|
4
4
|
"description": "Unofficial API for Ring doorbells, cameras, security alarm system and smart lighting",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
|
-
".":
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./lib/index.d.ts",
|
|
10
|
+
"ring-dev": "./index.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./ffmpeg": {
|
|
14
|
+
"types": "./lib/ffmpeg.d.ts",
|
|
15
|
+
"ring-dev": "./ffmpeg.ts",
|
|
16
|
+
"default": "./lib/ffmpeg.js"
|
|
17
|
+
},
|
|
18
|
+
"./util": {
|
|
19
|
+
"types": "./lib/util.d.ts",
|
|
20
|
+
"ring-dev": "./util.ts",
|
|
21
|
+
"default": "./lib/util.js"
|
|
22
|
+
},
|
|
23
|
+
"./rest-client": {
|
|
24
|
+
"types": "./lib/rest-client.d.ts",
|
|
25
|
+
"ring-dev": "./rest-client.ts",
|
|
26
|
+
"default": "./lib/rest-client.js"
|
|
27
|
+
},
|
|
28
|
+
"./streaming/streaming-session": {
|
|
29
|
+
"types": "./lib/streaming/streaming-session.d.ts",
|
|
30
|
+
"ring-dev": "./streaming/streaming-session.ts",
|
|
31
|
+
"default": "./lib/streaming/streaming-session.js"
|
|
32
|
+
}
|
|
13
33
|
},
|
|
14
34
|
"scripts": {
|
|
15
35
|
"build": "rm -rf lib && tsc --declaration && chmod +x ./lib/ring-*-cli.js && rm -rf ./lib/test",
|
|
16
|
-
"
|
|
36
|
+
"auth-cli": "node --conditions=ring-dev --env-file-if-exists=../../.env ./ring-auth-cli.ts",
|
|
37
|
+
"device-data-cli": "node --conditions=ring-dev --env-file-if-exists=../../.env ./ring-device-data-cli.ts",
|
|
17
38
|
"lint": "eslint .",
|
|
18
39
|
"test": "vitest run"
|
|
19
40
|
},
|
|
20
41
|
"dependencies": {
|
|
21
|
-
"@eneris/push-receiver": "4.
|
|
42
|
+
"@eneris/push-receiver": "4.4.0",
|
|
22
43
|
"@homebridge/camera-utils": "^3.0.0",
|
|
23
44
|
"colors": "1.4.0",
|
|
24
45
|
"debug": "^4.4.3",
|
|
25
46
|
"json-bigint": "^1.0.0",
|
|
26
47
|
"rxjs": "^7.8.2",
|
|
27
|
-
"systeminformation": "^5.
|
|
28
|
-
"undici": "^
|
|
29
|
-
"uuid": "^
|
|
30
|
-
"werift": "0.
|
|
48
|
+
"systeminformation": "^5.33.19",
|
|
49
|
+
"undici": "^8.12.3",
|
|
50
|
+
"uuid": "^14.0.3",
|
|
51
|
+
"werift": "0.26.0"
|
|
31
52
|
},
|
|
32
53
|
"devDependencies": {
|
|
33
|
-
"@types/debug": "4.1.
|
|
54
|
+
"@types/debug": "4.1.13",
|
|
34
55
|
"@types/json-bigint": "^1.0.4",
|
|
35
|
-
"@types/node": "
|
|
36
|
-
"@types/
|
|
37
|
-
"@types/ws": "^8.18.1",
|
|
56
|
+
"@types/node": "26.6.6",
|
|
57
|
+
"@types/ws": "^8.18.2",
|
|
38
58
|
"eslint-config-shared": "*",
|
|
39
|
-
"msw": "^
|
|
59
|
+
"msw": "^3.0.3",
|
|
40
60
|
"tsconfig": "*",
|
|
41
|
-
"typescript": "
|
|
42
|
-
"vitest": "^
|
|
61
|
+
"typescript": "7.0.2",
|
|
62
|
+
"vitest": "^5.1.0"
|
|
43
63
|
},
|
|
44
64
|
"engines": {
|
|
45
|
-
"node": "^
|
|
65
|
+
"node": "^22.19.0 || ^24 || ^26"
|
|
46
66
|
},
|
|
47
67
|
"repository": {
|
|
48
68
|
"type": "git",
|