camstreamerlib 4.0.0-beta.3 → 4.0.0-beta.31

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 (194) hide show
  1. package/README.md +8 -2
  2. package/cjs/CamOverlayAPI.d.ts +48 -26
  3. package/cjs/CamOverlayAPI.js +171 -88
  4. package/cjs/CamOverlayDrawingAPI.d.ts +2 -47
  5. package/cjs/CamOverlayDrawingAPI.js +6 -3
  6. package/cjs/CamOverlayPainter/Frame.d.ts +8 -37
  7. package/cjs/CamOverlayPainter/Frame.js +33 -0
  8. package/cjs/CamOverlayPainter/Painter.d.ts +16 -10
  9. package/cjs/CamOverlayPainter/Painter.js +6 -5
  10. package/cjs/CamOverlayPainter/ResourceManager.d.ts +3 -2
  11. package/cjs/CamOverlayPainter/ResourceManager.js +8 -11
  12. package/cjs/CamScripterAPI.d.ts +34 -16
  13. package/cjs/CamScripterAPI.js +50 -41
  14. package/cjs/CamScripterAPICameraEventsGenerator.d.ts +1 -1
  15. package/cjs/CamScripterAPICameraEventsGenerator.js +6 -3
  16. package/cjs/CamStreamerAPI.d.ts +17 -14
  17. package/cjs/CamStreamerAPI.js +32 -32
  18. package/cjs/CamSwitcherAPI.d.ts +43 -37
  19. package/cjs/CamSwitcherAPI.js +123 -114
  20. package/cjs/CamSwitcherEvents.d.ts +1 -1
  21. package/cjs/PlaneTrackerAPI.d.ts +43 -0
  22. package/cjs/PlaneTrackerAPI.js +211 -0
  23. package/cjs/VapixAPI.d.ts +56 -42
  24. package/cjs/VapixAPI.js +305 -216
  25. package/cjs/VapixEvents.d.ts +1 -1
  26. package/cjs/VapixEvents.js +3 -3
  27. package/cjs/errors/errors.d.ts +3 -0
  28. package/cjs/errors/errors.js +8 -1
  29. package/cjs/events/AxisCameraStationEvents.d.ts +7 -4
  30. package/cjs/events/AxisCameraStationEvents.js +23 -18
  31. package/cjs/events/GenetecAgent.d.ts +6 -3
  32. package/cjs/events/GenetecAgent.js +30 -19
  33. package/cjs/index.d.ts +14 -1
  34. package/cjs/index.js +23 -2
  35. package/cjs/internal/Digest.js +6 -6
  36. package/cjs/internal/ProxyClient.d.ts +8 -9
  37. package/cjs/internal/ProxyClient.js +25 -29
  38. package/cjs/internal/types.d.ts +42 -0
  39. package/cjs/internal/types.js +2 -0
  40. package/cjs/internal/utils.d.ts +4 -1
  41. package/cjs/internal/utils.js +22 -3
  42. package/cjs/internal/versionCompare.d.ts +2 -2
  43. package/cjs/node/DefaultClient.d.ts +5 -6
  44. package/cjs/node/DefaultClient.js +12 -14
  45. package/cjs/node/HttpRequestSender.d.ts +1 -0
  46. package/cjs/node/HttpRequestSender.js +13 -3
  47. package/cjs/node/HttpServer.js +1 -1
  48. package/cjs/node/WsClient.d.ts +2 -1
  49. package/cjs/node/index.d.ts +2 -0
  50. package/cjs/node/index.js +18 -1
  51. package/cjs/types/CamOverlayAPI/CamOverlayAPI.d.ts +3071 -0
  52. package/cjs/types/CamOverlayAPI/CamOverlayAPI.js +127 -0
  53. package/cjs/types/CamOverlayAPI/accuweatherSchema.d.ts +114 -0
  54. package/cjs/types/CamOverlayAPI/accuweatherSchema.js +50 -0
  55. package/cjs/types/CamOverlayAPI/customGraphicsSchema.d.ts +783 -0
  56. package/cjs/types/CamOverlayAPI/customGraphicsSchema.js +75 -0
  57. package/cjs/types/CamOverlayAPI/imagesSchema.d.ts +122 -0
  58. package/cjs/types/CamOverlayAPI/imagesSchema.js +12 -0
  59. package/cjs/types/CamOverlayAPI/index.d.ts +9 -0
  60. package/cjs/types/CamOverlayAPI/index.js +25 -0
  61. package/cjs/types/CamOverlayAPI/infotickerSchema.d.ts +130 -0
  62. package/cjs/types/CamOverlayAPI/infotickerSchema.js +29 -0
  63. package/cjs/types/CamOverlayAPI/pipSchema.d.ts +166 -0
  64. package/cjs/types/CamOverlayAPI/pipSchema.js +42 -0
  65. package/cjs/types/CamOverlayAPI/ptzCompassSchema.d.ts +126 -0
  66. package/cjs/types/CamOverlayAPI/ptzCompassSchema.js +28 -0
  67. package/cjs/types/CamOverlayAPI/ptzSchema.d.ts +146 -0
  68. package/cjs/types/CamOverlayAPI/ptzSchema.js +15 -0
  69. package/cjs/types/CamOverlayAPI/screenSharingSchema.d.ts +79 -0
  70. package/cjs/types/CamOverlayAPI/screenSharingSchema.js +11 -0
  71. package/cjs/types/CamOverlayAPI/webCameraSharingSchema.d.ts +79 -0
  72. package/cjs/types/CamOverlayAPI/webCameraSharingSchema.js +11 -0
  73. package/cjs/types/CamOverlayDrawingAPI.d.ts +58 -0
  74. package/cjs/types/CamOverlayDrawingAPI.js +2 -0
  75. package/cjs/types/CamOverlayPainter.d.ts +74 -0
  76. package/cjs/types/CamOverlayPainter.js +2 -0
  77. package/cjs/types/CamScripterAPI.d.ts +82 -17
  78. package/cjs/types/CamScripterAPI.js +22 -7
  79. package/cjs/types/CamStreamerAPI.d.ts +16 -5
  80. package/cjs/types/CamStreamerAPI.js +5 -1
  81. package/cjs/types/CamSwitcherAPI.d.ts +4 -6
  82. package/cjs/types/CamSwitcherEvents.d.ts +77 -0
  83. package/cjs/types/CamSwitcherEvents.js +8 -0
  84. package/cjs/types/PlaneTrackerAPI.d.ts +8 -0
  85. package/cjs/types/PlaneTrackerAPI.js +2 -0
  86. package/cjs/types/VapixAPI.d.ts +635 -520
  87. package/cjs/types/VapixAPI.js +62 -24
  88. package/cjs/types/common.d.ts +14 -5
  89. package/cjs/web/DefaultClient.d.ts +5 -5
  90. package/cjs/web/DefaultClient.js +22 -10
  91. package/cjs/web/WsClient.js +2 -2
  92. package/esm/CamOverlayAPI.d.ts +48 -26
  93. package/esm/CamOverlayAPI.js +167 -84
  94. package/esm/CamOverlayDrawingAPI.d.ts +2 -47
  95. package/esm/CamOverlayDrawingAPI.js +6 -3
  96. package/esm/CamOverlayPainter/Frame.d.ts +8 -37
  97. package/esm/CamOverlayPainter/Frame.js +33 -0
  98. package/esm/CamOverlayPainter/Painter.d.ts +16 -10
  99. package/esm/CamOverlayPainter/Painter.js +5 -3
  100. package/esm/CamOverlayPainter/ResourceManager.d.ts +3 -2
  101. package/esm/CamOverlayPainter/ResourceManager.js +7 -11
  102. package/esm/CamScripterAPI.d.ts +34 -16
  103. package/esm/CamScripterAPI.js +46 -37
  104. package/esm/CamScripterAPICameraEventsGenerator.d.ts +1 -1
  105. package/esm/CamScripterAPICameraEventsGenerator.js +6 -3
  106. package/esm/CamStreamerAPI.d.ts +17 -14
  107. package/esm/CamStreamerAPI.js +32 -32
  108. package/esm/CamSwitcherAPI.d.ts +43 -37
  109. package/esm/CamSwitcherAPI.js +116 -107
  110. package/esm/CamSwitcherEvents.d.ts +1 -1
  111. package/esm/PlaneTrackerAPI.d.ts +43 -0
  112. package/esm/PlaneTrackerAPI.js +207 -0
  113. package/esm/VapixAPI.d.ts +56 -42
  114. package/esm/VapixAPI.js +297 -208
  115. package/esm/VapixEvents.d.ts +1 -1
  116. package/esm/VapixEvents.js +3 -3
  117. package/esm/errors/errors.d.ts +3 -0
  118. package/esm/errors/errors.js +6 -0
  119. package/esm/events/AxisCameraStationEvents.d.ts +7 -4
  120. package/esm/events/AxisCameraStationEvents.js +18 -13
  121. package/esm/events/GenetecAgent.d.ts +6 -3
  122. package/esm/events/GenetecAgent.js +20 -9
  123. package/esm/index.d.ts +14 -1
  124. package/esm/index.js +14 -1
  125. package/esm/internal/Digest.js +6 -6
  126. package/esm/internal/ProxyClient.d.ts +8 -9
  127. package/esm/internal/ProxyClient.js +25 -29
  128. package/esm/internal/types.d.ts +42 -0
  129. package/esm/internal/types.js +1 -0
  130. package/esm/internal/utils.d.ts +4 -1
  131. package/esm/internal/utils.js +17 -1
  132. package/esm/internal/versionCompare.d.ts +2 -2
  133. package/esm/node/DefaultClient.d.ts +5 -6
  134. package/esm/node/DefaultClient.js +12 -14
  135. package/esm/node/HttpRequestSender.d.ts +1 -0
  136. package/esm/node/HttpRequestSender.js +13 -3
  137. package/esm/node/HttpServer.js +1 -1
  138. package/esm/node/WsClient.d.ts +2 -1
  139. package/esm/node/index.d.ts +2 -0
  140. package/esm/node/index.js +2 -0
  141. package/esm/types/CamOverlayAPI/CamOverlayAPI.d.ts +3071 -0
  142. package/esm/types/CamOverlayAPI/CamOverlayAPI.js +124 -0
  143. package/esm/types/CamOverlayAPI/accuweatherSchema.d.ts +114 -0
  144. package/esm/types/CamOverlayAPI/accuweatherSchema.js +46 -0
  145. package/esm/types/CamOverlayAPI/customGraphicsSchema.d.ts +783 -0
  146. package/esm/types/CamOverlayAPI/customGraphicsSchema.js +71 -0
  147. package/esm/types/CamOverlayAPI/imagesSchema.d.ts +122 -0
  148. package/esm/types/CamOverlayAPI/imagesSchema.js +8 -0
  149. package/esm/types/CamOverlayAPI/index.d.ts +9 -0
  150. package/esm/types/CamOverlayAPI/index.js +9 -0
  151. package/esm/types/CamOverlayAPI/infotickerSchema.d.ts +130 -0
  152. package/esm/types/CamOverlayAPI/infotickerSchema.js +25 -0
  153. package/esm/types/CamOverlayAPI/pipSchema.d.ts +166 -0
  154. package/esm/types/CamOverlayAPI/pipSchema.js +38 -0
  155. package/esm/types/CamOverlayAPI/ptzCompassSchema.d.ts +126 -0
  156. package/esm/types/CamOverlayAPI/ptzCompassSchema.js +24 -0
  157. package/esm/types/CamOverlayAPI/ptzSchema.d.ts +146 -0
  158. package/esm/types/CamOverlayAPI/ptzSchema.js +11 -0
  159. package/esm/types/CamOverlayAPI/screenSharingSchema.d.ts +79 -0
  160. package/esm/types/CamOverlayAPI/screenSharingSchema.js +7 -0
  161. package/esm/types/CamOverlayAPI/webCameraSharingSchema.d.ts +79 -0
  162. package/esm/types/CamOverlayAPI/webCameraSharingSchema.js +7 -0
  163. package/esm/types/CamOverlayDrawingAPI.d.ts +58 -0
  164. package/esm/types/CamOverlayDrawingAPI.js +1 -0
  165. package/esm/types/CamOverlayPainter.d.ts +74 -0
  166. package/esm/types/CamOverlayPainter.js +1 -0
  167. package/esm/types/CamScripterAPI.d.ts +82 -17
  168. package/esm/types/CamScripterAPI.js +21 -6
  169. package/esm/types/CamStreamerAPI.d.ts +16 -5
  170. package/esm/types/CamStreamerAPI.js +4 -0
  171. package/esm/types/CamSwitcherAPI.d.ts +4 -6
  172. package/esm/types/CamSwitcherEvents.d.ts +77 -0
  173. package/esm/types/CamSwitcherEvents.js +8 -0
  174. package/esm/types/PlaneTrackerAPI.d.ts +8 -0
  175. package/esm/types/PlaneTrackerAPI.js +1 -0
  176. package/esm/types/VapixAPI.d.ts +635 -520
  177. package/esm/types/VapixAPI.js +61 -23
  178. package/esm/types/common.d.ts +14 -5
  179. package/esm/web/DefaultClient.d.ts +5 -5
  180. package/esm/web/DefaultClient.js +22 -10
  181. package/esm/web/WsClient.js +2 -2
  182. package/package.json +9 -8
  183. package/cjs/internal/common.d.ts +0 -39
  184. package/cjs/internal/common.js +0 -27
  185. package/cjs/node/WsEventClient.d.ts +0 -13
  186. package/cjs/node/WsEventClient.js +0 -22
  187. package/cjs/types/CamOverlayAPI.d.ts +0 -188
  188. package/cjs/types/CamOverlayAPI.js +0 -47
  189. package/esm/internal/common.d.ts +0 -39
  190. package/esm/internal/common.js +0 -20
  191. package/esm/node/WsEventClient.d.ts +0 -13
  192. package/esm/node/WsEventClient.js +0 -18
  193. package/esm/types/CamOverlayAPI.d.ts +0 -188
  194. package/esm/types/CamOverlayAPI.js +0 -44
