hb-zp-tools 2.0.0-0 → 2.0.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/ZpClient.js CHANGED
@@ -155,10 +155,10 @@ class ZpClientRequest extends HttpClient.HttpRequest {
155
155
  get body () {}
156
156
 
157
157
  /** The (parsed) request body (in JavaScript).
158
- * @type {?*}
158
+ * @type {?string}
159
159
  * @readonly
160
160
  */
161
- get parsedBody () {}
161
+ get jsonBody () {}
162
162
  }
163
163
 
164
164
  /** ZpClient response.
@@ -331,6 +331,7 @@ class ZpClient extends HttpClient {
331
331
  .intKey('timeout', 1, 60) // seconds
332
332
  .intKey('subscriptionTimeout', 1, 1440) // minutes
333
333
  .instanceKey('listener', ZpListener)
334
+ .instanceKey('logger')
334
335
  .parse(params)
335
336
  _params.subscriptionTimeout *= 60 // minutes -> seconds
336
337
 
@@ -340,6 +341,7 @@ class ZpClient extends HttpClient {
340
341
  keepAlive: true,
341
342
  maxSockets: 1,
342
343
  name: _params.hostname,
344
+ logger: _params.logger,
343
345
  timeout: _params.timeout,
344
346
  xmlParser: parser.parse.bind(parser)
345
347
  }
@@ -373,6 +375,7 @@ class ZpClient extends HttpClient {
373
375
  // _request().
374
376
  error (error) {
375
377
  if (error.request == null) {
378
+ this.warn(error)
376
379
  this.emit('error', error)
377
380
  }
378
381
  }
@@ -486,7 +489,7 @@ class ZpClient extends HttpClient {
486
489
  props.household = household
487
490
  props.zoneGroup = group.coordinator
488
491
  if (props.id === this._params.id) {
489
- this._checkAddress(props.address)
492
+ this.#checkAddress(props.address)
490
493
  await this._checkBootSeq(props.bootSeq)
491
494
  if (props.bootSeq < this._props.bootSeq) {
492
495
  props.bootSeq = this._props.bootSeq
@@ -981,7 +984,7 @@ class ZpClient extends HttpClient {
981
984
  this._params.callbackUrl = await this._zpListener.addClient(this)
982
985
  this._zpListener.on(this.id, async (message) => {
983
986
  try {
984
- await this._updateLastSeen()
987
+ await this.#updateLastSeen()
985
988
  message.name = this.name
986
989
  if (message.body != null) {
987
990
  message.rawBody = message.body
@@ -994,6 +997,16 @@ class ZpClient extends HttpClient {
994
997
  this._zoneGroupState = message.body
995
998
  await this.initTopology(this)
996
999
  }
1000
+ const notify = message.device === 'ZonePlayer'
1001
+ ? message.service
1002
+ : message.device + '/' + message.service
1003
+ this.vvdebug(
1004
+ '%s: notify %s/Event: %j', this.name, notify, message.rawBody
1005
+ )
1006
+ this.vdebug(
1007
+ '%s: notify %s/Event: %j', this.name, notify, message.body
1008
+ )
1009
+ this.debug('%s: notify %s/Event', this.name, notify)
997
1010
  /** Emitted when a push notification has been received from the zone player.
998
1011
  * @event ZpClient#message
999
1012
  * @param {ZpClient.ZpClientNotification} message - The message.
@@ -1049,7 +1062,7 @@ class ZpClient extends HttpClient {
1049
1062
  }
1050
1063
  }
1051
1064
  try {
1052
- const response = await this._request('SUBSCRIBE', url, undefined, headers)
1065
+ const response = await this.#request('SUBSCRIBE', url, undefined, headers)
1053
1066
  this._subscriptions[url].sid = response.headers.sid
1054
1067
  } catch (error) {
1055
1068
  if (error.statusCode === 412) {
@@ -1084,7 +1097,7 @@ class ZpClient extends HttpClient {
1084
1097
  delete this._subscriptions[url]
1085
1098
  if (sid != null) {
1086
1099
  try {
1087
- await this._request('UNSUBSCRIBE', url, undefined, { SID: sid })
1100
+ await this.#request('UNSUBSCRIBE', url, undefined, { SID: sid })
1088
1101
  } catch (error) { this.error(error) }
1089
1102
  }
1090
1103
  if (Object.keys(this._subscriptions).length === 0) {
@@ -1112,6 +1125,10 @@ class ZpClient extends HttpClient {
1112
1125
  await this.subscribe(url)
1113
1126
  } catch (error) { this.error(error) }
1114
1127
  }
1128
+ this.debug(
1129
+ '%s: rebooted (%d -> %d)', this.name,
1130
+ oldBootSeq, this.bootSeq
1131
+ )
1115
1132
  /** Emitted when the zone player has rebooted.
1116
1133
  * @event ZpClient#rebooted
1117
1134
  * @param {integer} oldBootSeq - The old
@@ -1120,7 +1137,7 @@ class ZpClient extends HttpClient {
1120
1137
  this.emit('rebooted', oldBootSeq)
1121
1138
  }
1122
1139
 
1123
- _checkAddress (address) {
1140
+ #checkAddress (address) {
1124
1141
  if (address === this._props.address) {
1125
1142
  return
1126
1143
  }
@@ -1128,6 +1145,11 @@ class ZpClient extends HttpClient {
1128
1145
  this._props.address = address
1129
1146
  this.host = this._props.address + ':1400'
1130
1147
  this._params.hostname = this._props.address
1148
+
1149
+ this.debug(
1150
+ '%s: IP address changed (%s -> %s)', this.name,
1151
+ oldAddress, this.address
1152
+ )
1131
1153
  /** Emitted when the zone player has a new IP address.
1132
1154
  * @event ZpClient#addressChanged
1133
1155
  * @param {string} oldAddress - The old
@@ -1136,7 +1158,7 @@ class ZpClient extends HttpClient {
1136
1158
  this.emit('addressChanged', oldAddress)
1137
1159
  }
1138
1160
 
1139
- async _updateLastSeen () {
1161
+ async #updateLastSeen () {
1140
1162
  if (this._reSubscribing) {
1141
1163
  return
1142
1164
  }
@@ -1175,9 +1197,9 @@ class ZpClient extends HttpClient {
1175
1197
  if (this._props.household !== message.household) {
1176
1198
  this._props.household = message.household
1177
1199
  }
1178
- this._checkAddress(message.address)
1200
+ this.#checkAddress(message.address)
1179
1201
  await this._checkBootSeq(message.bootseq)
1180
- await this._updateLastSeen()
1202
+ await this.#updateLastSeen()
1181
1203
  }
1182
1204
 
1183
1205
  // ***** Control *************************************************************
@@ -1207,6 +1229,9 @@ class ZpClient extends HttpClient {
1207
1229
  PlayMode: alarm.playMode,
1208
1230
  Volume: alarm.volume,
1209
1231
  IncludeLinkedZones: alarm.includeLinkedZones
1232
+ // Note that when set from the Sonos iOS app, the alarm includes a
1233
+ // <Content type="..." .../> tag. This tag is lost when updating the
1234
+ // alarm here, but also when updating from the Sonos macOS app.
1210
1235
  })
1211
1236
  }
1212
1237
 
@@ -1411,7 +1436,7 @@ class ZpClient extends HttpClient {
1411
1436
  let meta = '<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">'
1412
1437
  meta += `<item id="${metaData.id}" parentID="${metaData.parentId}" restricted="${metaData.restricted}">`
1413
1438
  meta += `<dc:title>${metaData.title}</dc:title>`
1414
- meta += `<upnp:class>${metaData.class}.sonos-favorite</upnp:class>`
1439
+ meta += `<upnp:class>${metaData.class}</upnp:class>`
1415
1440
  if (albumArtUri != null) {
1416
1441
  for (const uri of albumArtUri) {
1417
1442
  meta += `<upnp:albumArtURI>${he.escape(uri)}</upnp:albumArtURI>`
@@ -1712,10 +1737,10 @@ class ZpClient extends HttpClient {
1712
1737
  }
1713
1738
  const info = {
1714
1739
  action,
1715
- parsedBody: options
1740
+ jsonBody: JSON.stringify(options)
1716
1741
  }
1717
- const response = await this._request('POST', url, body, headers, info)
1718
- await this._updateLastSeen()
1742
+ const response = await this.#request('POST', url, body, headers, info)
1743
+ await this.#updateLastSeen()
1719
1744
  return response.body
1720
1745
  }
1721
1746
 
@@ -1724,12 +1749,12 @@ class ZpClient extends HttpClient {
1724
1749
  * @returns {?*} - The parsed response body as JavaScript object.
1725
1750
  */
