@@ -17,7 +17,7 @@ import ArrayHelper from '../helpers/array-helper';
17
17
* @param {string } householdId HouseholdId is used from authentication, take from DevicePropertiesService.GetHouseholdID().CurrentHouseholdID
18
18
* @param {string } key private key is used for authentication (not sure how to fetch this from sonos)
19
19
* @param {string } authToken authToken is used for authentication (not sure how to fetch from sonos)
20
- *
20
+ *
21
21
* @export
22
22
* @interface SmapiClientOptions
23
23
*/
@@ -31,10 +31,10 @@ export interface SmapiClientOptions {
31
31
householdId ?: string ;
32
32
key ?: string ;
33
33
authToken ?: string ;
34
- saveNewAccount ?: saveNemAccountHandler ;
34
+ saveNewAccount ?: SaveNemAccountHandler ;
35
35
}
36
36
37
- declare type saveNemAccountHandler = ( serviceId : number , key : string , token : string ) => void ;
37
+ declare type SaveNemAccountHandler = ( serviceId : number , key : string , token : string ) => void ;
38
38
39
39
export interface MediaList {
40
40
index : number ;
@@ -100,12 +100,12 @@ export enum SmapiClientErrors {
100
100
* @class SmapiClient
101
101
*/
102
102
export class SmapiClient {
103
-
104
103
private readonly options : SmapiClientOptions ;
105
104
106
105
private debugger ?: Debugger ;
107
106
108
107
private key ?: string ;
108
+
109
109
private authToken ?: string ;
110
110
111
111
protected get debug ( ) : Debugger {
@@ -143,9 +143,9 @@ export class SmapiClient {
143
143
*/
144
144
public async GetAppLink ( ) : Promise < AppLinkResponse > {
145
145
return await this . SoapRequestWithBody < any , AppLinkResponse > ( 'getAppLink' ,
146
- {
147
- householdId : this . getHouseholdIdOrThrow ( )
148
- } ) ;
146
+ {
147
+ householdId : this . getHouseholdIdOrThrow ( ) ,
148
+ } ) ;
149
149
}
150
150
151
151
/**
@@ -157,12 +157,12 @@ export class SmapiClient {
157
157
*/
158
158
public async GetDeviceAuthToken ( linkCode : string ) : Promise < DeviceAuthResponse > {
159
159
return await this . SoapRequestWithBody < any , DeviceAuthResponse > ( 'getDeviceAuthToken' ,
160
- {
161
- householdId : this . getHouseholdIdOrThrow ( ) ,
162
- linkCode : linkCode ,
163
- linkDeviceId : this . options . deviceId
164
- } )
165
- . then ( async data => {
160
+ {
161
+ householdId : this . getHouseholdIdOrThrow ( ) ,
162
+ linkCode,
163
+ linkDeviceId : this . options . deviceId ,
164
+ } )
165
+ . then ( async ( data ) => {
166
166
if ( this . options . saveNewAccount !== undefined ) { // Save the account by the library provided way.
167
167
await this . options . saveNewAccount ( this . options . serviceId , data . privateKey , data . authToken ) ;
168
168
}
@@ -172,9 +172,9 @@ export class SmapiClient {
172
172
173
173
public async GetDeviceLinkCode ( ) : Promise < DeviceLink > {
174
174
return await this . SoapRequestWithBody < any , DeviceLink > ( 'getDeviceLinkCode' ,
175
- {
176
- householdId : this . getHouseholdIdOrThrow ( )
177
- } ) ;
175
+ {
176
+ householdId : this . getHouseholdIdOrThrow ( ) ,
177
+ } ) ;
178
178
}
179
179
180
180
/**
@@ -219,11 +219,13 @@ export class SmapiClient {
219
219
220
220
if ( input . mediaMetadata !== undefined ) {
221
221
result . mediaMetadata = ArrayHelper . ForceArray < MediaMetadata > ( input . mediaMetadata ) ;
222
- result . mediaMetadata . forEach ( ( m ) => {
223
- if ( m . itemType === 'stream' ) m . trackUri = `x-sonosapi-stream:${ m . id } ?sid=${ this . options . serviceId } ` ;
222
+ result . mediaMetadata = result . mediaMetadata . map ( ( m ) => {
223
+ const withTrack = m ;
224
+ if ( m . itemType === 'stream' ) withTrack . trackUri = `x-sonosapi-stream:${ m . id } ?sid=${ this . options . serviceId } ` ;
225
+ return withTrack ;
224
226
} ) ;
225
227
}
226
-
228
+
227
229
if ( input . mediaCollection !== undefined ) {
228
230
result . mediaCollection = ArrayHelper . ForceArray < MediaItem > ( input . mediaCollection ) ;
229
231
}
@@ -232,34 +234,31 @@ export class SmapiClient {
232
234
}
233
235
234
236
// #region Private server stuff
235
- private async SoapRequest < TResponse > ( action : string , isRetryWithNewCredentials : boolean = false ) : Promise < TResponse > {
237
+ private async SoapRequest < TResponse > ( action : string , isRetryWithNewCredentials = false ) : Promise < TResponse > {
236
238
this . debug ( '%s()' , action ) ;
237
239
try {
238
240
return await this . handleRequestAndParseResponse < TResponse > ( this . generateRequest < undefined > ( action , undefined ) , action ) ;
239
- }
240
- catch ( err ) {
241
- if ( err instanceof SmapiError && err . Fault . faultstring == SmapiClientErrors . TokenRefreshRequiredError && ! isRetryWithNewCredentials ) {
241
+ } catch ( err ) {
242
+ if ( err instanceof SmapiError && ( err . Fault as any ) . faultstring === SmapiClientErrors . TokenRefreshRequiredError && ! isRetryWithNewCredentials ) {
242
243
return await this . SoapRequest < TResponse > ( action , true ) ;
243
244
}
244
245
throw err ;
245
246
}
246
247
}
247
248
248
- private async SoapRequestWithBody < TBody , TResponse > ( action : string , body : TBody , isRetryWithNewCredentials : boolean = false ) : Promise < TResponse > {
249
+ private async SoapRequestWithBody < TBody , TResponse > ( action : string , body : TBody , isRetryWithNewCredentials = false ) : Promise < TResponse > {
249
250
this . debug ( '%s(%o)' , action , body ) ;
250
251
try {
251
252
return await this . handleRequestAndParseResponse < TResponse > ( this . generateRequest < TBody > ( action , body ) , action ) ;
252
- }
253
- catch ( err ) {
254
- if ( err instanceof SmapiError && err . Fault . faultstring == SmapiClientErrors . TokenRefreshRequiredError && ! isRetryWithNewCredentials ) {
253
+ } catch ( err ) {
254
+ if ( err instanceof SmapiError && ( err . Fault as any ) . faultstring === SmapiClientErrors . TokenRefreshRequiredError && ! isRetryWithNewCredentials ) {
255
255
return await this . SoapRequestWithBody < TBody , TResponse > ( action , body , true ) ;
256
256
}
257
257
throw err ;
258
258
}
259
-
260
259
}
261
260
262
- private async handleRequestAndParseResponse < TResponse > ( request : Request , action : string , isRetryWithNewCredentials : boolean = false ) : Promise < TResponse > {
261
+ private async handleRequestAndParseResponse < TResponse > ( request : Request , action : string , isRetryWithNewCredentials = false ) : Promise < TResponse > {
263
262
const response = await fetch ( request ) ;
264
263
// if (!response.ok) {
265
264
// this.debug('handleRequest error %d %s', response.status, response.statusText);
@@ -273,7 +272,7 @@ export class SmapiClient {
273
272
}
274
273
if ( typeof result . Envelope . Body . Fault !== 'undefined' ) {
275
274
const fault = result . Envelope . Body . Fault ;
276
- if ( ! isRetryWithNewCredentials && fault . faultstring === 'tokenRefreshRequired' ) {
275
+ if ( ! isRetryWithNewCredentials && fault . faultstring === 'tokenRefreshRequired' ) {
277
276
this . debug ( 'Saving new tokens' ) ;
278
277
// Set new tokens, maybe result in event?
279
278
this . authToken = fault . detail ?. refreshAuthTokenResult ?. authToken ;
@@ -284,12 +283,12 @@ export class SmapiClient {
284
283
if ( this . options . saveNewAccount !== undefined && this . key && this . authToken ) {
285
284
this . options . saveNewAccount ( this . options . serviceId , this . key , this . authToken ) ;
286
285
}
287
- }
286
+ }
288
287
this . debug ( 'Soap error %s %o' , action , fault ) ;
289
288
throw new SmapiError ( this . options . name , action , fault ) ;
290
289
}
291
290
this . debug ( 'handleRequest success' ) ;
292
- const body = result . Envelope . Body [ `${ action } Response` ]
291
+ const body = result . Envelope . Body [ `${ action } Response` ] ;
293
292
return body [ `${ action } Result` ] ?? body ;
294
293
}
295
294
@@ -323,25 +322,27 @@ export class SmapiClient {
323
322
private generateSoapBody < TBody > ( action : string , body : TBody ) : string {
324
323
let messageBody = `<soap:Body>\r\n<s:${ action } >` ;
325
324
if ( body ) {
326
- for ( const [ key , value ] of Object . entries ( body ) ) {
325
+ Object . entries ( body ) . forEach ( ( v ) => {
326
+ // Deconstruct v into key and value.
327
+ const [ key , value ] = v ;
327
328
if ( typeof value === 'boolean' ) messageBody += `<s:${ key } >${ value === true ? '1' : '0' } </s:${ key } >` ;
328
329
else messageBody += `<s:${ key } >${ value } </s:${ key } >` ;
329
- }
330
+ } ) ;
330
331
}
331
332
messageBody += `</s:${ action } >\r\n</soap:Body>` ;
332
333
return messageBody ;
333
334
}
334
335
335
336
private getHouseholdIdOrThrow ( ) : string {
336
- if ( this . options . householdId === undefined ) {
337
- throw new Error ( " options.householdId is undefined, fetch from DevicePropertiesService.GetHouseholdID" ) ;
337
+ if ( this . options . householdId === undefined ) {
338
+ throw new Error ( ' options.householdId is undefined, fetch from DevicePropertiesService.GetHouseholdID' ) ;
338
339
}
339
340
return this . options . householdId ;
340
341
}
341
342
342
343
private generateCredentialHeader ( options : { deviceId ?: string ; deviceCert ?: string ; zonePlayerId ?: string ; } = { } ) : string {
343
- let header = ' <s:credentials>\r\n'
344
-
344
+ let header = ' <s:credentials>\r\n' ;
345
+
345
346
if ( options . deviceId !== undefined ) {
346
347
header += ` <s:deviceId>${ options . deviceId } </s:deviceId>\r\n` ;
347
348
}
0 commit comments