package/esm/VapixAPI.js CHANGED
@@ -1,55 +1,65 @@
1
1
  import * as prettifyXml from 'prettify-xml';
2
- import { parseStringPromise } from 'xml2js';
3
- import { isNullish, responseStringify } from './internal/common';
4
- import { sdCardWatchedStatuses, APP_IDS, maxFpsResponseSchema, dateTimeinfoSchema, audioDeviceRequestSchema, audioSampleRatesResponseSchema, } from './types/VapixAPI';
5
- import { ApplicationAPIError, MaxFPSError, NoDeviceInfoError, SDCardActionError, SDCardJobError, } from './errors/errors';
2
+ import { arrayToUrl, isNullish, paramToUrl, responseStringify } from './internal/utils';
3
+ import { sdCardWatchedStatuses, APP_IDS, maxFpsResponseSchema, dateTimeinfoSchema, audioDeviceRequestSchema, audioSampleRatesResponseSchema, timeZoneSchema, getPortsResponseSchema, } from './types/VapixAPI';
4
+ import { ApplicationAPIError, MaxFPSError, NoDeviceInfoError, PtzNotSupportedError, SDCardActionError, SDCardJobError, } from './errors/errors';
6
5
  import { ProxyClient } from './internal/ProxyClient';
7
- import { arrayToUrl, paramToUrl } from './internal/utils';
8
6
  import { z } from 'zod';