1726
1751
  async get (url = '/xml/device_description.xml') {
1727
- const response = await this._request('GET', url)
1728
- await this._updateLastSeen()
1752
+ const response = await this.#request('GET', url)
1753
+ await this.#updateLastSeen()
1729
1754
  return response.body
1730
1755
  }
1731
1756
 
1732
- async _request (method, resource, body, headers, info) {
1757
+ async #request (method, resource, body, headers, info) {
1733
1758
  const response = await super.request(
1734
1759
  method, resource, body, headers, '', info
1735
1760
  )
package/lib/ZpTool.js CHANGED
@@ -52,7 +52,8 @@ const usage = {
52
52
  subLevel: `${b('subLevel')} [${b('-h')}] [${b('--')}] [${u('level')}]`,
53
53
  led: `${b('led')} [${b('-h')}] [${b('on')}|${b('off')}]`,
54
54
  buttonLock: `${b('buttonLock')} [${b('-h')}] [${b('on')}|${b('off')}]`,
55
- listAlarms: `${b('listAlarms')} [${b('-h')}]`
55
+ listAlarms: `${b('listAlarms')} [${b('-hns')}]`,
56
+ alarm: `${b('alarm')} [${b('-h')}] ${u('id')} [${b('on')}|${b('off')}]`
56
57
  }
57
58
 
58
59
  const description = {
@@ -93,7 +94,8 @@ const description = {
93
94
  subLevel: 'Get/set Sub level.',
94
95
  led: 'Get/set/clear LED state.',
95
96
  buttonLock: 'Get/set/clear button lock state.',
96
- listAlarms: 'Get alarms.'
97
+ listAlarms: 'Get alarms.',
98
+ alarm: 'Get/enable/disable alarm.'
97
99
  }
98
100
 
99
101
  const help = {
@@ -224,6 +226,9 @@ Commands:
224
226
  ${usage.listAlarms}
225
227
  ${description.listAlarms}
226
228
 
229
+ ${usage.alarm}
230
+ ${description.alarm}
231
+
227
232
  For more help, issue: ${b('zp')} ${u('command')} ${b('-h')}`,
228
233
  info: `${description.info}
229
234
 
@@ -661,7 +666,29 @@ Usage: ${b('zp')} ${usage.listAlarms}
661
666
 
662
667
  Parameters:
663
668
  ${b('-h')}, ${b('--help')}
664
- Print this help and exit.`
669
+ Print this help and exit.
670
+
671
+ ${b('-n')}, ${b('--noWhiteSpace')}
672
+ Do not include spaces nor newlines in JSON output.
673
+
674
+ ${b('-s')}, ${b('--sortKeys')}
675
+ Sort JSON keys alphabetically.`,
676
+ alarm: `${description.alarm}
677
+
678
+ Usage: ${b('zp')} ${usage.alarm}
679
+
680
+ Parameters:
681
+ ${b('-h')}, ${b('--help')}
682
+ Print this help and exit.
683
+
684
+ ${u('id')}
685
+ Alarm ID (from ${b('listAlarms')}).
686
+
687
+ ${b('on')}
688
+ Enable alarm.
689
+
690
+ ${b('off')}
691
+ Disable alarm.`
665
692
  }
666
693
 
667
694
  const unsupportedServices = [
@@ -679,105 +706,6 @@ class ZpTool extends CommandLineTool {
679
706
  this.clients = []
680
707
  }
681
708
 
682
- createZpClient (options) {
683
- const zpClient = new ZpClient(options)
684
- zpClient
685
- .on('error', (error) => {
686
- if (error.request == null) {
687
- this.warn(error)
688
- return
689
- }
690
- if (error.request.id !== this.requestId) {
691
- if (error.request.body == null) {
692
- this.log(
693
- '%s: request %d: %s %s', error.request.name, error.request.id,
694
- error.request.method, error.request.resource
695
- )
696
- } else {
697
- this.log(
698
- '%s: request %d: %s %s', error.request.name, error.request.id,
699
- error.request.method, error.request.resource, error.request.action
700
- )
701
- }
702
- this.requestId = error.request.id
703
- }
704
- this.warn(
705
- '%s: request %d: %s', error.request.name, error.request.id, error
706
- )
707
- })
708
- // TODO: never called, since no UPnP listener is active
709
- .on('rebooted', (oldBootSeq) => {
710
- this.debug(
711
- '%s: rebooted (%d -> %d)', zpClient.name,
712
- oldBootSeq, zpClient.bootSeq
713
- )
714
- })
715
- .on('addressChanged', (oldAddress) => {
716
- this.debug(
717
- '%s: IP address changed (%s -> %s)', zpClient.name,
718
- oldAddress, zpClient.address
719
- )
720
- })
721
- .on('request', (request) => {
722
- this.debug(
723
- '%s: request %s: %s %s%s', request.name,
724
- request.id, request.method, request.resource,
725
- request.action == null ? '' : ' ' + request.action
726
- )
727
- if (request.parsedBody != null) {
728
- this.vdebug(
729
- '%s: request %s: %s %s %j', request.name,
730
- request.id, request.method, request.url, request.parsedBody
731
- )
732
- this.vvdebug(
733
- '%s: request %s: %s %s (headers: %j) %j', request.name,
734
- request.id, request.method, request.url,
735
- request.headers, request.body
736
- )
737
- } else {
738
- this.vdebug(
739
- '%s: request %s: %s %s', request.name,
740
- request.id, request.method, request.url
741
- )
742
- this.vvdebug(
743
- '%s: request %s: %s %s (headers: %j)', request.name,
744
- request.id, request.method, request.url, request.headers
745
- )
746
- }
747
- })
748
- .on('response', (response) => {
749
- this.debug(
750
- '%s: request %d: %d %s', response.request.name,
751
- response.request.id, response.statusCode, response.statusMessage
752
- )
753
- if (response.rawBody != null) {
754
- this.vvdebug(
755
- '%s: request %d: response (headers: %j): %j', response.request.name,
756
- response.request.id, response.headers, response.rawBody
757
- )
758
- this.vdebug(
759
- '%s: request %d: response: %j', response.request.name,
760
- response.request.id, response.body
761
- )
762
- }
763
- })
764
- .on('message', (message) => {
765
- const notify = message.device === 'ZonePlayer'
766
- ? message.service
767
- : message.device + '/' + message.service
768
- this.vvdebug(
769
- '%s: notify %s/Event: %j', this._clargs.options.host,
770
- notify, message.rawBody
771
- )
772
- this.vdebug(
773
- '%s: notify %s/Event: %j', this._clargs.options.host,
774
- notify, message.body
775
- )
776
- this.debug('%s: notify %s/Event', this._clargs.options.host, notify)
777
- })
778
- return zpClient
779
- }
780
-
781
709
  async main () {
782
710
  try {
783
711
  this._clargs = this.parseArguments()
@@ -790,7 +718,8 @@ class ZpTool extends CommandLineTool {
790
718
  .on('close', (url) => { this.debug('closed %s', url) })
791
719
  .on('error', (error) => { this.warn(error) })
792
720
  this._clargs.options.listener = this.zpListener
793
- this.zpClient = await this.createZpClient(this._clargs.options)
721
+ this._clargs.options.logger = this
722
+ this.zpClient = new ZpClient(this._clargs.options)
794
723
  await this.zpClient.init()
795
724
  this.debug(
796
725
  '%s: reached using local address %s', this._clargs.options.host,
@@ -801,7 +730,9 @@ class ZpTool extends CommandLineTool {
801
730
  this.help = help[this._clargs.command]
802
731
  await this[this._clargs.command](this._clargs.args)
803
732
  } catch (error) {
804
- this.error(error)
733
+ if (error.request == null) {
734
+ this.error(error)
735
+ }
805
736
  }
806
737
  }
807
738
 
@@ -898,9 +829,10 @@ class ZpTool extends CommandLineTool {
898
829
  }
899
830
 
900
831
  async _getInfo (zonePlayer) {
901
- const zpClient = this.createZpClient({
832
+ const zpClient = new ZpClient({
902
833
  host: zonePlayer.address,
903
834
  id: zonePlayer.id,
835
+ logger: this,
904
836
  timeout: this._clargs.options.timeout
905
837
  })
906
838
  await zpClient.init()
@@ -1225,9 +1157,49 @@ class ZpTool extends CommandLineTool {
1225
1157
 
1226
1158
  async listAlarms (...args) {
1227
1159
  const parser = new CommandLineParser(this.pkgJson)
1228
- parser.help('h', 'help', this.help)
1229
- parser.parse(...args)
1230
- this.print(await this.zpClient.listAlarms())
1160
+ const clargs = {
1161
+ options: {}
1162
+ }
1163
+ parser
1164
+ .help('h', 'help', this.help)
1165
+ .flag('n', 'noWhiteSpace', () => { clargs.options.noWhiteSpace = true })
1166
+ .flag('s', 'sortKeys', () => { clargs.options.sortKeys = true })
1167
+ .parse(...args)
1168
+ const jsonFormatter = new JsonFormatter(clargs.options)
1169
+ const result = await this.zpClient.listAlarms()
1170
+ const json = jsonFormatter.stringify(result)
1171
+ this.print(json)
1172
+ }
1173
+
1174
+ async alarm (...args) {
1175
+ const parser = new CommandLineParser(this.pkgJson)
1176
+ const clargs = {}
1177
+ parser
1178
+ .help('h', 'help', this.help)
1179
+ .parameter('id', (value) => {
1180
+ clargs.id = OptionParser.toInt('id', value, 0, Infinity, true)
1181
+ })
1182
+ .remaining((list) => {
1183
+ if (list.length > 1) {
1184
+ throw new UsageError('too many arguments')
1185
+ }
1186
+ if (list.length === 1) {
1187
+ clargs.enabled = OptionParser.toBool('enabled', list[0], true)
1188
+ }
1189
+ })
1190
+ .parse(...args)
1191
+ const response = await this.zpClient.listAlarms()
1192
+ const alarm = response?.currentAlarmList?.filter(
1193
+ (alarm) => { return alarm.id === clargs.id }
1194
+ )?.[0]
1195
+ if (alarm == null) {
1196
+ throw new UsageError(`${clargs.id}: alarm not found`)
1197
+ }
1198
+ if (clargs.enabled != null) {
1199
+ alarm.enabled = clargs.enabled ? 1 : 0
1200
+ await this.zpClient.updateAlarm(alarm)
1201
+ }
1202
+ this.print(alarm.enabled ? 'on' : 'off')
1231
1203
  }
1232
1204
 
1233
1205
  async simpleCommand (command, ...args) {
@@ -109,25 +109,25 @@ class ZpXmlParser {
109
109
  const xml2jsParserOptions = {
110
110
  explicitArray: false,
111
111
  mergeAttrs: true,
112
- attrNameProcessors: [this._processKey.bind(this)],
113
- attrValueProcessors: [this._processValue.bind(this)],
114
- tagNameProcessors: [this._processKey.bind(this)],
115
- valueProcessors: [this._processValue.bind(this)]
112
+ attrNameProcessors: [this.#processKey.bind(this)],
113
+ attrValueProcessors: [this.#processValue.bind(this)],
114
+ tagNameProcessors: [this.#processKey.bind(this)],
115
+ valueProcessors: [this.#processValue.bind(this)]
116
116
  }
117
117
  this._parser = new Parser(xml2jsParserOptions)
118
118
  // this._debug = debug('ZpXmlParser')
119
119
  }
120
120
 
121
121
  async parse (xml) {
122
- // this._debug('parse(%j)', xml)
122
+ this._debug?.('parse(%j)', xml)
123
123
  const result = await this._parser.parseStringPromise(xml)
124
- return this._process(result)
124
+ return this.#process(result)
125
125
  }
126
126
 
127
127
  // Convert key to javascript standard key.
128
- _processKey (key) {
129
- // const oldKey = key
130
- // this._debug('processKey(%j)', oldKey)
128
+ #processKey (key) {
129
+ const oldKey = key
130
+ this._debug?.('processKey(%j)', oldKey)
131
131
 
132
132
  // Get rid of schema tags.
133
133
  const a = key.split(':')
@@ -152,14 +152,14 @@ class ZpXmlParser {
152
152
  key = replacementKeys[key]
153
153
  }
154
154
 
155
- // this._debug('processKey(%j) => %j', oldKey, key)
155
+ this._debug?.('processKey(%j) => %j', oldKey, key)
156
156
  return key
157
157
  }
158
158
 
159
159
  // Convert value to proper javascript value.
160
- _processValue (value, key) {
161
- // const oldValue = value
162
- // this._debug('processValue(%j, %j)', oldValue, key)
160
+ #processValue (value, key) {
161
+ const oldValue = value
162
+ this._debug?.('processValue(%j, %j)', oldValue, key)
163
163
 
164
164
  // Convert integer string to integer
165
165
  if (/^[0-9]+$/.test(value) && !stringKeys.includes(key)) {
@@ -170,12 +170,25 @@ class ZpXmlParser {
170
170
  value = he.decode(value)
171
171
  }
172
172
 
173
- // this._debug('processValue(%j, %j) => %j', oldValue, key, value)
173
+ this._debug?.('processValue(%j, %j) => %j', oldValue, key, value)
174
174
  return value
175
175
  }
176
176
 
177
177
  // Post-process converted XML.
178
- async _process (value) {
178
+ async #process (value) {
179
+ const oldValue = value
180
+ this._debug?.('process(%j)', value)
181
+ try {
182
+ value = await this.#tryProcess(value)
183
+ } catch (error) {
184
+ this._debug?.('process(%j) => error: %j', oldValue, error.message)
185
+ }
186
+ this._debug?.('process(%j) => %j', oldValue, value)
187
+ return value
188
+ }
189
+
190
+ // Post-process converted XML.
191
+ async #tryProcess (value) {
179
192
  // Recursively parse XML strings.
180
193
  if (typeof value === 'string' && /^<.*>$/.test(value)) {
181
194
  return this.parse(value)
@@ -185,7 +198,7 @@ class ZpXmlParser {
185
198
  if (Array.isArray(value)) {
186
199
  const list = []
187
200
  for (const elt of value) {
188
- list.push(await this._process(elt))
201
+ list.push(await this.#process(elt))
189
202
  }
190
203
  return list
191
204
  }
@@ -202,7 +215,7 @@ class ZpXmlParser {
202
215
  const keys = Object.keys(value)
203
216
  if (keys.length === 1) {
204
217
  if (rootKeys.includes(keys[0])) {
205
- return this._process(value[keys[0]])
218
+ return this.#process(value[keys[0]])
206
219
  }
207
220
  }
208
221
  // Recursively post-process key/value pairs.
@@ -212,7 +225,7 @@ class ZpXmlParser {
212
225
  const a = key.match(/^(.+)List$/)
213
226
  if (a != null || arrayKeys[key] != null) {
214
227
  const childKey = arrayKeys[key] == null ? a[1] : arrayKeys[key]
215
- let newValue = await this._process(value[key])
228
+ let newValue = await this.#process(value[key])
216
229
  const listKeys = Object.keys(newValue)
217
230
  if (listKeys.length === 1 && listKeys[0] === childKey) {
218
231
  newValue = newValue[childKey]
@@ -230,7 +243,7 @@ class ZpXmlParser {
230
243
  }
231
244
  // Handle e:property.
232
245
  if (key === 'e:property') {
233
- const newValue = await this._process(value[key])
246
+ const newValue = await this.#process(value[key])
234
247
  if (Array.isArray(newValue)) {
235
248
  for (const property of newValue) {
236
249
  for (const key in property) {
@@ -248,7 +261,7 @@ class ZpXmlParser {
248
261
  if (key === 's:Envelope') {
249
262
  if (value[key] != null && value[key]['s:Body'] != null) {
250
263
  const keys = Object.keys(value[key]['s:Body'])
251
- const newValue = await this._process(
264
+ const newValue = await this.#process(
252
265
  keys.length === 1
253
266
  ? value[key]['s:Body'][keys[0]]
254
267
  : value[key]['s:Body']
@@ -273,13 +286,13 @@ class ZpXmlParser {
273
286
  // Handle keys (like volume) with multiple channels.
274
287
  if (channelKeys.includes(key) && typeof value[key] === 'object') {
275
288
  obj[key] = {}
276
- const newValue = [].concat(await this._process(value[key]))
289
+ const newValue = [].concat(await this.#process(value[key]))
277
290
  for (const elt of newValue) {
278
291
  obj[key][this._processKey(elt.channel)] = elt.val
279
292
  }
280
293
  continue
281
294
  }
282
- obj[key] = await this._process(value[key])
295
+ obj[key] = await this.#process(value[key])
283
296
  }
284
297
  return obj
285
298
  }
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "ebaauw"
7
7
  ],
8
8
  "license": "Apache-2.0",
9
- "version": "2.0.0-0",
9
+ "version": "2.0.0",
10
10
  "type": "module",
11
11
  "exports": {
12
12
  "./*": "./lib/*.js"
@@ -29,7 +29,7 @@
29
29
  "node": "^24||^22||^20"
30
30
  },
31
31
  "dependencies": {
32
- "hb-lib-tools": "~3.0.0-0",
32
+ "hb-lib-tools": "~3.0.0",
33
33
  "he": "^1.2.0",
34
34
  "xml2js": "~0.6.2"
35
35
  },