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
@@ -1,22 +1,19 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WebrtcConnection = void 0;
4
- const ws_1 = require("ws");
5
- const rxjs_1 = require("rxjs");
6
- const operators_1 = require("rxjs/operators");
7
- const util_1 = require("../util");
8
- const peer_connection_1 = require("./peer-connection");
9
- const subscribed_1 = require("../subscribed");
10
- class WebrtcConnection extends subscribed_1.Subscribed {
1
+ import { WebSocket } from 'ws';
2
+ import { firstValueFrom, fromEvent, interval, ReplaySubject, Subject, } from 'rxjs';
3
+ import { concatMap, take } from 'rxjs/operators';
4
+ import { generateUuid, logDebug, logError, logInfo } from "../util.js";
5
+ import { WeriftPeerConnection, } from "./peer-connection.js";
6
+ import { Subscribed } from "../subscribed.js";
7
+ export class WebrtcConnection extends Subscribed {
11
8
  camera;
12
- onSessionId = new rxjs_1.ReplaySubject(1);
13
- onOfferSent = new rxjs_1.ReplaySubject(1);
14
- dialogId = (0, util_1.generateUuid)();
15
- onCameraConnected = new rxjs_1.ReplaySubject(1);
16
- onCallAnswered = new rxjs_1.ReplaySubject(1);
17
- onCallEnded = new rxjs_1.ReplaySubject(1);
18
- onError = new rxjs_1.ReplaySubject(1);
19
- onMessage = new rxjs_1.ReplaySubject();
9
+ onSessionId = new ReplaySubject(1);
10
+ onOfferSent = new ReplaySubject(1);
11
+ dialogId = generateUuid();
12
+ onCameraConnected = new ReplaySubject(1);
13
+ onCallAnswered = new ReplaySubject(1);
14
+ onCallEnded = new ReplaySubject(1);
15
+ onError = new ReplaySubject(1);
16
+ onMessage = new ReplaySubject();
20
17
  onWsOpen;
21
18
  onAudioRtp;
22
19
  onVideoRtp;
@@ -25,7 +22,7 @@ class WebrtcConnection extends subscribed_1.Subscribed {
25
22
  constructor(ticket, camera, options) {
26
23
  super();
27
24
  this.camera = camera;
28
- this.ws = new ws_1.WebSocket(`wss://api.prod.signalling.ring.devices.a2z.com:443/ws?api_version=4.0&auth_type=ring_solutions&client_id=ring_site-${(0, util_1.generateUuid)()}&token=${ticket}`, {
25
+ this.ws = new WebSocket(`wss://api.prod.signalling.ring.devices.a2z.com:443/ws?api_version=4.0&auth_type=ring_solutions&client_id=ring_site-${generateUuid()}&token=${ticket}`, {
29
26
  headers: {
30
27
  // This must exist or the socket will close immediately but content does not seem to matter
31
28
  'User-Agent': 'android:com.ringapp',
@@ -35,20 +32,20 @@ class WebrtcConnection extends subscribed_1.Subscribed {
35
32
  // we were passed a custom peer connection factory
36
33
  this.pc = options.createPeerConnection();
37
34
  // passing rtp packets is not supported for custom peer connections
38
- this.onAudioRtp = new rxjs_1.Subject();
39
- this.onVideoRtp = new rxjs_1.Subject();
35
+ this.onAudioRtp = new Subject();
36
+ this.onVideoRtp = new Subject();
40
37
  }
41
38
  else {
42
39
  // no custom peer connection factory, use the werift and pass along rtp packets
43
- const pc = new peer_connection_1.WeriftPeerConnection();
40
+ const pc = new WeriftPeerConnection();
44
41
  this.pc = pc;
45
42
  this.onAudioRtp = pc.onAudioRtp;
46
43
  this.onVideoRtp = pc.onVideoRtp;
47
44
  }
48
- this.onWsOpen = (0, rxjs_1.fromEvent)(this.ws, 'open');
49
- const onMessage = (0, rxjs_1.fromEvent)(this.ws, 'message'), onError = (0, rxjs_1.fromEvent)(this.ws, 'error'), onClose = (0, rxjs_1.fromEvent)(this.ws, 'close');
45
+ this.onWsOpen = fromEvent(this.ws, 'open');
46
+ const onMessage = fromEvent(this.ws, 'message'), onError = fromEvent(this.ws, 'error'), onClose = fromEvent(this.ws, 'close');
50
47
  this.addSubscriptions(onMessage
51
- .pipe((0, operators_1.concatMap)((event) => {
48
+ .pipe(concatMap((event) => {
52
49
  const message = JSON.parse(event.data);
53
50
  this.onMessage.next(message);
54
51
  return this.handleMessage(message).catch((e) => {
@@ -61,35 +58,35 @@ class WebrtcConnection extends subscribed_1.Subscribed {
61
58
  });
62
59
  }))
63
60
  .subscribe(), onError.subscribe((e) => {
64
- (0, util_1.logError)(e);
61
+ logError(e);
65
62
  this.callEnded();
66
63
  }), onClose.subscribe(() => {
67
64
  this.callEnded();
68
65
  }), this.pc.onConnectionState.subscribe((state) => {
69
66
  if (state === 'failed') {
70
- (0, util_1.logError)('Stream connection failed');
67
+ logError('Stream connection failed');
71
68
  this.callEnded();
72
69
  }
73
70
  if (state === 'closed') {
74
- (0, util_1.logDebug)('Stream connection closed');
71
+ logDebug('Stream connection closed');
75
72
  this.callEnded();
76
73
  }
77
74
  }), this.onError.subscribe((e) => {
78
- (0, util_1.logError)(e);
75
+ logError(e);
79
76
  this.callEnded();
80
77
  }), this.onWsOpen.subscribe(() => {
81
78
  const connectionType = camera.isRingEdgeEnabled ? 'Ring Edge' : 'Cloud';
82
- (0, util_1.logDebug)(`WebSocket connected for ${camera.name} (${connectionType})`);
79
+ logDebug(`WebSocket connected for ${camera.name} (${connectionType})`);
83
80
  this.initiateCall().catch((e) => {
84
- (0, util_1.logError)(e);
81
+ logError(e);
85
82
  this.callEnded();
86
83
  });
87
84
  }),
88
85
  // The ring-edge session needs a ping every 5 seconds to keep the connection alive
89
- (0, rxjs_1.interval)(5000).subscribe(() => {
86
+ interval(5000).subscribe(() => {
90
87
  this.sendSessionMessage('ping');
91
88
  }), this.pc.onIceCandidate.subscribe(async (iceCandidate) => {
92
- await (0, rxjs_1.firstValueFrom)(this.onOfferSent);
89
+ await firstValueFrom(this.onOfferSent);
93
90
  this.sendMessage({
94
91
  method: 'ice',
95
92
  dialog_id: this.dialogId,
@@ -161,8 +158,8 @@ class WebrtcConnection extends subscribed_1.Subscribed {
161
158
  break;
162
159
  }
163
160
  case 'close':
164
- (0, util_1.logError)('Video stream closed');
165
- (0, util_1.logError)(message.body);
161
+ logError('Video stream closed');
162
+ logError(message.body);
166
163
  this.callEnded();
167
164
  return;
168
165
  case 'camera_started':
@@ -170,8 +167,8 @@ class WebrtcConnection extends subscribed_1.Subscribed {
170
167
  // ignore these messages as we don't use them
171
168
  return;
172
169
  }
173
- (0, util_1.logError)('UNKNOWN MESSAGE');
174
- (0, util_1.logError)(message);
170
+ logError('UNKNOWN MESSAGE');
171
+ logError(message);
175
172
  }
176
173
  sendSessionMessage(method, body = {}) {
177
174
  const sendSessionMessage = (sessionId) => {
@@ -193,7 +190,7 @@ class WebrtcConnection extends subscribed_1.Subscribed {
193
190
  }
194
191
  else {
195
192
  // Otherwise wait for the session id to be set and then send the message
196
- this.addSubscriptions(this.onSessionId.pipe((0, operators_1.take)(1)).subscribe(sendSessionMessage));
193
+ this.addSubscriptions(this.onSessionId.pipe(take(1)).subscribe(sendSessionMessage));
197
194
  }
198
195
  }
199
196
  sendMessage(message) {
@@ -206,7 +203,7 @@ class WebrtcConnection extends subscribed_1.Subscribed {
206
203
  if (this.hasEnded) {
207
204
  return;
208
205
  }
209
- if (this.pc instanceof peer_connection_1.WeriftPeerConnection) {
206
+ if (this.pc instanceof WeriftPeerConnection) {
210
207
  this.pc.returnAudioTrack.writeRtp(rtp);
211
208
  }
212
209
  else {
@@ -214,7 +211,7 @@ class WebrtcConnection extends subscribed_1.Subscribed {
214
211
  }
215
212
  }
216
213
  activate() {
217
- (0, util_1.logInfo)('Activating Session');
214
+ logInfo('Activating Session');
218
215
  // the activate_session message is required to keep the stream alive longer than 70 seconds
219
216
  this.sendSessionMessage('activate_session');
220
217
  this.sendSessionMessage('stream_options', {
@@ -224,7 +221,7 @@ class WebrtcConnection extends subscribed_1.Subscribed {
224
221
  }
225
222
  activateCameraSpeaker() {
226
223
  // Fire and forget this call so that callers don't get hung up waiting for answer (which might not happen)
227
- this.addSubscriptions(this.onCameraConnected.pipe((0, operators_1.take)(1)).subscribe(() => {
224
+ this.addSubscriptions(this.onCameraConnected.pipe(take(1)).subscribe(() => {
228
225
  this.sendSessionMessage('camera_options', {
229
226
  stealth_mode: false,
230
227
  });
@@ -257,4 +254,3 @@ class WebrtcConnection extends subscribed_1.Subscribed {
257
254
  this.pc.requestKeyFrame?.();
258
255
  }
259
256
  }
260
- exports.WebrtcConnection = WebrtcConnection;
@@ -1,4 +1,4 @@
1
- import { Subscription } from 'rxjs';
1
+ import type { Subscription } from 'rxjs';
2
2
  export declare class Subscribed {
3
3
  private readonly subscriptions;
4
4
  addSubscriptions(...subscriptions: Subscription[]): void;
package/lib/subscribed.js CHANGED
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Subscribed = void 0;
4
- class Subscribed {
1
+ export class Subscribed {
5
2
  subscriptions = [];
6
3
  addSubscriptions(...subscriptions) {
7
4
  this.subscriptions.push(...subscriptions);
@@ -10,4 +7,3 @@ class Subscribed {
10
7
  this.subscriptions.forEach((subscription) => subscription.unsubscribe());
11
8
  }
12
9
  }
13
- exports.Subscribed = Subscribed;
package/lib/util.js CHANGED
@@ -1,47 +1,25 @@
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.clearTimeouts = clearTimeouts;
7
- exports.delay = delay;
8
- exports.logDebug = logDebug;
9
- exports.logInfo = logInfo;
10
- exports.logError = logError;
11
- exports.useLogger = useLogger;
12
- exports.enableDebug = enableDebug;
13
- exports.generateUuid = generateUuid;
14
- exports.getHardwareId = getHardwareId;
15
- exports.requestInput = requestInput;
16
- exports.stringify = stringify;
17
- exports.mapAsync = mapAsync;
18
- exports.randomInteger = randomInteger;
19
- exports.randomString = randomString;
20
- exports.fromBase64 = fromBase64;
21
- exports.toBase64 = toBase64;
22
- exports.buildSearchString = buildSearchString;
23
- const debug_1 = __importDefault(require("debug"));
24
- const colors_1 = require("colors");
25
- const readline_1 = require("readline");
26
- const uuid_1 = require("uuid");
27
- const systeminformation_1 = require("systeminformation");
28
- const logger_1 = __importDefault(require("@eneris/push-receiver/dist/utils/logger"));
29
- const debugLogger = (0, debug_1.default)('ring'), uuidNamespace = 'e53ffdc0-e91d-4ce1-bec2-df939d94739d';
1
+ import debug from 'debug';
2
+ import colors from 'colors';
3
+ import { createInterface } from 'readline';
4
+ import { v4 as generateRandomUuid, v5 as generateUuidFromNamespace } from 'uuid';
5
+ import { uuid as getSystemUuid } from 'systeminformation';
6
+ import pushReceiverLogger from '@eneris/push-receiver/dist/utils/logger.js';
7
+ const debugLogger = debug('ring'), uuidNamespace = 'e53ffdc0-e91d-4ce1-bec2-df939d94739d';
30
8
  let logger = {
31
9
  logInfo(message) {
32
10
  debugLogger(message);
33
11
  },
34
12
  logError(message) {
35
- debugLogger((0, colors_1.red)(message));
13
+ debugLogger(colors.red(message));
36
14
  },
37
15
  }, debugEnabled = false;
38
16
  const timeouts = new Set();
39
- function clearTimeouts() {
17
+ export function clearTimeouts() {
40
18
  timeouts.forEach((timeout) => {
41
19
  clearTimeout(timeout);
42
20
  });
43
21
  }
44
- function delay(milliseconds) {
22
+ export function delay(milliseconds) {
45
23
  return new Promise((resolve) => {
46
24
  const timeout = setTimeout(() => {
47
25
  timeouts.delete(timeout);
@@ -50,50 +28,50 @@ function delay(milliseconds) {
50
28
  timeouts.add(timeout);
51
29
  });
52
30
  }
53
- function logDebug(message) {
31
+ export function logDebug(message) {
54
32
  if (debugEnabled) {
55
33
  logger.logInfo(message);
56
34
  }
57
35
  }
58
- function logInfo(...message) {
36
+ export function logInfo(...message) {
59
37
  logger.logInfo(...message);
60
38
  }
61
- function logError(message) {
39
+ export function logError(message) {
62
40
  logger.logError(message);
63
41
  }
64
- function useLogger(newLogger) {
42
+ export function useLogger(newLogger) {
65
43
  logger = newLogger;
66
44
  }
67
- function enableDebug() {
45
+ export function enableDebug() {
68
46
  debugEnabled = true;
69
47
  }
70
- function generateUuid(seed) {
48
+ export function generateUuid(seed) {
71
49
  if (seed) {
72
- return (0, uuid_1.v5)(seed, uuidNamespace);
50
+ return generateUuidFromNamespace(seed, uuidNamespace);
73
51
  }
74
- return (0, uuid_1.v4)();
52
+ return generateRandomUuid();
75
53
  }
76
- async function getHardwareId(systemId) {
54
+ export async function getHardwareId(systemId) {
77
55
  if (systemId) {
78
56
  return generateUuid(systemId);
79
57
  }
80
58
  const timeoutValue = '-1', { os: id } = await Promise.race([
81
- (0, systeminformation_1.uuid)(),
59
+ getSystemUuid(),
82
60
  delay(5000).then(() => ({ os: timeoutValue })),
83
61
  ]);
84
62
  if (id === timeoutValue) {
85
63
  logError('Request for system uuid timed out. Falling back to random session id');
86
- return (0, uuid_1.v4)();
64
+ return generateRandomUuid();
87
65
  }
88
66
  if (id === '-') {
89
67
  // default value set by systeminformation if it can't find a real value
90
68
  logError('Unable to get system uuid. Falling back to random session id');
91
- return (0, uuid_1.v4)();
69
+ return generateRandomUuid();
92
70
  }
93
71
  return generateUuid(id);
94
72
  }
95
- async function requestInput(question) {
96
- const lineReader = (0, readline_1.createInterface)({
73
+ export async function requestInput(question) {
74
+ const lineReader = createInterface({
97
75
  input: process.stdin,
98
76
  output: process.stdout,
99
77
  }), answer = await new Promise((resolve) => {
@@ -102,7 +80,7 @@ async function requestInput(question) {
102
80
  lineReader.close();
103
81
  return answer.trim();
104
82
  }
105
- function stringify(data) {
83
+ export function stringify(data) {
106
84
  if (typeof data === 'string') {
107
85
  return data;
108
86
  }
@@ -111,13 +89,13 @@ function stringify(data) {
111
89
  }
112
90
  return JSON.stringify(data) + '';
113
91
  }
114
- function mapAsync(records, asyncMapper) {
92
+ export function mapAsync(records, asyncMapper) {
115
93
  return Promise.all(records.map((record) => asyncMapper(record)));
116
94
  }
117
- function randomInteger() {
95
+ export function randomInteger() {
118
96
  return Math.floor(Math.random() * 99999999) + 100000;
119
97
  }
120
- function randomString(length) {
98
+ export function randomString(length) {
121
99
  const uuid = generateUuid();
122
100
  return uuid.replace(/-/g, '').substring(0, length).toLowerCase();
123
101
  }
@@ -135,16 +113,17 @@ function logPushReceiver(...args) {
135
113
  logDebug('[Push Receiver]');
136
114
  logDebug(args[0]);
137
115
  }
138
- logger_1.default.error = logPushReceiver;
139
- function fromBase64(encodedInput) {
116
+ const pushReceiverLoggerDefault = pushReceiverLogger.default || pushReceiverLogger; // fix for vitest
117
+ pushReceiverLoggerDefault.error = logPushReceiver;
118
+ export function fromBase64(encodedInput) {
140
119
  const buff = Buffer.from(encodedInput, 'base64');
141
120
  return buff.toString('ascii');
142
121
  }
143
- function toBase64(input) {
122
+ export function toBase64(input) {
144
123
  const buff = Buffer.from(input);
145
124
  return buff.toString('base64');
146
125
  }
147
- function buildSearchString(search) {
126
+ export function buildSearchString(search) {
148
127
  return ('?' +
149
128
  Object.entries(search)
150
129
  .filter(([, value]) => value !== undefined && value !== null)
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "ring-client-api",
3
- "version": "13.2.1-beta.1",
3
+ "version": "14.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
+ "type": "module",
6
7
  "exports": {
7
8
  ".": "./lib/index.js",
8
9
  "./ffmpeg": "./lib/ffmpeg.js",
@@ -11,40 +12,37 @@
11
12
  "./streaming/streaming-session": "./lib/streaming/streaming-session.js"
12
13
  },
13
14
  "scripts": {
14
- "build": "rm -rf lib && tsc --declaration && chmod +x ./lib/ring-*-cli.js",
15
+ "build": "rm -rf lib && tsc --declaration && chmod +x ./lib/ring-*-cli.js && rm -rf ./lib/test",
15
16
  "dev": "tsc --declaration --watch --preserveWatchOutput",
16
17
  "lint": "eslint .",
17
- "test": "jest",
18
- "test:watch": "jest --watch"
18
+ "test": "vitest run"
19
19
  },
20
20
  "dependencies": {
21
21
  "@eneris/push-receiver": "4.3.0",
22
- "@homebridge/camera-utils": "^2.2.7",
22
+ "@homebridge/camera-utils": "^3.0.0",
23
23
  "colors": "1.4.0",
24
- "debug": "^4.3.7",
24
+ "debug": "^4.4.0",
25
25
  "json-bigint": "^1.0.0",
26
26
  "rxjs": "^7.8.1",
27
27
  "socket.io-client": "^2.5.0",
28
- "systeminformation": "^5.23.5",
29
- "undici": "^6.21.0",
30
- "uuid": "^11.0.3",
31
- "werift": "0.20.1",
28
+ "systeminformation": "^5.25.11",
29
+ "undici": "^7.2.1",
30
+ "uuid": "^11.0.5",
31
+ "werift": "0.21.6",
32
32
  "ws": "^8.18.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/debug": "4.1.12",
36
- "@types/jest": "29.5.14",
37
36
  "@types/json-bigint": "^1.0.4",
38
- "@types/node": "22.9.3",
37
+ "@types/node": "22.10.5",
39
38
  "@types/socket.io-client": "1.4.36",
40
39
  "@types/uuid": "10.0.0",
41
40
  "@types/ws": "^8.5.13",
42
41
  "eslint-config-shared": "*",
43
- "jest": "29.7.0",
44
- "msw": "^2.6.4",
45
- "ts-jest": "29.2.5",
42
+ "msw": "^2.7.0",
46
43
  "tsconfig": "*",
47
- "typescript": "5.7.2"
44
+ "typescript": "5.7.3",
45
+ "vitest": "^2.1.8"
48
46
  },
49
47
  "engines": {
50
48
  "node": "^18 || ^20 || ^22"
@@ -1 +0,0 @@
1
- export {};