7
+ import { XMLParser } from 'fast-xml-parser';
9
8
  export class VapixAPI {
10
9
  client;
11
- constructor(client, getProxyUrl) {
12
- this.client = new ProxyClient(client, getProxyUrl);
10
+ constructor(client) {
11
+ this.client = client;
13
12
  }
14
- async getUrlEncoded(proxy = null, path, parameters, headers = {}) {
13
+ getClient(proxyParams) {
14
+ return proxyParams ? new ProxyClient(this.client, proxyParams) : this.client;
15
+ }
16
+ async postUrlEncoded(path, parameters, headers, options) {
15
17
  const data = paramToUrl(parameters);
16
18
  const head = { ...headers, 'Content-Type': 'application/x-www-form-urlencoded' };
17
- const res = await this.client.post(proxy, path, data, {}, head);
19
+ const agent = this.getClient(options?.proxyParams);
20
+ const res = await agent.post({ path, data, headers: head, timeout: options?.timeout });
18
21
  if (!res.ok) {
19
22
  throw new Error(await responseStringify(res));
20
23
  }
21
24
  return res;
22
25
  }
23
- async postJson(proxy = null, path, jsonData, headers = {}) {
26
+ async postJson(path, jsonData, headers, options) {
24
27
  const data = JSON.stringify(jsonData);
25
28
  const head = { ...headers, 'Content-Type': 'application/json' };
26
- const res = await this.client.post(proxy, path, data, {}, head);
29
+ const agent = this.getClient(options?.proxyParams);
30
+ const res = await agent.post({ path, data, headers: head, timeout: options?.timeout });
27
31
  if (!res.ok) {
28
32
  throw new Error(await responseStringify(res));
29
33
  }
30
34
  return res;
31
35
  }
32
- async getCameraImage(params, proxy = null) {
33
- return await this.client.get(proxy, '/axis-cgi/jpg/image.cgi', params);
36
+ async getCameraImage(parameters, options) {
37
+ const agent = this.getClient(options?.proxyParams);
38
+ return await agent.get({ path: '/axis-cgi/jpg/image.cgi', parameters, timeout: options?.timeout });
34
39
  }
35
- async getEventDeclarations(proxy = null) {
40
+ async getEventDeclarations(options) {
36
41
  const data = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' +
37
42
  '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
38
43
  'xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
39
44
  '<GetEventInstances xmlns="http://www.axis.com/vapix/ws/event1"/>' +
40
45
  '</s:Body>' +
41
46
  '</s:Envelope>';
42
- const res = await this.client.post(proxy, '/vapix/services', data, { 'Content-Type': 'application/soap+xml' });
47
+ const agent = this.getClient(options?.proxyParams);
48
+ const res = await agent.post({
49
+ path: '/vapix/services',
50
+ data,
51
+ headers: { 'Content-Type': 'application/soap+xml' },
52
+ });
43
53
  if (!res.ok) {
44
54
  throw new Error(await responseStringify(res));
45
55
  }
46
56
  const declarations = await res.text();
47
57
  return prettifyXml(declarations);
48
58
  }
49
- async getSupportedAudioSampleRate(proxy = null) {
50
- const url = '/axis-cgi/audio/streamingcapabilities.cgi';
51
- const formData = { apiVersion: '1.0', method: 'list' };
52
- const res = await this.postJson(proxy, url, formData);
59
+ async getSupportedAudioSampleRate(options) {
60
+ const path = '/axis-cgi/audio/streamingcapabilities.cgi';
61
+ const jsonData = { apiVersion: '1.0', method: 'list' };
62
+ const res = await this.postJson(path, jsonData, undefined, options);
53
63
  const encoders = audioSampleRatesResponseSchema.parse(await res.json()).data.encoders;
54
64
  const data = encoders.aac ?? encoders.AAC ?? [];
55
65
  return data.map((item) => {
@@ -59,7 +69,7 @@ export class VapixAPI {
59
69
  };
60
70
  });
61
71
  }
62
- async performAutofocus(proxy = null) {
72
+ async performAutofocus(options) {
63
73
  try {
64
74
  const data = {
65
75
  apiVersion: '1',
@@ -72,24 +82,26 @@ export class VapixAPI {
72
82
  ],
73
83
  },
74
84
  };
75
- await this.postJson(proxy, '/axis-cgi/opticscontrol.cgi', data);
85
+ await this.postJson('/axis-cgi/opticscontrol.cgi', data, undefined, options);
76
86
  }
77
87
  catch (err) {
78
- await this.postJson(proxy, '/axis-cgi/opticssetup.cgi', {
88
+ await this.postUrlEncoded('/axis-cgi/opticssetup.cgi', {
79
89
  autofocus: 'perform',
80
90
  source: '1',
81
- });
91
+ }, undefined, options);
82
92
  }
83
93
  }
84
- async checkSDCard(proxy = null) {
85
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/disks/list.cgi', {
94
+ async checkSDCard(options) {
95
+ const res = await this.postUrlEncoded('/axis-cgi/disks/list.cgi', {
86
96
  diskid: 'SD_DISK',
97
+ }, undefined, options);
98
+ const xmlText = await res.text();
99
+ const parser = new XMLParser({
100
+ ignoreAttributes: false,
101
+ attributeNamePrefix: '',
102
+ allowBooleanAttributes: true,
87
103
  });
88
- const result = await parseStringPromise(await res.text(), {
89
- ignoreAttrs: false,
90
- mergeAttrs: true,
91
- explicitArray: false,
92
- });
104
+ const result = parser.parse(xmlText);
93
105
  const data = result.root.disks.disk;
94
106
  return {
95
107
  totalSize: parseInt(data.totalsize),
@@ -97,53 +109,56 @@ export class VapixAPI {
97
109
  status: sdCardWatchedStatuses.includes(data.status) ? data.status : 'disconnected',
98
110
  };
99
111
  }
100
- mountSDCard(proxy = null) {
101
- return this._doSDCardMountAction('MOUNT', proxy);
112
+ mountSDCard(options) {
113
+ return this._doSDCardMountAction('MOUNT', options);
102
114
  }
103
- unmountSDCard(proxy = null) {
104
- return this._doSDCardMountAction('UNMOUNT', proxy);
115
+ unmountSDCard(options) {
116
+ return this._doSDCardMountAction('UNMOUNT', options);
105
117
  }
106
- async _doSDCardMountAction(action, proxy = null) {
107
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/disks/mount.cgi', {
118
+ async _doSDCardMountAction(action, options) {
119
+ const res = await this.postUrlEncoded('/axis-cgi/disks/mount.cgi', {
108
120
  action: action,
109
121
  diskid: 'SD_DISK',
122
+ }, undefined, options);
123
+ const textXml = await res.text();
124
+ const parser = new XMLParser({
125
+ ignoreAttributes: false,
126
+ attributeNamePrefix: '',
127
+ allowBooleanAttributes: true,
110
128
  });
111
- const result = await parseStringPromise(await res.text(), {
112
- ignoreAttrs: false,
113
- mergeAttrs: true,
114
- explicitArray: false,
115
- });
129
+ const result = parser.parse(textXml);
116
130
  const job = result.root.job;
117
131
  if (job.result !== 'OK') {
118
132
  throw new SDCardActionError(action, await responseStringify(res));
119
133
  }
120
134
  return Number(job.jobid);
121
135
  }
122
- async fetchSDCardJobProgress(jobId, proxy = null) {
123
- const res = await this.getUrlEncoded(proxy, '/disks/job.cgi', {
136
+ async fetchSDCardJobProgress(jobId, options) {
137
+ const res = await this.postUrlEncoded('/disks/job.cgi', {
124
138
  jobid: String(jobId),
125
139
  diskid: 'SD_DISK',
140
+ }, undefined, options);
141
+ const textXml = await res.text();
142
+ const parser = new XMLParser({
143
+ ignoreAttributes: false,
144
+ attributeNamePrefix: '',
145
+ allowBooleanAttributes: true,
126
146
  });
127
- const result = await parseStringPromise(await res.text(), {
128
- ignoreAttrs: false,
129
- mergeAttrs: true,
130
- explicitArray: false,
131
- });
132
- const job = result.root.job;
147
+ const job = parser.parse(textXml).root.job;
133
148
  if (job.result !== 'OK') {
134
149
  throw new SDCardJobError();
135
150
  }
136
151
  return Number(job.progress);
137
152
  }
138
- downloadCameraReport(proxy = null) {
139
- return this.getUrlEncoded(proxy, '/axis-cgi/serverreport.cgi', { mode: 'text' });
153
+ downloadCameraReport(options) {
154
+ return this.postUrlEncoded('/axis-cgi/serverreport.cgi', { mode: 'text' }, undefined, options);
140
155
  }
141
- getSystemLog(proxy = null) {
142
- return this.getUrlEncoded(proxy, '/axis-cgi/admin/systemlog.cgi');
156
+ getSystemLog(options) {
157
+ return this.postUrlEncoded('/axis-cgi/admin/systemlog.cgi', undefined, undefined, options);
143
158
  }
144
- async getMaxFps(channel, proxy = null) {
159
+ async getMaxFps(channel, options) {
145
160
  const data = { apiVersion: '1.0', method: 'getCaptureModes' };
146
- const res = await this.postJson(proxy, '/axis-cgi/capturemode.cgi', data);
161
+ const res = await this.postJson('/axis-cgi/capturemode.cgi', data, undefined, options);
147
162
  const response = maxFpsResponseSchema.parse(await res.json());
148
163
  const channels = response.data;
149
164
  if (channels === undefined) {
@@ -163,77 +178,92 @@ export class VapixAPI {
163
178
  }
164
179
  return captureMode.maxFPS;
165
180
  }
166
- async getTimezone(proxy = null) {
167
- const data = { apiVersion: '1.0', method: 'getDateTimeInfo' };
168
- const res = await this.postJson(proxy, '/axis-cgi/time.cgi', data);
169
- return (await res.json())?.timeZone ?? 'Europe/Prague';
181
+ async getTimezone(options) {
182
+ try {
183
+ const agent = this.getClient(options?.proxyParams);
184
+ const resV2 = await agent.get({ path: '/config/rest/time/v2/timeZone', timeout: options?.timeout });
185
+ if (!resV2.ok) {
186
+ throw new Error(await responseStringify(resV2));
187
+ }
188
+ const json = await resV2.json();
189
+ const data = timeZoneSchema.parse(json);
190
+ if (data.status === 'error') {
191
+ throw new Error(data.error.message);
192
+ }
193
+ return data.data.activeTimeZone;
194
+ }
195
+ catch (error) {
196
+ console.warn('Failed to fetch time zone data from time API v2:', error instanceof Error ? error.message : JSON.stringify(error));
197
+ console.warn('Falling back to deprecated time API v1');
198
+ }
199
+ const data = await this.getDateTimeInfo(options);
200
+ if (data.data.timeZone === undefined) {
201
+ throw new Error('Time zone not setup on the device');
202
+ }
203
+ return data.data.timeZone;
170
204
  }
171
- async getDateTimeInfo(proxy = null) {
205
+ async getDateTimeInfo(options) {
172
206
  const data = { apiVersion: '1.0', method: 'getDateTimeInfo' };
173
- const res = await this.postJson(proxy, '/axis-cgi/time.cgi', data);
207
+ const res = await this.postJson('/axis-cgi/time.cgi', data, undefined, options);
174
208
  return dateTimeinfoSchema.parse(await res.json());
175
209
  }
176
- async getDevicesSettings(proxy = null) {
210
+ async getDevicesSettings(options) {
177
211
  const data = { apiVersion: '1.0', method: 'getDevicesSettings' };
178
- const res = await this.postJson(proxy, '/axis-cgi/audiodevicecontrol.cgi', data);
212
+ const res = await this.postJson('/axis-cgi/audiodevicecontrol.cgi', data, undefined, options);
179
213
  const result = audioDeviceRequestSchema.parse(await res.json());
180
- return result.devices.map((device) => ({
214
+ return result.data.devices.map((device) => ({
181
215
  ...device,
182
216
  inputs: (device.inputs || []).sort((a, b) => a.id.localeCompare(b.id)),
183
217
  outputs: (device.outputs || []).sort((a, b) => a.id.localeCompare(b.id)),
184
218
  }));
185
219
  }
186
- async fetchRemoteDeviceInfo(payload, proxy = null) {
187
- const res = await this.postJson(proxy, '/axis-cgi/basicdeviceinfo.cgi', payload);
188
- const result = await parseStringPromise(await res.text(), {
189
- ignoreAttrs: false,
190
- mergeAttrs: true,
191
- explicitArray: false,
192
- });
193
- if (isNullish(result.body.data)) {
220
+ async fetchRemoteDeviceInfo(payload, options) {
221
+ const res = await this.postJson('/axis-cgi/basicdeviceinfo.cgi', payload, undefined, options);
222
+ const json = await res.json();
223
+ if (isNullish(json.data)) {
194
224
  throw new NoDeviceInfoError();
195
225
  }
196
- return result.data;
226
+ return json.data;
197
227
  }
198
- async getHeaders(proxy = null) {
228
+ async getHeaders(options) {
199
229
  const data = { apiVersion: '1.0', method: 'list' };
200
- const res = await this.postJson(proxy, '/axis-cgi/customhttpheader.cgi', data);
230
+ const res = await this.postJson('/axis-cgi/customhttpheader.cgi', data, undefined, options);
201
231
  return z.object({ data: z.record(z.string()) }).parse(await res.json()).data;
202
232
  }
203
- async setHeaders(headers, proxy = null) {
233
+ async setHeaders(headers, options) {
204
234
  const data = { apiVersion: '1.0', method: 'set', params: headers };
205
- return this.postJson(proxy, '/axis-cgi/customhttpheader.cgi', data);
235
+ return this.postJson('/axis-cgi/customhttpheader.cgi', data, undefined, options);
206
236
  }
207
- async getParameter(paramNames, proxy = null) {
208
- const response = await this.getUrlEncoded(proxy, '/axis-cgi/param.cgi', {
237
+ async getParameter(paramNames, options) {
238
+ const response = await this.postUrlEncoded('/axis-cgi/param.cgi', {
209
239
  action: 'list',
210
240
  group: arrayToUrl(paramNames),
211
- });
212
- return parseParameters(await response.text());
241
+ }, undefined, options);
242
+ return VapixAPI.parseParameters(await response.text());
213
243
  }
214
- async setParameter(params, proxy = null) {
215
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/param.cgi', {
244
+ async setParameter(params, options) {
245
+ const res = await this.postUrlEncoded('/axis-cgi/param.cgi', {
216
246
  ...params,
217
247
  action: 'update',
218
- });
248
+ }, undefined, options);
219
249
  const responseText = await res.text();
220
250
  if (responseText.startsWith('# Error')) {
221
251
  throw new Error(responseText);
222
252
  }
223
253
  return true;
224
254
  }
225
- async getGuardTourList(proxy = null) {
255
+ async getGuardTourList(options) {
226
256
  const gTourList = new Array();
227
- const response = await this.getParameter('GuardTour', proxy);
257
+ const response = await this.getParameter('GuardTour', options);
228
258
  for (let i = 0; i < 20; i++) {
229
259
  const gTourBaseName = 'root.GuardTour.G' + i;
230
260
  if (gTourBaseName + '.CamNbr' in response) {
231
261
  const gTour = {
232
262
  id: gTourBaseName,
233
263
  camNbr: response[gTourBaseName + '.CamNbr'],
234
- name: response[gTourBaseName + '.Name'],
264
+ name: response[gTourBaseName + '.Name'] ?? 'Guard Tour ' + (i + 1),
235
265
  randomEnabled: response[gTourBaseName + '.RandomEnabled'],
236
- running: response[gTourBaseName + '.Running'],
266
+ running: response[gTourBaseName + '.Running'] ?? 'no',
237
267
  timeBetweenSequences: response[gTourBaseName + '.TimeBetweenSequences'],
238
268
  tour: [],
239
269
  };
@@ -258,16 +288,16 @@ export class VapixAPI {
258
288
  }
259
289
  return gTourList;
260
290
  }
261
- setGuardTourEnabled(guardTourID, enable, proxy = null) {
262
- const options = {};
263
- options[guardTourID + '.Running'] = enable ? 'yes' : 'no';
264
- return this.setParameter(options, proxy);
291
+ setGuardTourEnabled(guardTourID, enable, options) {
292
+ const params = {};
293
+ params[guardTourID + '.Running'] = enable ? 'yes' : 'no';
294
+ return this.setParameter(params, options);
265
295
  }
266
- async getPTZPresetList(channel, proxy = null) {
267
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/com/ptz.cgi', {
296
+ async getPTZPresetList(channel, options) {
297
+ const res = await this.postUrlEncoded('/axis-cgi/com/ptz.cgi', {
268
298
  query: 'presetposcam',
269
299
  camera: channel.toString(),
270
- });
300
+ }, undefined, options);
271
301
  const text = await res.text();
272
302
  const lines = text.split(/[\r\n]/);
273
303
  const positions = [];
@@ -282,100 +312,159 @@ export class VapixAPI {
282
312
  }
283
313
  return positions;
284
314
  }
285
- async listPTZ(camera, proxy = null) {
315
+ async listPTZ(camera, options) {
286
316
  const url = `/axis-cgi/com/ptz.cgi`;
287
- const response = await this.getUrlEncoded(proxy, url, {
317
+ const response = await this.postUrlEncoded(url, {
288
318
  camera,
289
319
  query: 'presetposcamdata',
290
320
  format: 'json',
291
- });
292
- return parseCameraPtzResponse(await response.text())[camera] ?? [];
321
+ }, undefined, options);
322
+ const text = await response.text();
323
+ if (text === '') {
324
+ throw new PtzNotSupportedError();
325
+ }
326
+ return VapixAPI.parseCameraPtzResponse(text)[camera] ?? [];
293
327
  }
294
- async listPtzVideoSourceOverview(proxy = null) {
295
- const response = await this.getUrlEncoded(proxy, '/axis-cgi/com/ptz.cgi', {
328
+ async listPtzVideoSourceOverview(options) {
329
+ const response = await this.postUrlEncoded('/axis-cgi/com/ptz.cgi', {
296
330
  query: 'presetposall',
297
331
  format: 'json',
298
- });
299
- const data = parseCameraPtzResponse(await response.text());
332
+ }, undefined, options);
333
+ const text = await response.text();
334
+ if (text === '') {
335
+ throw new PtzNotSupportedError();
336
+ }
337
+ const data = VapixAPI.parseCameraPtzResponse(text);
300
338
  const res = {};
301
- Object.keys(data).forEach((camera) => {
302
- res[Number(camera) - 1] = data[Number(camera)].map(({ data: itemData, ...d }) => d);
339
+ Object.keys(data)
340
+ .map(Number)
341
+ .forEach((camera) => {
342
+ if (data[camera] !== undefined) {
343
+ res[camera - 1] = data[camera]?.map(({ data: itemData, ...d }) => d);
344
+ }
303
345
  });
304
346
  return res;
305
347
  }
306
- goToPreset(channel, presetName, proxy = null) {
307
- return this.getUrlEncoded(proxy, '/axis-cgi/com/ptz.cgi', {
348
+ goToPreset(channel, presetName, options) {
349
+ return this.postUrlEncoded('/axis-cgi/com/ptz.cgi', {
308
350
  camera: channel.toString(),
309
351
  gotoserverpresetname: presetName,
310
- });
352
+ }, undefined, options);
311
353
  }
312
- async getPtzPosition(camera, proxy = null) {
313
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/com/ptz.cgi', {
354
+ async getPtzPosition(camera, options) {
355
+ const res = await this.postUrlEncoded('/axis-cgi/com/ptz.cgi', {
314
356
  query: 'position',
315
357
  camera: camera.toString(),
316
- });
317
- const params = parseParameters(await res.text());
358
+ }, undefined, options);
359
+ const params = VapixAPI.parseParameters(await res.text());
318
360
  return {
319
361
  pan: Number(params.pan),
320
362
  tilt: Number(params.tilt),
321
363
  zoom: Number(params.zoom),
322
364
  };
323
365
  }
324
- async getInputState(port, proxy = null) {
325
- const response = await (await this.getUrlEncoded(proxy, '/axis-cgi/io/port.cgi', { checkactive: port.toString() })).text();
326
- return response.split('=')[1].indexOf('active') === 0;
327
- }
328
- async setOutputState(port, active, proxy = null) {
329
- return this.getUrlEncoded(proxy, '/axis-cgi/io/port.cgi', { action: active ? `${port}:/` : `${port}:\\` });
330
- }
331
- async getApplicationList(proxy = null) {
332
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/list.cgi');
366
+ async getPorts(options) {
367
+ const res = await this.postJson('/axis-cgi/io/portmanagement.cgi', {
368
+ apiVersion: '1.0',
369
+ context: '',
370
+ method: 'getPorts',
371
+ }, undefined, options);
372
+ const portResponseParsed = await getPortsResponseSchema.parse(res.json());
373
+ return portResponseParsed.data.items;
374
+ }
375
+ async setPorts(ports, options) {
376
+ await this.postJson('/axis-cgi/io/portmanagement.cgi', {
377
+ apiVersion: '1.0',
378
+ context: '',
379
+ method: 'setPorts',
380
+ params: { ports },
381
+ }, undefined, options);
382
+ }
383
+ async setPortStateSequence(port, sequence, options) {
384
+ await this.postJson('/axis-cgi/io/portmanagement.cgi', {
385
+ apiVersion: '1.0',
386
+ context: '',
387
+ method: 'setStateSequence',
388
+ params: { port, sequence },
389
+ }, undefined, options);
390
+ }
391
+ async getApplicationList(options) {
392
+ const agent = this.getClient(options?.proxyParams);
393
+ const res = await agent.get({ path: '/axis-cgi/applications/list.cgi', timeout: options?.timeout });
333
394
  const xml = await res.text();
334
- const result = (await parseStringPromise(xml));
335
- const apps = [];
336
- for (let i = 0; i < result.reply.application.length; i++) {
337
- apps.push({
338
- ...result.reply.application[i].$,
339
- appId: APP_IDS.find((id) => id.toLowerCase() === result.reply.application[i].$.Name.toLowerCase()) ?? null,
340
- });
395
+ const parser = new XMLParser({
396
+ ignoreAttributes: false,
397
+ attributeNamePrefix: '',
398
+ allowBooleanAttributes: true,
399
+ });
400
+ const result = parser.parse(xml);
401
+ let apps = result.reply.application ?? [];
402
+ if (!Array.isArray(apps)) {
403
+ apps = [apps];
341
404
  }
342
- return apps;
405
+ return apps.map((app) => {
406
+ return {
407
+ ...app,
408
+ appId: APP_IDS.find((id) => id.toLowerCase() === app.Name.toLowerCase()) ?? null,
409
+ };
410
+ });
343
411
  }
344
- async startApplication(applicationID, proxy = null) {
345
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/control.cgi', {
346
- package: applicationID.toLowerCase(),
347
- action: 'start',
412
+ async startApplication(applicationID, options) {
413
+ const agent = this.getClient(options?.proxyParams);
414
+ const res = await agent.get({
415
+ path: '/axis-cgi/applications/control.cgi',
416
+ parameters: {
417
+ package: applicationID.toLowerCase(),
418
+ action: 'start',
419
+ },
420
+ timeout: options?.timeout,
348
421
  });
349
422
  const text = (await res.text()).trim().toLowerCase();
350
423
  if (text !== 'ok' && !(text.startsWith('error:') && text.substring(7) === '6')) {
351
424
  throw new ApplicationAPIError('START', await responseStringify(res));
352
425
  }
353
426
  }
354
- async restartApplication(applicationID, proxy = null) {
355
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/control.cgi', {
356
- package: applicationID.toLowerCase(),
357
- action: 'restart',
427
+ async restartApplication(applicationID, options) {
428
+ const agent = this.getClient(options?.proxyParams);
429
+ const res = await agent.get({
430
+ path: '/axis-cgi/applications/control.cgi',
431
+ parameters: {
432
+ package: applicationID.toLowerCase(),
433
+ action: 'restart',
434
+ },
435
+ timeout: options?.timeout,
358
436
  });
359
437
  const text = (await res.text()).trim().toLowerCase();
360
438
  if (text !== 'ok') {
361
439
  throw new ApplicationAPIError('RESTART', await responseStringify(res));
362
440
  }
363
441
  }
364
- async stopApplication(applicationID, proxy = null) {
365
- const res = await this.getUrlEncoded(proxy, '/axis-cgi/applications/control.cgi', {
366
- package: applicationID.toLowerCase(),
367
- action: 'stop',
442
+ async stopApplication(applicationID, options) {
443
+ const agent = this.getClient(options?.proxyParams);
444
+ const res = await agent.get({
445
+ path: '/axis-cgi/applications/control.cgi',
446
+ parameters: {
447
+ package: applicationID.toLowerCase(),
448
+ action: 'stop',
449
+ },
450
+ timeout: options?.timeout,
368
451
  });
369
452
  const text = (await res.text()).trim().toLowerCase();
370
453
  if (text !== 'ok' && !(text.startsWith('error:') && text.substring(7) === '6')) {
371
454
  throw new ApplicationAPIError('STOP', await responseStringify(res));
372
455
  }
373
456
  }
374
- async installApplication(data, fileName) {
457
+ async installApplication(data, fileName, options) {
375
458
  const formData = new FormData();
376
459
  formData.append('packfil', data, fileName);
377
- const res = await this.client.post(null, '/axis-cgi/applications/upload.cgi', formData, {}, {
378
- contentType: 'application/octet-stream',
460
+ const agent = this.getClient(options?.proxyParams);
461
+ const res = await agent.post({
462
+ path: '/axis-cgi/applications/upload.cgi',
463
+ data: formData,
464
+ headers: {
465
+ contentType: 'application/octet-stream',
466
+ },
467
+ timeout: options?.timeout ?? 120000,
379
468
  });
380
469
  if (!res.ok) {
381
470
  throw new Error(await responseStringify(res));
@@ -385,70 +474,70 @@ export class VapixAPI {
385
474
  throw new Error('installing error: ' + text);
386
475
  }
387
476
  }
388
- }
389
- const parseParameters = (response) => {
390
- const params = {};
391
- const lines = response.split(/[\r\n]/);
392
- for (let i = 0; i < lines.length; i++) {
393
- if (lines[i].length === 0 || lines[i].substring(0, 7) === '# Error') {
394
- continue;
395
- }
396
- const delimiterPos = lines[i].indexOf('=');
397
- if (delimiterPos !== -1) {
398
- const paramName = lines[i].substring(0, delimiterPos);
399
- const paramValue = lines[i].substring(delimiterPos + 1);
400
- params[paramName] = paramValue;
401
- }
402
- }
403
- return params;
404
- };
405
- const parseCameraPtzResponse = (response) => {
406
- const json = JSON.parse(response);
407
- const parsed = {};
408
- Object.keys(json).forEach((key) => {
409
- if (!key.startsWith('Camera ')) {
410
- return;
411
- }
412
- const camera = Number(key.replace('Camera ', ''));
413
- if (json[key].presets !== undefined) {
414
- parsed[camera] = parsePtz(json[key].presets);
415
- }
416
- });
417
- return parsed;
418
- };
419
- const parsePtz = (parsed) => {
420
- const res = [];
421
- parsed.forEach((value) => {
422
- const delimiterPos = value.indexOf('=');
423
- if (delimiterPos === -1) {
424
- return;
425
- }
426
- if (!value.startsWith('presetposno')) {
427
- return;
428
- }
429
- const id = Number(value.substring(11, delimiterPos));
430
- if (Number.isNaN(id)) {
431
- return;
477
+ static parseParameters = (response) => {
478
+ const params = {};
479
+ const lines = response.split(/[\r\n]/);
480
+ for (const line of lines) {
481
+ if (line.length === 0 || line.substring(0, 7) === '# Error') {
482
+ continue;
483
+ }
484
+ const delimiterPos = line.indexOf('=');
485
+ if (delimiterPos !== -1) {
486
+ const paramName = line.substring(0, delimiterPos).replace('root.', '');
487
+ const paramValue = line.substring(delimiterPos + 1);
488
+ params[paramName] = paramValue;
489
+ }
432
490
  }
433
- const data = value.substring(delimiterPos + 1).split(':');
434
- const getValue = (valueName) => {
435
- for (const d of data) {
436
- const p = d.split('=');
437
- if (p[0] === valueName) {
438
- return Number(p[1]);
439
- }
491
+ return params;
492
+ };
493
+ static parseCameraPtzResponse = (response) => {
494
+ const json = JSON.parse(response);
495
+ const parsed = {};
496
+ Object.keys(json).forEach((key) => {
497
+ if (!key.startsWith('Camera ')) {
498
+ return;
499
+ }
500
+ const camera = Number(key.replace('Camera ', ''));
501
+ if (json[key].presets !== undefined) {
502
+ parsed[camera] = VapixAPI.parsePtz(json[key].presets);
440
503
  }
441
- return 0;
442
- };
443
- res.push({
444
- id,
445
- name: data[0],
446
- data: {
447
- pan: getValue('pan'),
448
- tilt: getValue('tilt'),
449
- zoom: getValue('zoom'),
450
- },
451
504
  });
452
- });
453
- return res;
454
- };
505
+ return parsed;
506
+ };
507
+ static parsePtz = (parsed) => {
508
+ const res = [];
509
+ parsed.forEach((value) => {
510
+ const delimiterPos = value.indexOf('=');
511
+ if (delimiterPos === -1) {
512
+ return;
513
+ }
514
+ if (!value.startsWith('presetposno')) {
515
+ return;
516
+ }
517
+ const id = Number(value.substring(11, delimiterPos));
518
+ if (Number.isNaN(id)) {
519
+ return;
520
+ }
521
+ const data = value.substring(delimiterPos + 1).split(':');
522
+ const getValue = (valueName) => {
523
+ for (const d of data) {
524
+ const p = d.split('=');
525
+ if (p[0] === valueName) {
526
+ return Number(p[1]);
527
+ }
528
+ }
529
+ return 0;
530
+ };
531
+ res.push({
532
+ id,
533
+ name: data[0] ?? 'Preset ' + id,
534
+ data: {
535
+ pan: getValue('pan'),
536
+ tilt: getValue('tilt'),
537
+ zoom: getValue('zoom'),
538
+ },
539
+ });
540
+ });
541
+ return res;
542
+ };
543
+ }