ring-client-api 11.7.6 → 11.8.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 +28 -10
- package/lib/rest-client.d.ts +4 -0
- package/lib/rest-client.js +68 -17
- package/lib/ring-camera.js +10 -6
- package/lib/ring-types.d.ts +1 -1
- package/lib/streaming/webrtc-connection.js +1 -1
- package/lib/test/rest-client.spec.js +18 -12
- package/lib/util.d.ts +2 -0
- package/lib/util.js +11 -1
- package/package.json +4 -2
package/lib/api.js
CHANGED
|
@@ -16,6 +16,7 @@ const ffmpeg_1 = require("./ffmpeg");
|
|
|
16
16
|
const subscribed_1 = require("./subscribed");
|
|
17
17
|
const push_receiver_1 = __importDefault(require("@eneris/push-receiver"));
|
|
18
18
|
const ring_intercom_1 = require("./ring-intercom");
|
|
19
|
+
const json_bigint_1 = __importDefault(require("json-bigint"));
|
|
19
20
|
class RingApi extends subscribed_1.Subscribed {
|
|
20
21
|
constructor(options) {
|
|
21
22
|
super();
|
|
@@ -122,7 +123,8 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
125
|
async registerPushReceiver(cameras, intercoms) {
|
|
125
|
-
const pushReceiver = new push_receiver_1.default({
|
|
126
|
+
const credentials = this.restClient._internalOnly_pushNotificationCredentials, pushReceiver = new push_receiver_1.default({
|
|
127
|
+
credentials,
|
|
126
128
|
logLevel: 'NONE',
|
|
127
129
|
senderId: '876313859327', // for Ring android app. 703521446232 for ring-site
|
|
128
130
|
}), devicesById = {}, sendToDevice = (id, notification) => {
|
|
@@ -134,10 +136,15 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
134
136
|
for (const intercom of intercoms) {
|
|
135
137
|
devicesById[intercom.id] = intercom;
|
|
136
138
|
}
|
|
137
|
-
pushReceiver.onCredentialsChanged(({ newCredentials
|
|
139
|
+
pushReceiver.onCredentialsChanged(({ newCredentials }) => {
|
|
140
|
+
// Store the new credentials in the rest client so that it can be used for subsequent restarts
|
|
141
|
+
this.restClient._internalOnly_pushNotificationCredentials = newCredentials;
|
|
142
|
+
// Send the new credentials to the server
|
|
143
|
+
onPushNotificationToken.next(newCredentials.fcm.token);
|
|
144
|
+
});
|
|
138
145
|
this.addSubscriptions((0, rxjs_1.combineLatest)([
|
|
139
146
|
onPushNotificationToken,
|
|
140
|
-
this.restClient.onSession, // combined but not used here, just to trigger another request when session is updated
|
|
147
|
+
this.restClient.onSession.pipe((0, operators_1.startWith)(undefined)), // combined but not used here, just to trigger another request when session is updated
|
|
141
148
|
]).subscribe(async ([token]) => {
|
|
142
149
|
try {
|
|
143
150
|
await this.restClient.request({
|
|
@@ -159,10 +166,24 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
159
166
|
(0, util_1.logError)(e);
|
|
160
167
|
}
|
|
161
168
|
}));
|
|
169
|
+
try {
|
|
170
|
+
await pushReceiver.connect();
|
|
171
|
+
}
|
|
172
|
+
catch (e) {
|
|
173
|
+
(0, util_1.logError)('Failed to connect push notification receiver');
|
|
174
|
+
(0, util_1.logError)(e);
|
|
175
|
+
}
|
|
176
|
+
const startTime = Date.now();
|
|
162
177
|
pushReceiver.onNotification(({ message }) => {
|
|
178
|
+
// Ignore messages received in the first two seconds after connecting
|
|
179
|
+
// These are likely duplicates, and we aren't currently storying persistent ids anywhere to avoid re-processing them
|
|
180
|
+
if (Date.now() - startTime < 2000) {
|
|
181
|
+
(0, util_1.logInfo)('Ignoring push notification received in first two seconds after starting up');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
163
184
|
const dataJson = message.data?.gcmData;
|
|
164
185
|
try {
|
|
165
|
-
const notification =
|
|
186
|
+
const notification = (0, json_bigint_1.default)({ storeAsString: true }).parse(dataJson);
|
|
166
187
|
if ('ding' in notification) {
|
|
167
188
|
sendToDevice(notification.ding.doorbot_id, notification);
|
|
168
189
|
}
|
|
@@ -175,12 +196,9 @@ class RingApi extends subscribed_1.Subscribed {
|
|
|
175
196
|
(0, util_1.logError)(e);
|
|
176
197
|
}
|
|
177
198
|
});
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
catch (e) {
|
|
182
|
-
(0, util_1.logError)('Failed to connect push notification receiver');
|
|
183
|
-
(0, util_1.logError)(e);
|
|
199
|
+
// If we already have credentials, use them immediately
|
|
200
|
+
if (credentials) {
|
|
201
|
+
onPushNotificationToken.next(credentials.fcm.token);
|
|
184
202
|
}
|
|
185
203
|
}
|
|
186
204
|
async fetchRawLocations() {
|
package/lib/rest-client.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Options as RequestOptions } from 'got';
|
|
2
2
|
import { AuthTokenResponse, SessionResponse } from './ring-types';
|
|
3
3
|
import { ReplaySubject } from 'rxjs';
|
|
4
|
+
import type { Credentials } from '@eneris/push-receiver/dist/types';
|
|
4
5
|
export declare function clientApi(path: string): string;
|
|
5
6
|
export declare function deviceApi(path: string): string;
|
|
6
7
|
export declare function commandsApi(path: string): string;
|
|
@@ -24,6 +25,7 @@ export interface SessionOptions {
|
|
|
24
25
|
export declare class RingRestClient {
|
|
25
26
|
private authOptions;
|
|
26
27
|
refreshToken: string | undefined;
|
|
28
|
+
private authConfig;
|
|
27
29
|
private hardwareIdPromise;
|
|
28
30
|
private _authPromise;
|
|
29
31
|
private timeouts;
|
|
@@ -54,4 +56,6 @@ export declare class RingRestClient {
|
|
|
54
56
|
}): Promise<T & ExtendedResponse>;
|
|
55
57
|
getCurrentAuth(): Promise<AuthTokenResponse>;
|
|
56
58
|
clearTimeouts(): void;
|
|
59
|
+
get _internalOnly_pushNotificationCredentials(): Credentials | undefined;
|
|
60
|
+
set _internalOnly_pushNotificationCredentials(credentials: Credentials | undefined);
|
|
57
61
|
}
|
package/lib/rest-client.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.RingRestClient = exports.appApi = exports.commandsApi = exports.deviceAp
|
|
|
7
7
|
const got_1 = __importDefault(require("got"));
|
|
8
8
|
const util_1 = require("./util");
|
|
9
9
|
const rxjs_1 = require("rxjs");
|
|
10
|
+
const assert_1 = __importDefault(require("assert"));
|
|
10
11
|
const defaultRequestOptions = {
|
|
11
12
|
responseType: 'json',
|
|
12
13
|
method: 'GET',
|
|
@@ -64,6 +65,22 @@ async function requestWithRetry(requestOptions) {
|
|
|
64
65
|
throw e;
|
|
65
66
|
}
|
|
66
67
|
}
|
|
68
|
+
function parseAuthConfig(rawRefreshToken) {
|
|
69
|
+
if (!rawRefreshToken) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const config = JSON.parse((0, util_1.fromBase64)(rawRefreshToken));
|
|
74
|
+
(0, assert_1.default)(config);
|
|
75
|
+
(0, assert_1.default)(config.rt);
|
|
76
|
+
return config;
|
|
77
|
+
}
|
|
78
|
+
catch (_) {
|
|
79
|
+
return {
|
|
80
|
+
rt: rawRefreshToken,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
67
84
|
class RingRestClient {
|
|
68
85
|
clearPreviousAuth() {
|
|
69
86
|
this._authPromise = undefined;
|
|
@@ -90,6 +107,11 @@ class RingRestClient {
|
|
|
90
107
|
}
|
|
91
108
|
constructor(authOptions) {
|
|
92
109
|
this.authOptions = authOptions;
|
|
110
|
+
this.refreshToken = 'refreshToken' in this.authOptions
|
|
111
|
+
? this.authOptions.refreshToken
|
|
112
|
+
: undefined;
|
|
113
|
+
this.authConfig = parseAuthConfig(this.refreshToken);
|
|
114
|
+
this.hardwareIdPromise = this.authConfig?.hid || (0, util_1.getHardwareId)(this.authOptions.systemId);
|
|
93
115
|
this.timeouts = [];
|
|
94
116
|
this.sessionPromise = undefined;
|
|
95
117
|
this.using2fa = false;
|
|
@@ -99,17 +121,12 @@ class RingRestClient {
|
|
|
99
121
|
api_version: apiVersion,
|
|
100
122
|
device_model: this.authOptions.controlCenterDisplayName ?? 'ring-client-api',
|
|
101
123
|
};
|
|
102
|
-
this.refreshToken =
|
|
103
|
-
'refreshToken' in this.authOptions
|
|
104
|
-
? this.authOptions.refreshToken
|
|
105
|
-
: undefined;
|
|
106
|
-
this.hardwareIdPromise = (0, util_1.getHardwareId)(this.authOptions.systemId);
|
|
107
124
|
}
|
|
108
125
|
getGrantData(twoFactorAuthCode) {
|
|
109
|
-
if (this.
|
|
126
|
+
if (this.authConfig?.rt && !twoFactorAuthCode) {
|
|
110
127
|
return {
|
|
111
128
|
grant_type: 'refresh_token',
|
|
112
|
-
refresh_token: this.
|
|
129
|
+
refresh_token: this.authConfig.rt,
|
|
113
130
|
};
|
|
114
131
|
}
|
|
115
132
|
const { authOptions } = this;
|
|
@@ -125,7 +142,7 @@ class RingRestClient {
|
|
|
125
142
|
async getAuth(twoFactorAuthCode) {
|
|
126
143
|
const grantData = this.getGrantData(twoFactorAuthCode);
|
|
127
144
|
try {
|
|
128
|
-
const response = await requestWithRetry({
|
|
145
|
+
const hardwareId = await this.hardwareIdPromise, response = await requestWithRetry({
|
|
129
146
|
url: 'https://oauth.ring.com/oauth/token',
|
|
130
147
|
json: {
|
|
131
148
|
client_id: 'ring_official_android',
|
|
@@ -136,21 +153,33 @@ class RingRestClient {
|
|
|
136
153
|
headers: {
|
|
137
154
|
'2fa-support': 'true',
|
|
138
155
|
'2fa-code': twoFactorAuthCode || '',
|
|
139
|
-
hardware_id:
|
|
156
|
+
hardware_id: hardwareId,
|
|
140
157
|
'User-Agent': 'android:com.ringapp',
|
|
141
158
|
},
|
|
142
|
-
});
|
|
159
|
+
}), oldRefreshToken = this.refreshToken;
|
|
160
|
+
// Store the new refresh token and auth config
|
|
161
|
+
this.authConfig = {
|
|
162
|
+
...this.authConfig,
|
|
163
|
+
rt: response.refresh_token,
|
|
164
|
+
hid: hardwareId,
|
|
165
|
+
};
|
|
166
|
+
this.refreshToken = (0, util_1.toBase64)(JSON.stringify(this.authConfig));
|
|
167
|
+
// Emit an event with the new token
|
|
143
168
|
this.onRefreshTokenUpdated.next({
|
|
144
|
-
oldRefreshToken
|
|
145
|
-
newRefreshToken:
|
|
169
|
+
oldRefreshToken,
|
|
170
|
+
newRefreshToken: this.refreshToken,
|
|
146
171
|
});
|
|
147
|
-
|
|
148
|
-
|
|
172
|
+
return {
|
|
173
|
+
...response,
|
|
174
|
+
// Override the refresh token in the response so that consumers of this data get the wrapped version
|
|
175
|
+
refresh_token: this.refreshToken,
|
|
176
|
+
};
|
|
149
177
|
}
|
|
150
178
|
catch (requestError) {
|
|
151
179
|
if (grantData.refresh_token) {
|
|
152
180
|
// failed request with refresh token
|
|
153
181
|
this.refreshToken = undefined;
|
|
182
|
+
this.authConfig = undefined;
|
|
154
183
|
(0, util_1.logError)(requestError);
|
|
155
184
|
return this.getAuth();
|
|
156
185
|
}
|
|
@@ -250,9 +279,6 @@ class RingRestClient {
|
|
|
250
279
|
});
|
|
251
280
|
}
|
|
252
281
|
async request(options) {
|
|
253
|
-
if (!this.sessionPromise) {
|
|
254
|
-
this.refreshSession();
|
|
255
|
-
}
|
|
256
282
|
const hardwareId = await this.hardwareIdPromise, url = options.url, initialSessionPromise = this.sessionPromise;
|
|
257
283
|
try {
|
|
258
284
|
await initialSessionPromise;
|
|
@@ -319,5 +345,30 @@ class RingRestClient {
|
|
|
319
345
|
clearTimeouts() {
|
|
320
346
|
this.timeouts.forEach(clearTimeout);
|
|
321
347
|
}
|
|
348
|
+
get _internalOnly_pushNotificationCredentials() {
|
|
349
|
+
return this.authConfig?.pnc;
|
|
350
|
+
}
|
|
351
|
+
set _internalOnly_pushNotificationCredentials(credentials) {
|
|
352
|
+
if (!this.refreshToken || !this.authConfig) {
|
|
353
|
+
throw new Error('Cannot set push notification credentials without a refresh token');
|
|
354
|
+
}
|
|
355
|
+
const oldRefreshToken = this.refreshToken;
|
|
356
|
+
this.authConfig = {
|
|
357
|
+
...this.authConfig,
|
|
358
|
+
pnc: credentials,
|
|
359
|
+
};
|
|
360
|
+
// SOMEDAY: refactor the conversion from auth config to refresh token - DRY from above
|
|
361
|
+
const newRefreshToken = (0, util_1.toBase64)(JSON.stringify(this.authConfig));
|
|
362
|
+
if (newRefreshToken === oldRefreshToken) {
|
|
363
|
+
// No change, so we don't need to emit an updated refresh token
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
// Save and emit the updated refresh token
|
|
367
|
+
this.refreshToken = newRefreshToken;
|
|
368
|
+
this.onRefreshTokenUpdated.next({
|
|
369
|
+
oldRefreshToken,
|
|
370
|
+
newRefreshToken,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
322
373
|
}
|
|
323
374
|
exports.RingRestClient = RingRestClient;
|
package/lib/ring-camera.js
CHANGED
|
@@ -99,18 +99,22 @@ class RingCamera extends subscribed_1.Subscribed {
|
|
|
99
99
|
this.onInHomeDoorbellStatus = this.onData.pipe((0, operators_1.map)(({ settings: { chime_settings } }) => {
|
|
100
100
|
return Boolean(chime_settings?.enable);
|
|
101
101
|
}), (0, operators_1.distinctUntilChanged)());
|
|
102
|
-
|
|
102
|
+
this.addSubscriptions(this.restClient.onSession
|
|
103
|
+
.pipe((0, operators_1.startWith)(undefined), (0, operators_1.throttleTime)(1000)) // Force this to run immediately, but don't double run if a session is created due to these api calls
|
|
104
|
+
.subscribe(() => {
|
|
103
105
|
this.subscribeToDingEvents().catch((e) => {
|
|
104
|
-
(0, util_1.logError)('Failed to subscribe ' +
|
|
106
|
+
(0, util_1.logError)('Failed to subscribe ' +
|
|
107
|
+
initialData.description +
|
|
108
|
+
' to ding events');
|
|
105
109
|
(0, util_1.logError)(e);
|
|
106
110
|
});
|
|
107
|
-
}
|
|
108
|
-
if (!initialData.subscribed_motions) {
|
|
109
111
|
this.subscribeToMotionEvents().catch((e) => {
|
|
110
|
-
(0, util_1.logError)('Failed to subscribe ' +
|
|
112
|
+
(0, util_1.logError)('Failed to subscribe ' +
|
|
113
|
+
initialData.description +
|
|
114
|
+
' to motion events');
|
|
111
115
|
(0, util_1.logError)(e);
|
|
112
116
|
});
|
|
113
|
-
}
|
|
117
|
+
}));
|
|
114
118
|
}
|
|
115
119
|
updateData(update) {
|
|
116
120
|
this.onData.next(update);
|
package/lib/ring-types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ const ws_1 = require("ws");
|
|
|
5
5
|
const streaming_connection_base_1 = require("./streaming-connection-base");
|
|
6
6
|
const util_1 = require("../util");
|
|
7
7
|
function parseLiveCallSession(sessionId) {
|
|
8
|
-
const encodedSession = sessionId.split('.')[1],
|
|
8
|
+
const encodedSession = sessionId.split('.')[1], text = (0, util_1.fromBase64)(encodedSession);
|
|
9
9
|
return JSON.parse(text);
|
|
10
10
|
}
|
|
11
11
|
class WebrtcConnection extends streaming_connection_base_1.StreamingConnectionBase {
|
|
@@ -106,6 +106,12 @@ const email = 'some@one.com', password = 'abc123!', phone = '+1xxxxxxxx89', twoF
|
|
|
106
106
|
},
|
|
107
107
|
}));
|
|
108
108
|
}));
|
|
109
|
+
async function wrapRefreshToken(rt) {
|
|
110
|
+
return (0, util_1.toBase64)(JSON.stringify({
|
|
111
|
+
rt,
|
|
112
|
+
hid: await hardwareIdPromise,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
109
115
|
beforeEach(() => {
|
|
110
116
|
sessionCreatedCount = 0;
|
|
111
117
|
});
|
|
@@ -143,9 +149,9 @@ describe('getAuth', () => {
|
|
|
143
149
|
const auth = await client.getAuth(twoFactorAuthCode);
|
|
144
150
|
expect(auth).toMatchObject({
|
|
145
151
|
access_token: accessToken,
|
|
146
|
-
refresh_token: refreshToken,
|
|
152
|
+
refresh_token: await wrapRefreshToken(refreshToken),
|
|
147
153
|
});
|
|
148
|
-
expect(client.refreshToken).toEqual(refreshToken);
|
|
154
|
+
expect(client.refreshToken).toEqual(await wrapRefreshToken(refreshToken));
|
|
149
155
|
});
|
|
150
156
|
test('it should handle invalid credentials', async () => {
|
|
151
157
|
client = new rest_client_1.RingRestClient({
|
|
@@ -171,9 +177,9 @@ describe('getAuth', () => {
|
|
|
171
177
|
});
|
|
172
178
|
expect(await client.getCurrentAuth()).toMatchObject({
|
|
173
179
|
access_token: accessToken,
|
|
174
|
-
refresh_token: secondRefreshToken,
|
|
180
|
+
refresh_token: await wrapRefreshToken(secondRefreshToken),
|
|
175
181
|
});
|
|
176
|
-
expect(client.refreshToken).toEqual(secondRefreshToken);
|
|
182
|
+
expect(client.refreshToken).toEqual(await wrapRefreshToken(secondRefreshToken));
|
|
177
183
|
});
|
|
178
184
|
test('it should emit an event when a new refresh token is created', async () => {
|
|
179
185
|
client = new rest_client_1.RingRestClient({
|
|
@@ -182,11 +188,11 @@ describe('getAuth', () => {
|
|
|
182
188
|
const refreshedPromise = (0, rxjs_1.firstValueFrom)(client.onRefreshTokenUpdated), auth = await client.getAuth();
|
|
183
189
|
expect(auth).toMatchObject({
|
|
184
190
|
access_token: accessToken,
|
|
185
|
-
refresh_token: secondRefreshToken,
|
|
191
|
+
refresh_token: await wrapRefreshToken(secondRefreshToken),
|
|
186
192
|
});
|
|
187
193
|
expect(await refreshedPromise).toEqual({
|
|
188
194
|
oldRefreshToken: refreshToken,
|
|
189
|
-
newRefreshToken: secondRefreshToken,
|
|
195
|
+
newRefreshToken: await wrapRefreshToken(secondRefreshToken),
|
|
190
196
|
});
|
|
191
197
|
});
|
|
192
198
|
});
|
|
@@ -194,7 +200,7 @@ describe('fetch', () => {
|
|
|
194
200
|
let invalidateFirstAccessToken = false;
|
|
195
201
|
beforeEach(() => {
|
|
196
202
|
invalidateFirstAccessToken = false;
|
|
197
|
-
server.use(msw_1.rest.get('https://api.ring.com/
|
|
203
|
+
server.use(msw_1.rest.get('https://api.ring.com/clients_api/some_endpoint', (req, res, ctx) => {
|
|
198
204
|
const authHeader = req.headers.get('Authorization');
|
|
199
205
|
if (invalidateFirstAccessToken &&
|
|
200
206
|
authHeader === `Bearer ${accessToken}`) {
|
|
@@ -207,10 +213,10 @@ describe('fetch', () => {
|
|
|
207
213
|
return res(ctx.status(401));
|
|
208
214
|
}
|
|
209
215
|
if (sessionCreatedCount === 0) {
|
|
210
|
-
// eslint-disable-next-line no-console
|
|
211
|
-
console.error('Request received before session was created');
|
|
212
216
|
// Session not created yet
|
|
213
|
-
return res(ctx.status(404), ctx.
|
|
217
|
+
return res(ctx.status(404), ctx.json({
|
|
218
|
+
error: 'Session not found for ' + req.headers.get('hardware_id'),
|
|
219
|
+
}));
|
|
214
220
|
}
|
|
215
221
|
return res(ctx.json([]));
|
|
216
222
|
}));
|
|
@@ -220,7 +226,7 @@ describe('fetch', () => {
|
|
|
220
226
|
refreshToken,
|
|
221
227
|
});
|
|
222
228
|
const response = await client.request({
|
|
223
|
-
url: 'https://api.ring.com/
|
|
229
|
+
url: 'https://api.ring.com/clients_api/some_endpoint',
|
|
224
230
|
});
|
|
225
231
|
expect(response).toEqual([]);
|
|
226
232
|
});
|
|
@@ -230,7 +236,7 @@ describe('fetch', () => {
|
|
|
230
236
|
});
|
|
231
237
|
invalidateFirstAccessToken = true;
|
|
232
238
|
const response = await client.request({
|
|
233
|
-
url: 'https://api.ring.com/
|
|
239
|
+
url: 'https://api.ring.com/clients_api/some_endpoint',
|
|
234
240
|
});
|
|
235
241
|
expect(response).toEqual([]);
|
|
236
242
|
});
|
package/lib/util.d.ts
CHANGED
|
@@ -19,4 +19,6 @@ export declare function randomString(length: number): string;
|
|
|
19
19
|
export type DeepPartial<T> = {
|
|
20
20
|
[K in keyof T]?: T[K] extends Array<infer U> ? Array<DeepPartial<U>> : T[K] extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : DeepPartial<T[K]>;
|
|
21
21
|
};
|
|
22
|
+
export declare function fromBase64(encodedInput: string): string;
|
|
23
|
+
export declare function toBase64(input: string): string;
|
|
22
24
|
export {};
|
package/lib/util.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.randomString = exports.randomInteger = exports.mapAsync = exports.stringify = exports.requestInput = exports.getHardwareId = exports.generateUuid = exports.enableDebug = exports.useLogger = exports.logError = exports.logInfo = exports.logDebug = exports.delay = exports.clearTimeouts = void 0;
|
|
6
|
+
exports.toBase64 = exports.fromBase64 = exports.randomString = exports.randomInteger = exports.mapAsync = exports.stringify = exports.requestInput = exports.getHardwareId = exports.generateUuid = exports.enableDebug = exports.useLogger = exports.logError = exports.logInfo = exports.logDebug = exports.delay = exports.clearTimeouts = void 0;
|
|
7
7
|
const debug_1 = __importDefault(require("debug"));
|
|
8
8
|
const colors_1 = require("colors");
|
|
9
9
|
const readline_1 = require("readline");
|
|
@@ -134,3 +134,13 @@ function logPushReceiver(...args) {
|
|
|
134
134
|
logDebug(args[0]);
|
|
135
135
|
}
|
|
136
136
|
logger_1.default.error = logPushReceiver;
|
|
137
|
+
function fromBase64(encodedInput) {
|
|
138
|
+
const buff = Buffer.from(encodedInput, 'base64');
|
|
139
|
+
return buff.toString('ascii');
|
|
140
|
+
}
|
|
141
|
+
exports.fromBase64 = fromBase64;
|
|
142
|
+
function toBase64(input) {
|
|
143
|
+
const buff = Buffer.from(input);
|
|
144
|
+
return buff.toString('base64');
|
|
145
|
+
}
|
|
146
|
+
exports.toBase64 = toBase64;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ring-client-api",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.8.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
|
"exports": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"colors": "1.4.0",
|
|
26
26
|
"debug": "^4.3.4",
|
|
27
27
|
"got": "^11.8.5",
|
|
28
|
+
"json-bigint": "^1.0.0",
|
|
28
29
|
"msw": "^1.2.1",
|
|
29
30
|
"rxjs": "^7.8.0",
|
|
30
31
|
"socket.io-client": "^2.5.0",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/debug": "4.1.7",
|
|
39
40
|
"@types/jest": "29.5.0",
|
|
41
|
+
"@types/json-bigint": "^1.0.1",
|
|
40
42
|
"@types/node": "18.15.9",
|
|
41
43
|
"@types/uuid": "9.0.1",
|
|
42
44
|
"@types/ws": "^8.5.4",
|
|
@@ -47,7 +49,7 @@
|
|
|
47
49
|
"typescript": "5.0.2"
|
|
48
50
|
},
|
|
49
51
|
"engines": {
|
|
50
|
-
"node": "^16 || ^18"
|
|
52
|
+
"node": "^16 || ^18 || ^20"
|
|
51
53
|
},
|
|
52
54
|
"repository": {
|
|
53
55
|
"type": "git",
|