├── .gitignore
├── .vs
└── slnx.sqlite
├── CHANGELOG.md
├── README.md
├── index.js
├── lib
├── report.js
├── reportExecution.js
├── reportExecutionUrl.js
├── reportService.js
├── soap.js
└── utils.js
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/.vs/slnx.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vision10/mssql-ssrs/182c944eb49b13508b54c037d2669cf6f4597291/.vs/slnx.sqlite
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Change Log
2 |
3 | ### v2.4.2
4 | - packages bump
5 | ### v2.4.1
6 | - bugfix `uploadFiles` - reading files with multiple directories
7 | - packages bump
8 | ### v2.4.0
9 | - HTML render will automatically get associated image streams in base64 inside the html
10 | - packages bump
11 | ### v2.3.0
12 | - package updated to latest
13 | ### v2.1.0
14 | - replace encodeURI with encodeURIComponent for getReport by url
15 | - package updates
16 | ### v2.0.1-v2.0.4
17 | - packages bump
18 | - bug fix
19 | ### v2.0.0
20 | - update packages (soap v40+ dropped request and httpntlm in favour of axios and axios-ntlm)
21 | - drop internal promisify function, using soap async functions (returned result may change)
22 | - rewritten functionality using classes (big changes)
23 | - documentation updates
24 |
25 | ### v1.4.1
26 | - update packages
27 | - new option for upload reports `options` when deleting existing items - `keepDataSource` (default: false)
28 |
29 | ### v1.4.0
30 | - some documentation updates
31 | - droped internal NtlmSecurity, use soap ntlm security (NTLMSecurity)
32 | - update packages (dropped lodash, replace moment=>dayjs)
33 | - new `createClient` on reportService and reportExecution for multiple clients with diferent configurations
34 |
35 | ### v1.3.9 - v1.3.12
36 | - bug fix
37 |
38 | ### v1.3.8
39 | - auto convert definition parameter on `createReport` to base64 string
40 |
41 | ### v1.3.2 - v1.3.7
42 | - added `include` array to `uploadFiles`
43 | - bug fixes to `fixDataSourceReference`, `upload`
44 | - documentation update
45 | - packages update to latest
46 |
47 | ### v1.3.1
48 |
49 | - consistent parameters for all start functions `report.start`, `reportService.start` and `reportExecution.start`
50 | - documentation updates
51 | - minor buxfix
52 |
53 | ### v1.2.2 - v1.2.4
54 |
55 | - bug fix
56 |
57 | ### v1.2.1
58 |
59 | - packages update
60 |
61 | ### v1.2.0
62 |
63 | - modified `download` returned result
64 | - fixed some minor issues with `getReportByUrl`
65 | - exported `setServerUrl`
66 |
67 | ### v1.1.0
68 |
69 | - documentation update
70 | - added `readFiles`
71 | - `upload` and `uploadFiles` options changed
72 | - `deleteReports` option changed to `deleteExistingItems`
73 | - `auth` option changed to `dataSourceOptions`
74 | - removed `debug` option
75 | - added `logger` object with `log` and `warn` functions, or boolean(outputs to console)
76 | - added `exclude` array for `uploadFiles`, can exclude by name, extension, path
77 | - added `log` parameter to `fixDataSourceReference`
78 |
79 | ### v1.0.0
80 |
81 | - documentation update
82 | - replace custom soap package with original
83 | - default to ntlm request, does not override request if othes security is passed
84 | - auth option changed to [soap config](https://www.npmjs.com/package/soap#options)
85 | - export entire original soap not just custom `createClient` and `security`
86 | - other small improvements
87 |
88 | ### v0.3.0
89 |
90 | - documentation updates
91 | - option `useRs2010` on reportService start function has been changed to `useRs2012`
92 | - still defaults to using 2010
93 | - fixed issue with other types of security than ntlm
94 | - suport for basic security
95 |
96 | ### v0.2.0
97 |
98 | - bug fix for: `upload`, added debug option,
99 | - added: `fixDataSourceReference`
100 | - added: `getItemReferences`, `setItemReferences`
101 | - restricted `getServerUrl`, `setServerUrl`, `getRootFolder`, `setRootFolder`,
102 | - not exported outside the package
103 | - documentation updates
104 |
105 | ### v0.1.0 - v0.1.11 bug fix and documentation
106 |
107 | ### v0.1.0 first release
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](https://badge.fury.io/js/mssql-ssrs)
3 | # mssql-ssrs
4 |
5 | > Promise based api for MSSQL reporting services
6 |
7 | ## Table of contents
8 |
9 | - [Install](#install)
10 | - [Usage](#usage)
11 | - [Url/serverConfig/path](#url/serverConfig/path)
12 | - [Soap config](#soap-config)
13 | - [Report service options](#report-service-options)
14 | - [Security](#security)
15 | - [Report Service](#report-service)
16 | - [report service client](#report-service-client)
17 | - [client description](#client-description)
18 | - [list children](#list-children)
19 | - [get parameters for specific report](#get-parameters-for-specific-report)
20 | - [update parameters for specifig report](#update-parameters-for-specifig-report)
21 | - [test data source connection](#testing-data-source-connection)
22 | - [get report properties](#get-report-properties)
23 | - [set report properties](#set-report-properties)
24 | - [list all running jobs](#list-all-running-jobs)
25 | - [cancel running job](#cancel-running-job)
26 | - [get item definition](#get-item-definition)
27 | - [create folder](#create-folder)
28 | - [create data source](#create-data-source)
29 | - [create report](#create-report)
30 | - [delete item](#delete-item)
31 | - [get item datasources](#get-item-data-sources)
32 | - [set item datasources](#set-item-data-sources)
33 | - [get item references](#get-item-references)
34 | - [set item references](#set-item-references)
35 | - [create resource](#create-resource)
36 | - [Report Execution](#report-execution)
37 | - [get report execution client](#get-report-execution-client)
38 | - [get client description](#get-client-description)
39 | - [list available rendering extensions](#list-available-rendering-extensions)
40 | - [run report](#run-report)
41 | - [Report Execution with Url](#report-execution-via-url)
42 | - [run report](#run-report-with-url)
43 | - [Report manager](#report-manager)
44 | - [get report list](#get-report-list)
45 | - [cache report list](#cache-report-list)
46 | - [create a copy of a report](#create-a-copy-of-a-report)
47 | - [create link for report builder for specified report](#create-link-for-report-builder-for-specified-report)
48 | - [clear cached reports](#clear-cached-reports)
49 | - [read reports folder](#read-reports-folder)
50 | - [upload reports](#upload-reports)
51 | - [download reports](#download-reports)
52 | - [fix data source reference](#fix-data-source-reference)
53 | - [Soap](#client)
54 | - [create client](#create-client)
55 | - [security](#security)
56 | - [Contributors](#contributors)
57 |
58 |
59 | ## Install
60 |
61 | Install with [npm](http://github.com/isaacs/npm):
62 |
63 | ```
64 | npm install mssql-ssrs
65 | ```
66 |
67 | ## Usage
68 |
69 | MSSQL has 2 parts for reporting services:
70 | - report service for report management (create, search...)
71 | - report execution for report rendering (executing report)
72 |
73 | To start using reporting services we need to connect to the server first:
74 |
75 | start both services (reportService, reportExecution)
76 |
77 | ```js
78 | var { ReportManager } = require('mssql-ssrs');
79 |
80 | var ssrs = new ReportManager([cacheReports]);
81 | await ssrs.start(url/path/serverConfig, soapConfig [, options] [, security]);
82 |
83 | const list = await ssrs.reportService.listChildren(reportPath);
84 | const report = await ssrs.reportExecution.getReport(reportPath, fileType, parameters);
85 | ...
86 | ```
87 |
88 | or start them separately
89 |
90 | ```js
91 | var { ReportService, ReportExecution } = require('mssql-ssrs');
92 |
93 | var rs = new ReportService();
94 | await rs.start(url/Path/serverConfig, soapConfig [, options] [, security]);
95 |
96 | var re = new ReportExecution();
97 | await re.start(url/Path/serverConfig, soapConfig [, options] [, security]);
98 | ```
99 | **NOTE**: [Report Execution via Url](#report-execution-via-url) does not have or require `start`
100 |
101 | #### Url/serverConfig/path
102 |
103 | The `url/serverConfig/path` argument accepts a string url, config object or a system file path (the file path option must contain a valid ssrs wsdl file from reporting services):
104 |
105 | ```js
106 | var url = 'http(s)://:/ReportServer_',
107 | var serverConfig = {
108 | server: 'serverName',
109 | instance: 'serverInstance',
110 | isHttps: false, // optional, default: false
111 | port: 80, // optional, default: 80
112 | };
113 | ```
114 |
115 | #### Soap Config
116 |
117 | [soapConfig](https://www.npmjs.com/package/soap#options), can include directly on config object or on config.wsdl_options the folowing properties for ssrs connection:
118 | - `username`: '', (required)
119 | - `password`: '', (required)
120 | - `workstation`: '', (optional)
121 | - `domain`: '', (optional)
122 |
123 | #### Report Service Options
124 |
125 | - `rootFolder`: base folder added to `reportPath` parameters, default: '/'
126 | - `useRs2012`: specify witch version of wsdl should client use (2010/2012), default: false (2010)
127 | - `cache`: specify whether to cache report list, default false
128 | - by default hidden reports are not kept
129 | - `cacheOnStart`: specify whether to cache all reports when starting report services, default false
130 |
131 | #### Report Manager
132 |
133 | - `cacheReports` can also be set directly when instatiating ReportManager
134 | - new ReportManager(true/false) - default false
135 | - same as `cache` option on `start`
136 | - `cacheOnStart` option is stil needed if all reports should be cached at `start`
137 |
138 | #### Security
139 |
140 | More information on types of security see [soap security](https://github.com/vpulim/node-soap#security)
141 |
142 | Defaults to NTLM security so no extra steps needed, just start
143 |
144 | - NTLM security, more details here [Usage](#usage)
145 | ```js
146 | // ex:
147 | await ssrs.start(url, { username: username, password: password });
148 |
149 | // start everything
150 | await ssrs.start(url/Path/serverConfig, soapConfig [, options] [, security]);
151 | // or start separately
152 | var rs = new ReportService();
153 | await rs.start(url/Path/serverConfig, soapConfig [, options] [, security]);
154 | var re = new ReportExecution();
155 | await re.start(url/Path/serverConfig, soapConfig [, options] [, security]);
156 | ```
157 |
158 | - basic security and others
159 | ```js
160 | // added in the same way for any other security type you use
161 | // instanciating security type can differ
162 |
163 | var auth = { username: username, password: password };
164 | await ssrs.start(url, auth, null, 'basic');
165 |
166 | // or
167 |
168 | var wsdl_headers = {};
169 | var security = new ssrs.soap.security.BasicAuthSecurity(auth.username, auth.password);
170 | security.addHeaders(wsdl_headers); // add authorization
171 |
172 | await ssrs.start(url, { wsdl_headers: wsdl_headers }, null, security);
173 | ```
174 |
175 | ## Report Service
176 |
177 | - list of all reporting services [methods and options](https://docs.microsoft.com/en-us/dotnet/api/reportservice2010.reportingservice2010?view=sqlserver-2016)
178 | - not all methods where implemented
179 |
180 | ```js
181 | var { ReportService } = require('mssql-ssrs');
182 | var reportService = new ReportService();
183 |
184 | await reportService.start(url/Path/serverConfig, soapConfig [, options] [, security]);
185 | ```
186 |
187 | ### Report service client
188 |
189 | ```js
190 | var client = reportService.getClient();
191 | or
192 | reportService.client['functionName']()
193 | ```
194 |
195 | ### Client description
196 |
197 | ```js
198 | var description = reportService.getDescription();
199 | ```
200 |
201 | ### List children
202 |
203 | List all children down from current specified folder, if recursive is used it will go down into all folders
204 | ```js
205 | var reportList = await reportService.listChildren(reportPath[, isRcursive]);
206 | ```
207 |
208 | ### Get parameters for specific report
209 |
210 | ```js
211 | var params = await reportService.getReportParams(reportPath[, forRendering]);
212 | ```
213 |
214 | ### Update parameters for specifig report
215 |
216 | ```js
217 | var params = await reportService.updateReportParams(reportPath, params[, formatParams]);
218 | ```
219 |
220 | ### Testing data source connection
221 |
222 | For all DataSourceDefinition properties use [microsoft documentation](https://msdn.microsoft.com/en-us/library/reportservice2010.datasourcedefinition%28v=sql.120%29.aspx)
223 |
224 | ```js
225 | var status = await reportService.testDataSourceConnection(userName, password, dataSourceDefinition)
226 | ```
227 |
228 | Example for `dataSourceDefinition`:
229 |
230 | ```js
231 | DataSourceDefinition: {
232 | Extension: 'SQL',
233 | ConnectString: 'Data Source=\\;Initial Catalog='
234 | }
235 | ```
236 |
237 | ### Get report properties
238 |
239 | If properties are given, all report properties are returned. Report custom properties are not available
240 |
241 | ```js
242 | var properties = ['Hidden', 'Description'];
243 | // or
244 | var properties = [{ Name: 'Hidden' }, { Name: 'Description' }];
245 | var properties = await reportService.getProperties(reportPath[, properties])
246 | ```
247 |
248 | ### Set report properties
249 |
250 | ```js
251 | var properties = { Hidden: true, Description: 'my description' };
252 | // or
253 | var properties = [
254 | { Name: 'Hidden', Value: true },
255 | { Name: 'Description', Value: 'my description' }
256 | ];
257 | var properties = await reportService.setProperties(reportPath, properties)
258 | ```
259 |
260 | ### List all running jobs
261 |
262 | ```js
263 | var jobs = await reportService.listJobs()
264 | ```
265 |
266 | ### Cancel running job
267 |
268 | ```js
269 | await reportService.cancelJob(jobId)
270 | ```
271 |
272 | ### Get item definition
273 |
274 | ```js
275 | var rdl = await reportService.getItemDefinition(reportPath)
276 | ```
277 |
278 | ### Create folder
279 |
280 | ```js
281 | await reportService.createFolder(folderName, path)
282 | ```
283 |
284 | ### Create data source
285 |
286 | ```js
287 | var dataSource = await reportService.createDataSource(dataSourceName, folderPath, overwrite, definition, description, isHidden)
288 | ```
289 | #### Create data source
290 | - `dataSourceName`: The name for the data source including the file name and, in SharePoint mode, the extension (.rsds).
291 | - `folderPath`: The fully qualified URL for the parent folder that will contain the data source.
292 | - `overwrite`: default false, indicates whether an existing data source with the same name in the location specified should be overwritten.
293 | - `definition`: A `DataSourceDefinition` object that describes the connection properties for the data source.
294 | - `description`: report description
295 | - `isHidden`: hide report in ssrs
296 |
297 | #### Data Source Definition
298 | - `ConnectString`: 'data source=server\instance; initial catalog=databaseName'
299 | - `UseOriginalConnectString`: data source should revert to the original connection string
300 | - `OriginalConnectStringExpressionBased`: indicates whether the original connection string for the data source was expression-based.
301 | - `Extension`: SQL, OLEDB, ODBC, or a custom
302 | - `Enabled`: enable/disable datasource
303 | - `EnabledSpecified`: true if the `Enabled` property should be omitted from the Web service call; otherwise, false. The default is false.
304 | - `CredentialRetrieval`: Prompt, Store, Integrated, None
305 | - `WindowsCredentials`: indicates whether the report server passes user-provided or stored credentials as Windows credentials when it connects to a data source.
306 | - `ImpersonateUser`: indicates whether the report server tries to impersonate a user by using stored credentials.
307 | - `ImpersonateUserSpecified`: true if the `ImpersonateUser` property should be omitted from the Web service call; otherwise, false. The default is false.
308 | - `Prompt`: prompt that the report server displays to the user when it prompts for credentials.
309 | - `UserName`: auth
310 | - `Password`: auth
311 |
312 | ### Create report
313 |
314 | Mostly as above but `definition` property is a `ReportDefinition` object
315 | ```js
316 | var report = await reportService.createReport(reportName, folderPath, overwrite, definition, description, isHidden)
317 | - `reportName`: report name
318 | - `folderPath`: report folder destination
319 | - `overwrite`: overwrite if already exists
320 | - `definition`: report definition xml string (will be automaticaly converted to base64)
321 | - `description`: report description
322 | - `isHidden`: report manager property hidden
323 | ```
324 |
325 | ### Delete item
326 |
327 | ```js
328 | await reportService.deleteItem(path)
329 | ```
330 |
331 | ### Create resource
332 |
333 | Usually used for creating images
334 |
335 | ```js
336 | var resurce = await reportService.createResource(name, path, fileContents, overwrite, mimeType);
337 | ```
338 |
339 | ### Get item data sources
340 |
341 | ```js
342 | var references = await reportService.getItemDataSources(itemPath);
343 | ```
344 |
345 | ### Set item data sources
346 |
347 | ```js
348 | var dataSources = { dataSourceName: 'dataSourcesNewReferencePath' });
349 | var references = await reportService.setItemDataSources(itemPath, dataSources);
350 | ```
351 | - `itemPath`: path of the report including the file name
352 | - `dataSources`: object of dataSourceName: newValue type.
353 |
354 | ### Get item references
355 |
356 | ```js
357 | var references = await reportService.getItemReferences(itemPath, referenceType);
358 | ```
359 | - `itemPath`: path of the report including the file name
360 | - `referenceType`: 'DataSource'|'DataSet'...
361 |
362 | ### Set item references
363 |
364 | ```js
365 | var refs = { 'DataSourceName': '/path/DataSourceName' };
366 | var refs = [{ Name: 'DataSourceName': Reference: '/path/DataSourceName' }];
367 | var references = await reportService.setItemReferences(itemPath, refs);
368 | ```
369 | - `itemPath`: path of the report including the file name
370 | - `refs`: array of objects with name and reference paths
371 |
372 | ## Report Execution
373 |
374 | ### Get report execution client
375 |
376 | - list of all reporting execution [methods and options](https://docs.microsoft.com/en-us/dotnet/api/reportservice2005.reportingservice2005?view=sqlserver-2016)
377 | - not all methods where implemented
378 |
379 | ```js
380 | var { ReportExecution } = require('mssql-ssrs');
381 | var reportExecution = new ReportExecution();
382 |
383 | await reportExecution.start(url/Path/serverConfig, soapConfig [, options] [, security]);
384 | ```
385 |
386 | Using client soap directly
387 | ```js
388 | var client = reportExecution.getClient();
389 | or
390 | reportExecution.client['functionName']()
391 | ```
392 |
393 | ### Get client description
394 |
395 | ```js
396 | var description = reportExecution.getDescription()
397 | ```
398 |
399 | ### List available rendering extensions
400 |
401 | ```js
402 | var extensions = await reportExecution.listRenderingExtensions()
403 | ```
404 |
405 | ### Run report
406 |
407 | ```js
408 | var reportPath = '/Folder/ReportName';
409 | var fileType = 'pdf';
410 | var parameters = {
411 | parameterName1: 1,
412 | parameterName2: false,
413 | parameterName3: 'parameterValue',
414 | multiValue: ['value1', 'value2']
415 | };
416 | //or
417 | var parameters = [
418 | { Name: 'parameterName1', Value: 1 },
419 | { Name: 'parameterName2', Value: false },
420 | { Name: 'parameterName3', Value: 'parameterValue' },
421 | { Name: 'multiValue', Value: ['value1', 'value2'] }
422 | ]
423 | var report = await reportExecution.getReport(reportPath, fileType, parameters)
424 | ```
425 | - `parameters` can be an object with name, value atributes or instance of `ReportParameterInfo` objects
426 | **NOTE**: HTML render will automatically get associated image streams from the report server in base64 inside the html
427 |
428 | report result:
429 | ```js
430 | {
431 | "Extension": "pdf",
432 | "MimeType": "application/pdf",
433 | "Result:" "", // base64 string, this is the pdf
434 | "StreamIds": null
435 | }
436 | ```
437 |
438 | ## Report Execution via Url
439 |
440 | ### Run report (with url)
441 |
442 | No need to use `start` function (it does not exist)
443 |
444 | ```js
445 | var { ReportExecutionUrl } = require('mssql-ssrs');
446 |
447 | var auth = {
448 | username: 'userName',
449 | password: 'password',
450 | workstation: '', // optional
451 | domain: '' // optional
452 | };
453 | var re = new ReportExecutionUrl(url/path/serverConfig, auth[, options][, axiosConfig]);
454 |
455 | ```
456 | - `options`: optional
457 | - rootFolder: the folder to look into for reports
458 | - axiosConfig: [config for axios instance](https://www.npmjs.com/package/axios)
459 |
460 | ```js
461 | var report = await re.getReport(reportPath, fileType, parameters, axiosConfig)
462 | ```
463 | - `reportPath`: path to the report
464 | - `fileType`: the report file tipe of file extension
465 | - `parameters` can be an object with { name: value } properties or instance of `ReportParameterInfo` objects
466 | - `axiosConfig`: local axios config for overriding defaults per request
467 |
468 | returned result is an [axios response schema](https://www.npmjs.com/package/axios#response-schema)
469 | ```js
470 | {
471 | data: Buffer,
472 | status: ...,
473 | statusText: ...,
474 | headers: ...,
475 | config: ...,
476 | request: ...
477 | }
478 | ```
479 |
480 | ## Report Manager
481 |
482 | ```js
483 | var { ReportManager } = require('mssql-ssrs');
484 | var ssrs = new ReportManager();
485 |
486 | await ssrs.start(url/Path/serverConfig, soapConfig [, options] [, security]);
487 | ```
488 |
489 | ### Fix Data Source Reference
490 |
491 | ```js
492 | var references = await ssrs.fixDataSourceReference(reportPath, dataSourcePath[, logger]);
493 | ```
494 | - `reportPath`: path to reports
495 | - `dataSourcePath`: path to data source
496 |
497 | - `log`: boolean, outputs to console
498 | or
499 | - `log`: object
500 | - `log`: function for normal log messages
501 | - `warn`: function for log warrning/error messages
502 |
503 | ### Get report list
504 |
505 | Get report list from cache, if path is not found in cache it will be download and cached
506 |
507 | ```js
508 | var reportList = await ssrs.getReportList(reportPath [, forceRefresh])
509 | ```
510 |
511 | - if `reportPath` is not present of is the same as rootFolder for reports entire cache is returned
512 | - `forceRefresh` force a recache, if `reportPath` is not present `rootFolder` is used
513 |
514 | ### Cache report list
515 |
516 | ```js
517 | await ssrs.cacheReportList(reportPath[, keepHidden])
518 | ```
519 |
520 | ### Clear cached reports
521 |
522 | ```js
523 | await ssrs.clearCache()
524 | ```
525 |
526 | ### Create report builder link for specified report
527 |
528 | [Report Builder](https://docs.microsoft.com/en-us/sql/reporting-services/install-windows/install-report-builder) only installs from ie/edge
529 |
530 | ```js
531 | var link = await ssrs.reportBuilder(reportPath)
532 | ```
533 |
534 | ### Create a copy of a report
535 |
536 | Create a copy of a specified report in the same folder and return new report
537 |
538 | ```js
539 | var newReport = await ssrs.createReportCopy(reportPath, options)
540 | ```
541 |
542 | Inspired from [Report Loader](http://neilsleightholm.blogspot.ro/2008/08/report-loader-for-sql-server-reporting.html)
543 |
544 | ### Download reports
545 |
546 | Download list of all items down from specified path, can also be used for 1 specific report
547 |
548 | ```js
549 | var fileList = await ssrs.download(reportPath)
550 | ```
551 |
552 | - `reportPath`: string|Array of strings path for base folders in report service from where to create definitions.
553 |
554 | ### Read reports folder
555 |
556 | ```js
557 | var result = await ssrs.readFiles(filePath, exclude, noDefinitions);
558 | ```
559 | - `filePath`: path to folder to read
560 | - `exclude`: array of strings to exclude specified files paths, names or extensions
561 | - `noDefinitions`: does not read file content(definition)
562 |
563 | ### Upload reports
564 |
565 | Upload items (report/datasource/image) or entire folder structure to reporting services
566 |
567 | ```js
568 | var warrnings = await ssrs.upload(filePath, reportPath, options)
569 | ```
570 | - `filePath`: root folder path where to read files
571 | - `reportPath`: report path where to upload files
572 | - `options` for `upload` and `uploadFiles` are the same
573 |
574 | ### Upload reports files
575 |
576 | Read file directory and upload reports
577 |
578 | ```js
579 | var warrnings = await ssrs.uploadFiles(filePath [, reportPath] [, options]);
580 |
581 | var warrnings = await ssrs.uploadFiles('.path/to/root/directory', '/newReportFolderName', {
582 | overwrite: false,
583 | keepDataSource: true, // keep existing datasources
584 | deleteExistingItems: false,
585 | fixDataSourceReference: false,
586 | exclude: ['folderName', '.extension', '/path/to/file.rdl'],
587 | include: { folders: [], dataSources: [], reports: [] },
588 | dataSourceOptions: {
589 | myDataSourceName: {
590 | ConnectString: 'data source=\; initial catalog=',
591 | UserName: '',
592 | Password: ''
593 | },
594 | mySecondDataSourceName: {
595 | WindowsCredentials: true,
596 | ConnectString: 'data source=\; initial catalog=',
597 | UserName: '',
598 | Password: ''
599 | }
600 | },
601 | logger: true || {
602 | log: function (msg) { console.log(msg) },
603 | warn: function (msg) { console.warn(msg) }
604 | }
605 | }});
606 |
607 | ```
608 | - `filePath`: root folder from where to read files
609 | - `reportPath`: report path where to upload, if not specified last folder name from `filePath` is used
610 | - `options`: additional properties object, optional
611 | - `exclude`: array of strings to exclude specified files paths, names or extensions
612 | - `overwrite`: overrites reports and datasources on upload, default true
613 | - `deleteExistingItems`: delete items before upload, default false
614 | - `keepDataSource`: do not delete existing datasources, default false
615 | - `fixDataSourceReference`: fix uploaded reports datasource references with uploaded datasources, default true
616 | - `dataSourceOptions`: each dataSourceName and its connection properties
617 | - `dataSourceName`:
618 | - `connectstring`: connection string for data source
619 | - `userName`: userName for data source
620 | - `password`: password for data source
621 | - name, prompt, security, extension type is determined from the .rds and dataSourceOptions file
622 | - `logger`: boolean, outputs to console
623 | - `logger`: object
624 | - `log`: log messages function
625 | - `warn`: log warrning/error messages function
626 |
627 | ## soap
628 |
629 | ### Create client
630 |
631 | Creates [soap clients](https://github.com/vpulim/node-soap#soapcreateclienturl-options-callback---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path) (used for creating reportService and reportExecution client)
632 |
633 | ### Security
634 |
635 | types of [soap security](https://www.npmjs.com/package/soap#security)
636 |
637 | ```js
638 | const ssrs = require('mssql-ssrs')
639 | var customSecurity = await ssrs.soap.security.BasicAuthSecurity('username', 'password');
640 | var customSecurity = await ssrs.soap.security.NTLMSecurity('username', 'password', 'domain', 'workstation');
641 | var customSecurity = await ssrs.soap.security.NTLMSecurity({
642 | username: username,
643 | password: password,
644 | domain: domain,
645 | workstation: workstation
646 | });
647 | ```
648 |
649 | ```js
650 | const { soap, SsrsSoap } = require('mssql-ssrs')
651 |
652 | const ssrs = new SsrsSoap([url][, options])
653 | const client = await ssrs.createClient(url, config[, security])
654 | ```
655 | - `url`: url/serverConfig/path
656 | - `config`: { username:'', password:'', domain: '', workstation: '', ...otherOptions }
657 | - `security`: 'ntlm' | 'basic' | customSecurity
658 |
659 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const soap = require('soap');
2 | const SsrsSoap = require('./lib/soap');
3 | const ReportManager = require('./lib/report');
4 | const ReportService = require('./lib/reportService');
5 | const ReportExecution = require('./lib/reportExecution');
6 | const ReportExecutionUrl = require('./lib/reportExecutionUrl');
7 |
8 | module.exports = {
9 | soap, SsrsSoap,
10 | ReportManager, ReportService,
11 | ReportExecution, ReportExecutionUrl,
12 | };
--------------------------------------------------------------------------------
/lib/report.js:
--------------------------------------------------------------------------------
1 |
2 | const fs = require('fs');
3 | const dayjs = require('dayjs');
4 |
5 | const ReportService = require('./reportService');
6 | const ReportExecution = require('./reportExecution');
7 |
8 | module.exports = class ReportManager {
9 | constructor(cacheReports) {
10 | this.cache = {};
11 | this.isCacheable = cacheReports || false;
12 | this.reportService = new ReportService();
13 | this.reportExecution = new ReportExecution();
14 | }
15 |
16 | async start(urlOrServerConfig, clientConfig, options, security) {
17 | await this.reportService.start(urlOrServerConfig, clientConfig, options, security);
18 | await this.reportExecution.start(urlOrServerConfig, clientConfig, options, security);
19 | if (options) {
20 | if (options.cache) { this.isCacheable = options.cache }
21 | if (this.isCacheable && options.cacheOnStart) { await this.cacheReportList() }
22 | }
23 | }
24 |
25 | reportBuilder(reportPath) {
26 | const rs = this.reportService.soapInstance || this.reportExecution.soapInstance;
27 | return `${rs.getServerUrl()}/ReportBuilder/ReportBuilder_3_0_0_0.application?ReportPath=${reportPath || '/'}`
28 | }
29 |
30 | clearCache() {
31 | for (var key in this.cache) { delete this.cache[key] }
32 | }
33 |
34 | async getReportList(reportPath, forceRefresh) {
35 | if (this.isCacheable) {
36 | if (!(reportPath in this.cache) || forceRefresh) {
37 | await this.cacheReportList(reportPath)
38 | }
39 | return this.cache[reportPath]
40 | } else {
41 | return await this.reportService.listChildren(reportPath)
42 | }
43 | }
44 |
45 | async cacheReportList(reportPath, keepHidden) {
46 | reportPath = (reportPath || (this.reportService.soapInstance || this.reportExecution.soapInstance).getRootFolder());
47 | const reports = await this.reportService.listChildren(reportPath, true);
48 | if (!reports.length) { return }
49 | this.cache[reportPath] = [];
50 |
51 | for (var i = 0; i < reports.length; i++) {
52 | if (reports[i].TypeName === "DataSource") { continue; }
53 | if (reports[i].TypeName === "Folder") {
54 | reportPath = reports[i].Path.substr(reports[i].Path.lastIndexOf("/"));
55 | this.cache[reportPath] = [];
56 | } else if (reports[i].TypeName === "ReportItem" || reports[i].TypeName === "Report") {
57 | if (keepHidden) {
58 | this.cache[reportPath].push(reports[i]);
59 | } else {
60 | // eliminate hidden reports
61 | var properties = await this.reportService.getProperties(reports[i].Path, [{ Name: 'Hidden' }])
62 | if (properties && properties[0].Value === "False") {
63 | this.cache[reportPath].push(reports[i]);
64 | }
65 | }
66 | }
67 | }
68 | }
69 |
70 | async createReportCopy(reportPath, options) {
71 | var reportName = reportPath.substr(reportPath.lastIndexOf("/") + 1);
72 | const reportFolder = reportPath.substr(0, reportPath.lastIndexOf("/"));
73 |
74 | if (reportName.indexOf("_custom_") != -1) {
75 | reportName = reportName.substring(0, reportName.lastIndexOf("_") + 1) + dayjs().format("DDMMYYTHHmm")
76 | } else {
77 | reportName = reportName + "_custom_" + dayjs().format("DDMMYYTHHmm")
78 | }
79 |
80 | const definition = await this.reportService.getItemDefinition(reportPath);
81 | const newReport = await this.reportService.createReport(
82 | options.name || reportName,
83 | options.parent || reportFolder,
84 | options.overwrite || false,
85 | definition,
86 | options.description,
87 | options.hidden
88 | );
89 |
90 | if (isCacheable) {
91 | this.clearCache();
92 | this.cacheReportList();
93 | }
94 |
95 | return newReport;
96 | }
97 |
98 | async download(reportPath) {
99 | if (!Array.isArray(reportPath)) reportPath = [reportPath];
100 | var files = { folders: [], dataSources: [], reports: [], others: [] };
101 | while (reportPath.length) {
102 | const result = await this.reportService.listChildren(reportPath.shift(), true);
103 | for (var i = 0; i < result.length; i++) {
104 | var file = { name: result[i].Name, path: result[i].Path };
105 | if (result[i].TypeName !== 'Folder') {
106 | file.definition = await this.reportService.getItemDefinition(result[i].Path)
107 | }
108 | var placement = 'others';
109 | if (result[i].TypeName === 'Folder') { placement = 'folders' }
110 | else if (result[i].TypeName === 'Report') { placement = 'reports' }
111 | else if (result[i].TypeName === 'DataSource') { placement = 'dataSources' }
112 | files[placement].push(file);
113 | }
114 | }
115 | return files;
116 | }
117 |
118 | async readFiles(filePath, exclude, noDefinitions) {
119 | const init = { folders: [], reports: [], dataSources: [], other: [] };
120 | return this.read(filePath, '', init, exclude || [], noDefinitions);
121 | }
122 |
123 | read(root, relativePath, files, exclude, noDefinitions) {
124 | var dir = fs.readdirSync(root + relativePath);
125 | for (var i = 0; i < dir.length; i++) {
126 | var path = relativePath + '/' + dir[i];
127 | if (exclude.indexOf(dir[i]) > -1) { continue }
128 | if (fs.statSync(root + path).isDirectory()) {
129 | if (exclude.indexOf(path) > -1) { continue; }
130 | files.folders.push({ name: dir[i], path: path });
131 | this.read(root, path, files, exclude, noDefinitions);
132 | } else {
133 | var idx = dir[i].lastIndexOf('.');
134 | var ext = dir[i].substring(idx);
135 | if (exclude.indexOf(ext) > -1) { continue }
136 | var options = { name: dir[i].substring(0, idx), path: path };
137 |
138 | if (!noDefinitions) {
139 | var content = fs.readFileSync(root + path).toString();
140 | options.definition = content;
141 | } else {
142 | options.filePath = root;
143 | }
144 |
145 | var placement = 'other';
146 | if (ext === '.rds') { placement = 'dataSources' }
147 | else if (ext === '.rdl') { placement = 'reports' }
148 | files[placement].push(options);
149 | }
150 | }
151 | return files;
152 | }
153 |
154 | async uploadFiles(filePath, reportPath, options) {
155 | var files = await this.readFiles(filePath, options && options.exclude);
156 | if (options) {
157 | var inc = options.include || {};
158 | if (Array.isArray(inc.folders)) { files.folders = files.folders.concat(inc.folders) }
159 | if (Array.isArray(inc.dataSources)) { files.dataSources = files.dataSources.concat(inc.dataSources) }
160 | if (Array.isArray(inc.reports)) { files.reports = files.reports.concat(inc.reports) }
161 | delete options.include;
162 | }
163 | return await this.upload(reportPath, files, options);
164 | }
165 |
166 | async upload(reportPath, files, options) {
167 | var warrnings = [], options = options || {};
168 |
169 | function logger(msg, type) {
170 | if (!options.logger) return;
171 | if (options.logger === true) console[type](msg);
172 | else if (options.logger[type]) options.logger[type](msg);
173 | }
174 | function log(msg, type) { logger(msg, 'log') }
175 | log.warn = function warn(msg) { logger(msg, 'warn') }
176 |
177 | try {
178 | log('Check report folder...');
179 | await this.reportService.listChildren(reportPath);
180 | } catch (error) {
181 | try {
182 | log("Create root folder '" + reportPath + "'.");
183 | var parts = reportPath.split('/');
184 | var result = await this.reportService.createFolder(parts.pop(), '/' + parts.join('/'));
185 | } catch (error) {
186 | log.warn(error.message);
187 | warrnings.push(error);
188 | }
189 | }
190 |
191 | if (options.deleteExistingItems) {
192 | log('Delete existing items' + (options.keepDataSource ? ', keep DataSources' : '') + ' ...');
193 | var items = await this.reportService.listChildren(reportPath, true);
194 | items = items || [];
195 |
196 | for (var i = 0; i < items.length; i++) {
197 | try {
198 | if (options.keepDataSource && items[i].TypeName == 'DataSource') { continue }
199 | await this.reportService.deleteItem(items[i].Path);
200 | } catch (error) {
201 | log.warn(error.message);
202 | warrnings.push(error);
203 | }
204 | }
205 | }
206 |
207 | reportPath = /^\//.test(reportPath) ? reportPath.substr(1) : reportPath;
208 | var count = 0;
209 | var total = 1
210 | + (files.folders && files.folders.length || 0)
211 | + (files.dataSources && files.dataSources.length || 0)
212 | + (files.reports && files.reports.length || 0);
213 |
214 | if (files.folders && files.folders.length > 0) {
215 | for (var i = 0; i < files.folders.length; i++) {
216 | try {
217 | var path = this.newPath(files.folders[i].path, reportPath, true);
218 | log(`[${(++count)}/${total}] Create folder: ${path}/${files.folders[i].name}`);
219 | await this.reportService.createFolder(files.folders[i].name, path);
220 | } catch (error) {
221 | log.warn(error.message);
222 | warrnings.push(error);
223 | }
224 | }
225 | }
226 |
227 | if (files.dataSources && files.dataSources.length > 0) {
228 | for (var i = 0; i < files.dataSources.length; i++) {
229 | try {
230 | if (!files.dataSources[i].definition) {
231 | files.dataSources[i].definition = fs.readFileSync(files.reports[i].filePath + files.reports[i].path).toString();
232 | }
233 | var path = this.newPath(files.dataSources[i].path, reportPath, true);
234 | log(`[${(++count)}/${total}] Create datasource: ${path}/${files.dataSources[i].name}`);
235 | await this.createDataSource(path,
236 | files.dataSources[i].overwrite || options.overwrite,
237 | options.dataSourceOptions && options.dataSourceOptions[files.dataSources[i].name] || {},
238 | files.dataSources[i].definition,
239 | files.dataSources[i].name);
240 | } catch (error) {
241 | log.warn(error.message);
242 | warrnings.push(error);
243 | }
244 | }
245 | } else if (options.dataSourceOptions) {
246 | for (var key in options.dataSourceOptions) {
247 | log(`Create additional datasource: /${reportPath}/${key}`);
248 | await this.reportService.createDataSource(key, '/' + reportPath, true, options.dataSourceOptions[key]);
249 | }
250 | }
251 |
252 | if (files.reports && files.reports.length > 0) {
253 | for (var i = 0; i < files.reports.length; i++) {
254 | try {
255 | if (!files.reports[i].definition) {
256 | files.reports[i].definition = fs.readFileSync(files.reports[i].filePath + files.reports[i].path).toString();
257 | }
258 | var path = this.newPath(files.reports[i].path, reportPath, true);
259 | log(`[${(++count)}/${total}] Create report: ${path}/${files.reports[i].name}`);
260 | await this.reportService.createReport(files.reports[i].name, path,
261 | files.reports[i].overwrite || options.overwrite,
262 | files.reports[i].definition);
263 | } catch (error) {
264 | log.warn(error.message);
265 | warrnings.push(error);
266 | }
267 | }
268 | }
269 |
270 | // If shared datasources where created => fix references if necessary
271 | if (options.fixDataSourceReference && (files.dataSources.length > 0 || options.dataSourceOptions)) {
272 | var references = {};
273 | log('Set datasource references...');
274 | if (files.dataSources.length > 0) {
275 | for (var i = 0; i < files.dataSources.length; i++) {
276 | var path = this.newPath(files.dataSources[i].path, reportPath).replace(/\.rds$/i, '');
277 | var name = files.dataSources[i].name || path.substr(path.lastIndexOf('/') + 1).replace(/\.rds$/i, '');
278 | references[name] = path;
279 | }
280 | }
281 | if (options.dataSourceOptions) {
282 | for (var key in options.dataSourceOptions) {
283 | var path = this.newPath(options.dataSources[key].path, reportPath).replace(/\.rds$/i, '');
284 | references[key] = path;
285 | }
286 | }
287 | var warn = await this.setReferences(files.reports, references, '/' + reportPath, log);
288 | warrnings.concat(warn);
289 | }
290 |
291 | return warrnings;
292 | }
293 |
294 | newPath(path, newPath, removeName) {
295 | var parts = path.split('/');
296 | if (parts[0] === "" || parts[0] === '.') { parts.shift() }
297 | if (!parts.length) { return '/' + (newPath || '') }
298 | if (newPath) { parts.unshift(newPath) }
299 | if (removeName) { parts.pop(); }
300 | return '/' + parts.join('/');
301 | }
302 |
303 | async createDataSource(path, overwrite, auth, rdsFile, rdsName) {
304 | var name = rdsFile.Name || this.getAttribute('Name', rdsFile) || rdsName;
305 | var extension = rdsFile.Extension || this.extractBetween('Extension', rdsFile);
306 | if (!auth.ConnectString) {
307 | auth.ConnectString = this.extractBetween('ConnectString', rdsFile);
308 | }
309 | var security = !!(rdsFile.IntegratedSecurity || this.extractBetween('IntegratedSecurity', rdsFile));
310 | var prompt = rdsFile.Prompt || this.extractBetween('Prompt', rdsFile);
311 | var promptSpecified = !!prompt;
312 |
313 | var dataSourceDefinition = {
314 | ConnectString: auth.ConnectString || rdsFile.ConnectString,
315 | Extension: extension,
316 | Enabled: true,
317 | EnabledSpecified: true,
318 | ImpersonateUserSpecified: rdsFile.ImpersonateUserSpecified || false,
319 | };
320 | if (auth.WindowsCredentials || rdsFile.WindowsCredentials) {
321 | dataSourceDefinition.WindowsCredentials = true;
322 | }
323 | // Override security if supplied username
324 | if (rdsFile.UserName || auth.UserName) {
325 | dataSourceDefinition.CredentialRetrieval = 'Store';
326 | dataSourceDefinition.UserName = auth.UserName || rdsFile.UserName;
327 | dataSourceDefinition.Password = auth.Password || rdsFile.Password;
328 | } else {
329 | if (promptSpecified) {
330 | dataSourceDefinition.CredentialRetrieval = 'Prompt';
331 | dataSourceDefinition.Prompt = prompt;
332 | } else {
333 | dataSourceDefinition.CredentialRetrieval = 'Integrated';
334 | dataSourceDefinition.Prompt = null;
335 | }
336 | }
337 |
338 | await this.reportService.createDataSource(name, path, overwrite, dataSourceDefinition);
339 | }
340 |
341 | async fixDataSourceReference(reportPath, dataSourcePath, logger) {
342 | var items = await this.reportService.listChildren(reportPath, true);
343 | var reports = items.filter(r => r.TypeName === 'Report');
344 |
345 | var dataSources;
346 | if (dataSourcePath && dataSourcePath != reportPath) {
347 | dataSources = await this.reportService.listChildren(dataSourcePath, true);
348 | } else {
349 | dataSources = items.filter(r => r.TypeName === 'DataSource')
350 | }
351 |
352 | function doLog(msg, type) {
353 | if (logger === true) console[type](msg);
354 | else if (logger && logger[type]) logger[type](msg);
355 | }
356 | function log(msg) { doLog(msg, 'log') }
357 | log.warn = function warn(msg) { doLog(msg, 'warn') }
358 |
359 | if (!dataSources.length) {
360 | log.warn('No dataSources found!');
361 | return [];
362 | }
363 |
364 | var ds = {};
365 | dataSources.forEach(r => { ds[r.Name] = r.Path });
366 |
367 | var result = await this.setReferences(reports, ds, '', log);
368 | return result;
369 | }
370 |
371 | async setReferences(reports, dataSources, reportPath, log) {
372 | var warrnings = [], path;
373 | for (var i = 0; i < reports.length; i++) {
374 | try {
375 | path = reportPath + (reports[i].Path || reports[i].path).replace(/\.rdl$/i, '');
376 | log && log("[" + (i + 1) + "/" + (reports.length + 1) + "] Set '" + path + "' datasource references.");
377 | var result = await this.setDataSourceReference(path, dataSources);
378 | if (result) log(result)
379 | } catch (error) {
380 | log && log.warn(error.message);
381 | warrnings.push(error);
382 | }
383 | }
384 | return warrnings;
385 | }
386 |
387 | async setDataSourceReference(path, rds) {
388 | var dataSources = await this.reportService.getItemReferences(path, 'DataSource');
389 | if (dataSources.length) {
390 | var refs = [];
391 | for (var i = 0; i < dataSources.length; i++)
392 | if (dataSources[i].Name in rds)
393 | refs.push({ Name: dataSources[i].Name, Reference: rds[dataSources[i].Name].replace(/\.rds$/i, '') });
394 | if (refs.length) {
395 | await this.reportService.setItemReferences(path, refs);
396 | } else {
397 | return 'No compatible datasources found for ' + path;
398 | }
399 | }
400 | }
401 |
402 | async setDataSource(path, rds) {
403 | var dataSources = await this.reportService.getItemReferences(path, 'DataSource');
404 | // If datasources are found
405 | if (dataSources.length) {
406 | var refs = [];
407 | for (var i = 0; i < dataSources.length; i++)
408 | if (dataSources[i].Name in rds) {
409 | const dsRef = { Reference: rds[dataSources[i].Name].replace(/\.rds$/i, '') };
410 | refs.push({ Name: dataSources[i].Name, DataSourceReference: dsRef });
411 | }
412 | if (refs.length) {
413 | await this.reportService.setItemDataSources(path, refs)
414 | }
415 | }
416 | }
417 |
418 | extractBetween(tag, str) {
419 | var match = new RegExp('<' + tag + '>(.*?)<\/' + tag + '>').exec(str);
420 | return match && match[1];
421 | }
422 | getAttribute(attr, str) {
423 | var match = new RegExp(attr + '="([^"]*)"').exec(str);
424 | return match && match[1];
425 | }
426 | }
--------------------------------------------------------------------------------
/lib/reportExecution.js:
--------------------------------------------------------------------------------
1 | const dayjs = require('dayjs');
2 | const utils = require('./utils');
3 |
4 | module.exports = class ReportExecution {
5 | constructor() { }
6 |
7 | getClient() { return this.client }
8 | getDescription() { return this.client.describe() }
9 |
10 | async start(url, clientConfig, options, security) {
11 | try {
12 | this.soapInstance = utils.createSoapInstance(null, options);
13 | if (/^https?:/.test(url)) { url = url + '/ReportExecution2005.asmx' }
14 | this.client = await this.soapInstance.createClient(url, clientConfig, security);
15 | return this.client;
16 | } catch (err) { utils.errorHandler(err) }
17 | }
18 |
19 | async listRenderingExtensions() {
20 | try {
21 | const result = await this.client.ListRenderingExtensionsAsync();
22 | return result[0].Extensions.Extension;
23 | } catch (err) { utils.errorHandler(err) }
24 | }
25 |
26 | async #getImageForHtmlRendering(report) {
27 | const { Result: renderedReport, StreamIds } = report[0];
28 |
29 | // Retrieve and encode images in Base64
30 | const imagesBase64 = {};
31 | for (const streamId of StreamIds.string) {
32 | const imageData = await this.client.RenderStreamAsync({
33 | Format: 'HTML5',
34 | StreamID: streamId,
35 | DeviceInfo: 'true'
36 | });
37 | const base64Image = imageData[0].Result.toString('base64');
38 | imagesBase64[streamId] = `data:image/png;base64,${base64Image}`;
39 | }
40 |
41 | // Convert from base64 to html
42 | let html = Buffer.from(renderedReport, 'base64').toString('utf8');
43 |
44 | // Replace image references in the HTML with Base64 data
45 | for (const [streamId, base64Image] of Object.entries(imagesBase64)) {
46 | const regex = new RegExp(`src="[^"]*ImageID=${streamId}"`, 'g');
47 | html = html.replace(regex, `src="${base64Image}"`);
48 | }
49 |
50 | report[0].Result = Buffer.from(html, 'utf8');
51 |
52 | return report;
53 | }
54 |
55 | async getReport(reportPath, fileType, params) {
56 | try {
57 | reportPath = utils.testReportPath(this.soapInstance.getRootFolder(), reportPath);
58 | fileType = utils.reportFileFormat(fileType);
59 |
60 | // Loads a report from the report server into a new execution.
61 | const execInfo = await this.client.LoadReportAsync({ Report: reportPath });
62 |
63 | // clear last headers and include executionId as soap header otherwise request fails
64 | // make shure somehow, header does not change from another request
65 | // would be nice to have headers for 1 specific request not global
66 | const executionHeader = { ExecutionHeader: { ExecutionID: execInfo[0].executionInfo.ExecutionID } };
67 | const xmlns = 'http://schemas.microsoft.com/sqlserver/2005/06/30/reporting/reportingservices';
68 |
69 | this.client.clearSoapHeaders();
70 | const index = this.client.addSoapHeader(executionHeader, '', 'h', xmlns);
71 | const header = this.client.getSoapHeaders()[index]; // keep for later
72 | // Sets and validates parameter values associated with the current report execution.
73 | await this.client.SetExecutionParametersAsync({
74 | Parameters: { ParameterValue: this.formatParameters(params) },
75 | ExecutionDateTime: new Date() // set start of ExecutionTime
76 | });
77 |
78 | this.client.clearSoapHeaders();
79 | this.client.addSoapHeader(header); // skip processing header again
80 | // Process and render loaded report in the specified format.
81 | let result = await this.client.RenderAsync({ Format: fileType });
82 |
83 | if(fileType === 'HTML5') {
84 | result = await this.#getImageForHtmlRendering(result);
85 | }
86 |
87 | this.client.clearSoapHeaders();
88 |
89 | return result;
90 | } catch (err) {
91 | this.client.clearSoapHeaders();
92 | utils.errorHandler(err);
93 | }
94 | }
95 |
96 | /**
97 | * parameters must be formated like => [{ Name: name, Value: value }]
98 | *
99 | * for params with multivalue
100 | * [{ Name: sameName, Value: [] }] =>
101 | *
102 | * [{ Name: sameName, Value: value1 }, { Name: sameName, Value: value2 }]
103 | *
104 | * name value is case sensitive
105 | */
106 | formatParameters(params) {
107 | return Array.isArray(params) ? this.arrayToReport(params) : this.objectToReport(params)
108 | }
109 |
110 | /**
111 | * [{ Name: nume, Value: valoare }]
112 | */
113 | arrayToReport(params, checkNulls) {
114 | const formated = [];
115 | for (var i = 0; i < params.length; i++) {
116 | if (params[i].ParameterTypeName === "DateTime" || params[i].Value instanceof Date) {
117 | formated.push({
118 | Name: params[i].Name,
119 | Value: dayjs(params[i].Value).format("MM/DD/YYYY")
120 | })
121 | } else if ((params[i].AllowBlank === true || params[i].Nullable === true) && (!params[i].Value || params[i].Value === undefined)) {
122 | formated.push({
123 | Name: params[i].Name,
124 | Value: undefined
125 | })
126 | } else if (checkNulls && (!params[i].AllowBlank || !params[i].Nullable) && (!params[i].Value || params[i].Value === undefined)) {
127 | throw `Parameter ${params[i].Name} cannot be undefined!`
128 | } else if (Array.isArray(params[i].Value)) {
129 | if (!params[i].Value.length)
130 | formated.push({ Name: params[i].Name, Value: null })
131 | if (params[i].Value.length === 1 && params[i].Value[0] === "all validValues") {
132 | for (var j = 0; j < params[i].ValidValues.ValidValue.length; j++) {
133 | formated.push({
134 | Name: params[i].Name,
135 | Value: params[i].ValidValues.ValidValue[j].Value
136 | })
137 | }
138 | } else {
139 | for (var j = 0; j < params[i].Value.length; j++) {
140 | formated.push({
141 | Name: params[i].Name,
142 | Value: params[i].Value[j]
143 | })
144 | }
145 | }
146 | } else {
147 | formated.push({ Name: params[i].Name, Value: params[i].Value })
148 | }
149 | }
150 | return formated;
151 | }
152 |
153 | /**
154 | * object params { [name]: value }
155 | *
156 | * for multivalue { [name]: [value1, value2] } =>
157 | *
158 | * return [{ Name: sameField, Value: value1 }, { Name: sameField, Value: value2 }]
159 | */
160 | objectToReport(params) {
161 | const formated = [];
162 | for (var key in params) {
163 | if (params[key] instanceof Date && !isNaN(params[key].valueOf())) {
164 | formated.push({ Name: key, Value: dayjs(params[key]).format("MM/DD/YYYY") })
165 | } else if (Array.isArray(params[key])) {
166 | if (!params[key].length) {
167 | formated.push({ Name: params[key], Value: undefined })
168 | } else {
169 | for (var i = 0; i < params[key].length; i++) {
170 | formated.push({ Name: key, Value: params[key][i] })
171 | }
172 | }
173 | } else {
174 | formated.push({ Name: key, Value: params[key] === null ? undefined : params[key] })
175 | }
176 | }
177 | return formated;
178 | }
179 | }
--------------------------------------------------------------------------------
/lib/reportExecutionUrl.js:
--------------------------------------------------------------------------------
1 | const dayjs = require('dayjs');
2 | const { NtlmClient } = require('axios-ntlm');
3 |
4 | const utils = require('./utils');
5 |
6 | module.exports = class ReportExecutionUrl {
7 | constructor(url, auth, options, axiosConfig) {
8 | this.soapInstance = utils.createSoapInstance(url, options);
9 | this.axiosCfg = axiosConfig;
10 | this.auth = auth;
11 | }
12 |
13 | async getReport(reportPath, fileType, params, axiosConfig) {
14 | if (!this.client) {
15 | const credentials = this.soapInstance.createAuthObj(this.auth);
16 | const defaults = { method: 'get', responseType: 'arraybuffer' };
17 | this.client = NtlmClient(credentials, Object.assign(defaults, this.axiosCfg, axiosConfig));
18 | }
19 | const urlPath = utils.testReportPath(this.soapInstance.getRootFolder(), reportPath).replace(/\s/g, '+');
20 | const urlParams = `&rs:Command=Render&rs:Format=${utils.reportFileFormat(fileType)}${formatParamsToUrl(params)}`;
21 | return await this.client(`${this.soapInstance.getServerUrl()}?${encodeURIComponent(urlPath)}${urlParams}`);
22 | }
23 | }
24 |
25 | /**
26 | * param1=value1¶m2=value2¶m3=value3
27 | *
28 | * for multiple params {sameName: [...]}
29 | *
30 | * sameName=value1%2Cvalue2
31 | */
32 | function formatParamsToUrl(params) {
33 | const urlParts = [];
34 | if (Array.isArray(params)) { // [{Name: nume, Value: valoare}]
35 | for (var i = 0; i < params.length; i++) {
36 | const value = params[i];
37 | if (value.ParameterTypeName === "DateTime") {
38 | urlParts.push(value.Name + "=" + dayjs(value.Value).format("MM.DD.YYYY"))
39 | } else if (Array.isArray(value.Value)) {
40 | // result paramName=paramValue1%2CparamValue2%2CparamValue3
41 | const parts = [];
42 | for (var j = 0; j < value.Value.length; j++) {
43 | parts.push(encodeURIComponent(value.Value[j].Value))
44 | }
45 | urlParts.push(`${value.Name}=${parts.join('%2C')}`)
46 | } else {
47 | urlParts.push(`${value.Name}=${encodeURIComponent(value.Value)}`)
48 | }
49 | }
50 | } else { // { name: value }
51 | for (var key in params) {
52 | const value = params[key];
53 | if (value instanceof Date && !isNaN(value.valueOf())) {
54 | urlParts.push(key + "=" + dayjs(value).format("MM/DD/YYYY"))
55 | } else if (Array.isArray(value)) {
56 | // result paramName=paramValue1%2CparamValue2%2CparamValue3
57 | const parts = [];
58 | for (var j = 0; j < value.length; j++) {
59 | parts.push(encodeURIComponent(value[j]))
60 | }
61 | urlParts.push(value + "=" + parts.join('%2C'))
62 | } else if (typeof value === 'boolean') {
63 | urlParts.push(key + "=" + (value ? 'True' : 'False'))
64 | } else {
65 | urlParts.push(key + (value === null || value === undefined ? ':IsNull=True' : "=" + encodeURIComponent(value)))
66 | }
67 | }
68 | }
69 | return urlParts.length > 0 ? '&' + urlParts.join('&') : ''
70 | }
--------------------------------------------------------------------------------
/lib/reportService.js:
--------------------------------------------------------------------------------
1 | const utils = require('./utils');
2 | const ReportExecution = require('./reportExecution');
3 |
4 | module.exports = class ReportService {
5 | constructor() { }
6 |
7 | getClient() { return this.client }
8 | getDescription() { return this.client.describe() }
9 |
10 | async start(url, clientConfig, options, security) {
11 | try {
12 | this.soapInstance = await utils.createSoapInstance(null, options);
13 | if (/^https?:/.test(url)) {
14 | url = url + `/ReportService201${options && options.useRs2012 ? '2' : '0'}.asmx`
15 | }
16 | this.client = await this.soapInstance.createClient(url, clientConfig, security);
17 | return this.client;
18 | } catch (err) { utils.errorHandler(err) }
19 | }
20 |
21 | async listChildren(reportPath, isRecursive) {
22 | try {
23 | const reports = await this.client.ListChildrenAsync({
24 | ItemPath: reportPath,
25 | Recursive: isRecursive
26 | });
27 | return reports[0].CatalogItems && reports[0].CatalogItems.CatalogItem;
28 | } catch (err) { utils.errorHandler(err) }
29 | }
30 |
31 | async getReportParams(reportPath, forRendering) {
32 | try {
33 | const result = await this.client.GetItemParametersAsync({
34 | ItemPath: reportPath,
35 | ForRendering: forRendering || false
36 | });
37 | return result[0].Parameters && result[0].Parameters.ItemParameter;
38 | } catch (err) { utils.errorHandler(err) }
39 | }
40 |
41 | async updateReportParams(reportPath, params, formatParams) {
42 | try {
43 | if (formatParams) { params = (new ReportExecution()).formatParameters(params) }
44 | const result = await this.client.GetItemParametersAsync({
45 | ItemPath: reportPath, ForRendering: true,
46 | Values: { ParameterValue: params },
47 | });
48 | return result[0].Parameters && result[0].Parameters.ItemParameter;
49 | } catch (err) { utils.errorHandler(err) }
50 | }
51 |
52 | // all DataSourceDefinition properties
53 | // https://msdn.microsoft.com/en-us/library/reportservice2010.datasourcedefinition%28v=sql.120%29.aspx
54 | async testDataSourceConnection(userName, password, dataSourceDefinition) {
55 | try {
56 | const result = await this.client.TestConnectForDataSourceDefinitionAsync({
57 | DataSourceDefinition: dataSourceDefinition,
58 | UserName: userName,
59 | Password: password,
60 | });
61 | // throw error on ConnectError ????
62 | if (result[0].TestConnectForDataSourceDefinitionResult) {
63 | return result[0].TestConnectForDataSourceDefinitionResult
64 | }
65 | return result[0].ConnectError
66 | } catch (err) { utils.errorHandler(err) }
67 | }
68 |
69 | async getProperties(reportPath, properties) {
70 | try {
71 | let props = [];
72 | if (properties) {
73 | if (typeof properties[0] === 'string') {
74 | for (var i = 0; i < properties.length; i++) { props.push({ Name: properties[i] }) }
75 | // props = properties.map(function (p) { return { Name: p } });
76 | } else { props = properties }
77 | }
78 |
79 | // properties = [{ Name: 'Hidden' }, { Name: 'Description' }]
80 | const args = { ItemPath: reportPath };
81 | if (props.length) { args.Properties = { Property: props } }
82 | const result = await this.client.GetPropertiesAsync(args);
83 | return result[0].Values.Property;
84 | } catch (err) { utils.errorHandler(err) }
85 | }
86 |
87 | async setProperties(reportPath, properties) {
88 | try {
89 | let props = [];
90 | if (!Array.isArray(properties)) {
91 | for (var key in properties)
92 | props.push({ Name: key, Value: properties[key] })
93 | } else { props = properties }
94 |
95 | // properties = [{ Name: 'Hidden', Value: true }, { Name: 'Description', Value: true }]
96 | const result = this.client.SetPropertiesAsync({
97 | ItemPath: reportPath,
98 | Properties: { Property: props }
99 | });
100 | return result[0]
101 | } catch (err) { utils.errorHandler(err) }
102 | }
103 |
104 | async listJobs() {
105 | try {
106 | const jobs = await client.ListJobsAsync();
107 | return jobs[0].Jobs;
108 | } catch (err) { utils.errorHandler(err) }
109 | }
110 |
111 | async cancelJob(jobId) {
112 | if (!jobId) { throw new Error("Job id required!") }
113 | try {
114 | const result = await this.client.CancelJobAsync({ JobId: jobId });
115 | return result[0].Jobs;
116 | } catch (err) { utils.errorHandler(err) }
117 | }
118 |
119 | async getItemDefinition(reportPath) {
120 | try {
121 | const rdl = await this.client.GetItemDefinitionAsync({ ItemPath: reportPath });
122 | return Buffer.from(rdl[0].Definition, 'base64').toString().replace(/\0/g, '');
123 | } catch (error) { utils.errorHandler(error) }
124 | }
125 |
126 | async deleteItem(path) {
127 | try {
128 | const result = await this.client.DeleteItemAsync({ ItemPath: path });
129 | return result[0]
130 | } catch (error) { utils.errorHandler(error) }
131 | }
132 |
133 | async createFolder(folderName, path) {
134 | try {
135 | const result = await this.client.CreateFolderAsync({ Folder: folderName, Parent: path });
136 | return result[0];
137 | } catch (error) { utils.errorHandler(error) }
138 | }
139 |
140 | async createDataSource(dataSourceName, folder, overwrite, definition, description, isHidden) {
141 | try {
142 | const result = await this.client.CreateDataSourceAsync({
143 | Parent: folder, // The fully qualified URL for the parent folder that will contain the data source.
144 | DataSource: dataSourceName, // The name for the data source including the file name and, in SharePoint mode, the extension (.rsds).
145 | Overwrite: overwrite || false, // indicates whether an existing data source with the same name in the location specified should be overwritten.
146 | Definition: definition, // A DataSourceDefinition object that describes the connection properties for the data source.
147 | Properties: { // An array of Property objects that defines the property names and values to set for the data source.
148 | Property: [
149 | { Name: 'Description', Value: description },
150 | { Name: 'Hidden', Value: isHidden || false }
151 | ]
152 | },
153 | })
154 | return result[0].ItemInfo;
155 | } catch (error) { utils.errorHandler(error) }
156 | }
157 |
158 | async createReport(reportName, folder, overwrite, definition, description, isHidden) {
159 | try {
160 | const newReport = await this.client.CreateCatalogItemAsync({
161 | ItemType: 'Report',
162 | Parent: folder,
163 | Name: reportName,
164 | Overwrite: overwrite || false,
165 | Definition: Buffer.from(definition).toString('base64'),
166 | Properties: {
167 | Property: [
168 | { Name: 'Description', Value: description },
169 | { Name: 'Hidden', Value: isHidden || false }
170 | ]
171 | }
172 | });
173 | return newReport[0].ItemInfo;
174 | } catch (error) { utils.errorHandler(error) }
175 | }
176 |
177 | async createResource(name, path, fileContents, overwrite, mimeType) {
178 | try {
179 | const resource = await this.client.CreateCatalogItemAsync({
180 | ItemType: 'Resource',
181 | Parent: path,
182 | Name: name,
183 | Overwrite: overwrite,
184 | Definition: fileContents,
185 | Properties: {
186 | Property: [{ Name: 'MimeType', Value: mimeType }]
187 | }
188 | });
189 | return resource[0].ItemInfo;
190 | } catch (error) { utils.errorHandler(error) }
191 | }
192 |
193 | async setItemDataSources(itemPath, dataSources) {
194 | try {
195 | const ds = [];
196 | if (Array.isArray(dataSources)) {
197 | ds.push(...dataSources);
198 | } else {
199 | for (var key in dataSources)
200 | ds.push({ Name: key, DataSourceReference: { Reference: dataSources[key] } });
201 | }
202 | const result = await this.client.SetItemDataSourcesAsync({
203 | ItemPath: itemPath,
204 | DataSources: { DataSource: ds }
205 | });
206 | return result[0];
207 | } catch (error) { utils.errorHandler(error) }
208 | }
209 |
210 | async getItemDataSources(itemPath) {
211 | try {
212 | const result = await this.client.GetItemDataSourcesAsync({ ItemPath: itemPath });
213 | return result[0].DataSources.DataSource;
214 | } catch (error) { utils.errorHandler(error) }
215 | }
216 |
217 | async getItemReferences(itemPath, referenceItemType) {
218 | try {
219 | const result = await this.client.GetItemReferencesAsync({
220 | ItemPath: itemPath,
221 | ReferenceItemType: referenceItemType
222 | });
223 | return result[0].ItemReferences && result[0].ItemReferences.ItemReferenceData || [];
224 | } catch (error) { utils.errorHandler(error) }
225 | }
226 |
227 | async setItemReferences(itemPath, itemReferences) {
228 | try {
229 | const result = await this.client.SetItemReferencesAsync({
230 | ItemPath: itemPath,
231 | ItemReferences: { ItemReference: itemReferences }
232 | });
233 | return result[0];
234 | } catch (error) { utils.errorHandler(error) }
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/lib/soap.js:
--------------------------------------------------------------------------------
1 | const soap = require('soap');
2 |
3 | module.exports = class Soap {
4 | constructor(defaultUrlOrServerConfig, rootFolder) {
5 | defaultUrlOrServerConfig && this.setServerUrl(defaultUrlOrServerConfig);
6 | rootFolder && this.setRootFolder(rootFolder);
7 | }
8 |
9 | async createClient(url, config, security) {
10 | if (url) { this.setServerUrl(url) }
11 | config = config || {};
12 | if (!security) { security = 'ntlm' }
13 | const auth = this.createAuthObj(config);
14 | const secure = this.getSecurity(security, auth);
15 |
16 | const cfg = this.setOptions(config, security, secure);
17 | this.client = await soap.createClientAsync(this.url, cfg);
18 | if (secure) { this.client.setSecurity(secure) }
19 |
20 | return this.client;
21 | }
22 |
23 | getRootFolder() { return this.rootFolder }
24 | setRootFolder(rootFolder) { this.rootFolder = rootFolder || '/' }
25 |
26 | getServerUrl() { return this.url }
27 | setServerUrl(config) {
28 | this.url = typeof config === 'string'
29 | ? config
30 | : (config.isHttps ? 'https' : 'http') + '://'
31 | + config.server + (config.port ? ':' + config.port : '')
32 | + '/ReportServer' + (config.instance ? '_' + config.instance : '')
33 | }
34 |
35 | createAuthObj(config) {
36 | if (config.wsdl_options) { return config.wsdl_options }
37 | return {
38 | username: (config.username || config.userName),
39 | password: config.password || '',
40 | workstation: config.workstation || '',
41 | domain: config.domain || ''
42 | }
43 | }
44 |
45 | setOptions(config, securityType, security) {
46 | switch (securityType) {
47 | case 'ntlm':
48 | config.wsdl_options = security.defaults;
49 | config.wsdl_headers = config.wsdl_headers || {};
50 | security && security.addHeaders && security.addHeaders(config.wsdl_headers);
51 | break;
52 | case 'basic':
53 | config.wsdl_headers = config.wsdl_headers || {};
54 | security && security.addHeaders && security.addHeaders(config.wsdl_headers);
55 | break;
56 | }
57 | return config;
58 | }
59 |
60 | getSecurity(security, auth) {
61 | switch (security) {
62 | case 'ntlm': return new soap.security.NTLMSecurity(auth.username, auth.password, auth.domain, auth.workstation);
63 | case 'basic': return new soap.security.BasicAuthSecurity(auth.username, auth.password);
64 | default: return security;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/lib/utils.js:
--------------------------------------------------------------------------------
1 | const Soap = require('./soap');
2 |
3 | module.exports = {
4 | createSoapInstance: function createSoapInstance(url, options) {
5 | return new Soap(url, (options || {}).rootFolder)
6 | },
7 | testReportPath: function testReportPath(rootFolder, reportPath) {
8 | return rootFolder && !new RegExp('^' + rootFolder).test(reportPath) ? rootFolder + reportPath : reportPath;
9 | },
10 | reportFileFormat: function reportFormat(fileType) {
11 | fileType = fileType && fileType.toUpperCase();
12 | switch (fileType) {
13 | case 'EXCELOPENXML': case 'EXCEL': case 'XLS': case 'XLSX': return 'EXCELOPENXML';
14 | case 'WORDOPENXML': case 'WORD': case 'DOC': case 'DOCX': return 'WORDOPENXML';
15 | default: return fileType || 'PDF';
16 | }
17 | },
18 | errorHandler: function errorHandler(err) {
19 | const message = err && err.root && err.root.Envelope && err.root.Envelope.Body && err.root.Envelope.Body.Fault.faultstring;
20 | throw new Error(message || (err && err.message) || err);
21 | }
22 | }
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mssql-ssrs",
3 | "version": "2.4.2",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "mssql-ssrs",
9 | "version": "2.4.2",
10 | "license": "MIT",
11 | "dependencies": {
12 | "axios-ntlm": "^1.4.4",
13 | "dayjs": "^1.11.13",
14 | "soap": "^1.1.11"
15 | },
16 | "engines": {
17 | "node": ">= 12"
18 | }
19 | },
20 | "node_modules/@noble/hashes": {
21 | "version": "1.8.0",
22 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
23 | "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
24 | "license": "MIT",
25 | "engines": {
26 | "node": "^14.21.3 || >=16"
27 | },
28 | "funding": {
29 | "url": "https://paulmillr.com/funding/"
30 | }
31 | },
32 | "node_modules/@paralleldrive/cuid2": {
33 | "version": "2.2.2",
34 | "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz",
35 | "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==",
36 | "license": "MIT",
37 | "dependencies": {
38 | "@noble/hashes": "^1.1.5"
39 | }
40 | },
41 | "node_modules/@xmldom/is-dom-node": {
42 | "version": "1.0.1",
43 | "resolved": "https://registry.npmjs.org/@xmldom/is-dom-node/-/is-dom-node-1.0.1.tgz",
44 | "integrity": "sha512-CJDxIgE5I0FH+ttq/Fxy6nRpxP70+e2O048EPe85J2use3XKdatVM7dDVvFNjQudd9B49NPoZ+8PG49zj4Er8Q==",
45 | "license": "MIT",
46 | "engines": {
47 | "node": ">= 16"
48 | }
49 | },
50 | "node_modules/@xmldom/xmldom": {
51 | "version": "0.8.10",
52 | "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
53 | "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
54 | "license": "MIT",
55 | "engines": {
56 | "node": ">=10.0.0"
57 | }
58 | },
59 | "node_modules/asap": {
60 | "version": "2.0.6",
61 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
62 | "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
63 | "license": "MIT"
64 | },
65 | "node_modules/asynckit": {
66 | "version": "0.4.0",
67 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
68 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
69 | "license": "MIT"
70 | },
71 | "node_modules/axios": {
72 | "version": "1.8.4",
73 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
74 | "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
75 | "license": "MIT",
76 | "dependencies": {
77 | "follow-redirects": "^1.15.6",
78 | "form-data": "^4.0.0",
79 | "proxy-from-env": "^1.1.0"
80 | }
81 | },
82 | "node_modules/axios-ntlm": {
83 | "version": "1.4.4",
84 | "resolved": "https://registry.npmjs.org/axios-ntlm/-/axios-ntlm-1.4.4.tgz",
85 | "integrity": "sha512-kpCRdzMfL8gi0Z0o96P3QPAK4XuC8iciGgxGXe+PeQ4oyjI2LZN8WSOKbu0Y9Jo3T/A7pB81n6jYVPIpglEuRA==",
86 | "license": "MIT",
87 | "dependencies": {
88 | "axios": "^1.8.4",
89 | "des.js": "^1.1.0",
90 | "dev-null": "^0.1.1",
91 | "js-md4": "^0.3.2"
92 | }
93 | },
94 | "node_modules/call-bind-apply-helpers": {
95 | "version": "1.0.2",
96 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
97 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
98 | "license": "MIT",
99 | "dependencies": {
100 | "es-errors": "^1.3.0",
101 | "function-bind": "^1.1.2"
102 | },
103 | "engines": {
104 | "node": ">= 0.4"
105 | }
106 | },
107 | "node_modules/combined-stream": {
108 | "version": "1.0.8",
109 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
110 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
111 | "license": "MIT",
112 | "dependencies": {
113 | "delayed-stream": "~1.0.0"
114 | },
115 | "engines": {
116 | "node": ">= 0.8"
117 | }
118 | },
119 | "node_modules/dayjs": {
120 | "version": "1.11.13",
121 | "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
122 | "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
123 | "license": "MIT"
124 | },
125 | "node_modules/debug": {
126 | "version": "4.4.0",
127 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
128 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
129 | "license": "MIT",
130 | "dependencies": {
131 | "ms": "^2.1.3"
132 | },
133 | "engines": {
134 | "node": ">=6.0"
135 | },
136 | "peerDependenciesMeta": {
137 | "supports-color": {
138 | "optional": true
139 | }
140 | }
141 | },
142 | "node_modules/delayed-stream": {
143 | "version": "1.0.0",
144 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
145 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
146 | "license": "MIT",
147 | "engines": {
148 | "node": ">=0.4.0"
149 | }
150 | },
151 | "node_modules/des.js": {
152 | "version": "1.1.0",
153 | "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
154 | "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
155 | "license": "MIT",
156 | "dependencies": {
157 | "inherits": "^2.0.1",
158 | "minimalistic-assert": "^1.0.0"
159 | }
160 | },
161 | "node_modules/dev-null": {
162 | "version": "0.1.1",
163 | "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz",
164 | "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==",
165 | "license": "MIT"
166 | },
167 | "node_modules/dezalgo": {
168 | "version": "1.0.4",
169 | "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
170 | "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
171 | "license": "ISC",
172 | "dependencies": {
173 | "asap": "^2.0.0",
174 | "wrappy": "1"
175 | }
176 | },
177 | "node_modules/dunder-proto": {
178 | "version": "1.0.1",
179 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
180 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
181 | "license": "MIT",
182 | "dependencies": {
183 | "call-bind-apply-helpers": "^1.0.1",
184 | "es-errors": "^1.3.0",
185 | "gopd": "^1.2.0"
186 | },
187 | "engines": {
188 | "node": ">= 0.4"
189 | }
190 | },
191 | "node_modules/es-define-property": {
192 | "version": "1.0.1",
193 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
194 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
195 | "license": "MIT",
196 | "engines": {
197 | "node": ">= 0.4"
198 | }
199 | },
200 | "node_modules/es-errors": {
201 | "version": "1.3.0",
202 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
203 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
204 | "license": "MIT",
205 | "engines": {
206 | "node": ">= 0.4"
207 | }
208 | },
209 | "node_modules/es-object-atoms": {
210 | "version": "1.1.1",
211 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
212 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
213 | "license": "MIT",
214 | "dependencies": {
215 | "es-errors": "^1.3.0"
216 | },
217 | "engines": {
218 | "node": ">= 0.4"
219 | }
220 | },
221 | "node_modules/es-set-tostringtag": {
222 | "version": "2.1.0",
223 | "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
224 | "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
225 | "license": "MIT",
226 | "dependencies": {
227 | "es-errors": "^1.3.0",
228 | "get-intrinsic": "^1.2.6",
229 | "has-tostringtag": "^1.0.2",
230 | "hasown": "^2.0.2"
231 | },
232 | "engines": {
233 | "node": ">= 0.4"
234 | }
235 | },
236 | "node_modules/follow-redirects": {
237 | "version": "1.15.9",
238 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
239 | "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
240 | "funding": [
241 | {
242 | "type": "individual",
243 | "url": "https://github.com/sponsors/RubenVerborgh"
244 | }
245 | ],
246 | "license": "MIT",
247 | "engines": {
248 | "node": ">=4.0"
249 | },
250 | "peerDependenciesMeta": {
251 | "debug": {
252 | "optional": true
253 | }
254 | }
255 | },
256 | "node_modules/form-data": {
257 | "version": "4.0.2",
258 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
259 | "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
260 | "license": "MIT",
261 | "dependencies": {
262 | "asynckit": "^0.4.0",
263 | "combined-stream": "^1.0.8",
264 | "es-set-tostringtag": "^2.1.0",
265 | "mime-types": "^2.1.12"
266 | },
267 | "engines": {
268 | "node": ">= 6"
269 | }
270 | },
271 | "node_modules/formidable": {
272 | "version": "3.5.4",
273 | "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz",
274 | "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==",
275 | "license": "MIT",
276 | "dependencies": {
277 | "@paralleldrive/cuid2": "^2.2.2",
278 | "dezalgo": "^1.0.4",
279 | "once": "^1.4.0"
280 | },
281 | "engines": {
282 | "node": ">=14.0.0"
283 | },
284 | "funding": {
285 | "url": "https://ko-fi.com/tunnckoCore/commissions"
286 | }
287 | },
288 | "node_modules/function-bind": {
289 | "version": "1.1.2",
290 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
291 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
292 | "license": "MIT",
293 | "funding": {
294 | "url": "https://github.com/sponsors/ljharb"
295 | }
296 | },
297 | "node_modules/get-intrinsic": {
298 | "version": "1.3.0",
299 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
300 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
301 | "license": "MIT",
302 | "dependencies": {
303 | "call-bind-apply-helpers": "^1.0.2",
304 | "es-define-property": "^1.0.1",
305 | "es-errors": "^1.3.0",
306 | "es-object-atoms": "^1.1.1",
307 | "function-bind": "^1.1.2",
308 | "get-proto": "^1.0.1",
309 | "gopd": "^1.2.0",
310 | "has-symbols": "^1.1.0",
311 | "hasown": "^2.0.2",
312 | "math-intrinsics": "^1.1.0"
313 | },
314 | "engines": {
315 | "node": ">= 0.4"
316 | },
317 | "funding": {
318 | "url": "https://github.com/sponsors/ljharb"
319 | }
320 | },
321 | "node_modules/get-proto": {
322 | "version": "1.0.1",
323 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
324 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
325 | "license": "MIT",
326 | "dependencies": {
327 | "dunder-proto": "^1.0.1",
328 | "es-object-atoms": "^1.0.0"
329 | },
330 | "engines": {
331 | "node": ">= 0.4"
332 | }
333 | },
334 | "node_modules/get-stream": {
335 | "version": "6.0.1",
336 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
337 | "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
338 | "license": "MIT",
339 | "engines": {
340 | "node": ">=10"
341 | },
342 | "funding": {
343 | "url": "https://github.com/sponsors/sindresorhus"
344 | }
345 | },
346 | "node_modules/gopd": {
347 | "version": "1.2.0",
348 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
349 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
350 | "license": "MIT",
351 | "engines": {
352 | "node": ">= 0.4"
353 | },
354 | "funding": {
355 | "url": "https://github.com/sponsors/ljharb"
356 | }
357 | },
358 | "node_modules/has-symbols": {
359 | "version": "1.1.0",
360 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
361 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
362 | "license": "MIT",
363 | "engines": {
364 | "node": ">= 0.4"
365 | },
366 | "funding": {
367 | "url": "https://github.com/sponsors/ljharb"
368 | }
369 | },
370 | "node_modules/has-tostringtag": {
371 | "version": "1.0.2",
372 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
373 | "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
374 | "license": "MIT",
375 | "dependencies": {
376 | "has-symbols": "^1.0.3"
377 | },
378 | "engines": {
379 | "node": ">= 0.4"
380 | },
381 | "funding": {
382 | "url": "https://github.com/sponsors/ljharb"
383 | }
384 | },
385 | "node_modules/hasown": {
386 | "version": "2.0.2",
387 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
388 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
389 | "license": "MIT",
390 | "dependencies": {
391 | "function-bind": "^1.1.2"
392 | },
393 | "engines": {
394 | "node": ">= 0.4"
395 | }
396 | },
397 | "node_modules/inherits": {
398 | "version": "2.0.4",
399 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
400 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
401 | "license": "ISC"
402 | },
403 | "node_modules/js-md4": {
404 | "version": "0.3.2",
405 | "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz",
406 | "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==",
407 | "license": "MIT"
408 | },
409 | "node_modules/lodash": {
410 | "version": "4.17.21",
411 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
412 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
413 | "license": "MIT"
414 | },
415 | "node_modules/math-intrinsics": {
416 | "version": "1.1.0",
417 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
418 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
419 | "license": "MIT",
420 | "engines": {
421 | "node": ">= 0.4"
422 | }
423 | },
424 | "node_modules/mime-db": {
425 | "version": "1.52.0",
426 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
427 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
428 | "license": "MIT",
429 | "engines": {
430 | "node": ">= 0.6"
431 | }
432 | },
433 | "node_modules/mime-types": {
434 | "version": "2.1.35",
435 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
436 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
437 | "license": "MIT",
438 | "dependencies": {
439 | "mime-db": "1.52.0"
440 | },
441 | "engines": {
442 | "node": ">= 0.6"
443 | }
444 | },
445 | "node_modules/minimalistic-assert": {
446 | "version": "1.0.1",
447 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
448 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
449 | "license": "ISC"
450 | },
451 | "node_modules/ms": {
452 | "version": "2.1.3",
453 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
454 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
455 | "license": "MIT"
456 | },
457 | "node_modules/once": {
458 | "version": "1.4.0",
459 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
460 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
461 | "license": "ISC",
462 | "dependencies": {
463 | "wrappy": "1"
464 | }
465 | },
466 | "node_modules/proxy-from-env": {
467 | "version": "1.1.0",
468 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
469 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
470 | "license": "MIT"
471 | },
472 | "node_modules/sax": {
473 | "version": "1.4.1",
474 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
475 | "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
476 | "license": "ISC"
477 | },
478 | "node_modules/soap": {
479 | "version": "1.1.11",
480 | "resolved": "https://registry.npmjs.org/soap/-/soap-1.1.11.tgz",
481 | "integrity": "sha512-wxpKktgEZZvxHIKisFPB4VgURNhSuSJU3mX/1kP11GxlENNzYe0gWk3w/+vLhpx68mMSMjeMR/8sahaPXVBj+Q==",
482 | "license": "MIT",
483 | "dependencies": {
484 | "axios": "^1.8.4",
485 | "axios-ntlm": "^1.4.4",
486 | "debug": "^4.4.0",
487 | "formidable": "^3.5.2",
488 | "get-stream": "^6.0.1",
489 | "lodash": "^4.17.21",
490 | "sax": "^1.4.1",
491 | "strip-bom": "^3.0.0",
492 | "whatwg-mimetype": "4.0.0",
493 | "xml-crypto": "^6.1.1"
494 | },
495 | "engines": {
496 | "node": ">=14.17.0"
497 | }
498 | },
499 | "node_modules/strip-bom": {
500 | "version": "3.0.0",
501 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
502 | "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
503 | "license": "MIT",
504 | "engines": {
505 | "node": ">=4"
506 | }
507 | },
508 | "node_modules/whatwg-mimetype": {
509 | "version": "4.0.0",
510 | "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
511 | "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
512 | "license": "MIT",
513 | "engines": {
514 | "node": ">=18"
515 | }
516 | },
517 | "node_modules/wrappy": {
518 | "version": "1.0.2",
519 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
520 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
521 | "license": "ISC"
522 | },
523 | "node_modules/xml-crypto": {
524 | "version": "6.1.1",
525 | "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-6.1.1.tgz",
526 | "integrity": "sha512-ni6H4Xnd5zvpDKvevmFmmKNojF2cAoTcioeSasICsDTkF0pjqS/PlHsMCLjiruH0N6iVa3OCBMHRLwRfcUPo2g==",
527 | "license": "MIT",
528 | "dependencies": {
529 | "@xmldom/is-dom-node": "^1.0.1",
530 | "@xmldom/xmldom": "^0.8.10",
531 | "xpath": "^0.0.33"
532 | },
533 | "engines": {
534 | "node": ">=16"
535 | }
536 | },
537 | "node_modules/xpath": {
538 | "version": "0.0.33",
539 | "resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.33.tgz",
540 | "integrity": "sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA==",
541 | "license": "MIT",
542 | "engines": {
543 | "node": ">=0.6.0"
544 | }
545 | }
546 | }
547 | }
548 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mssql-ssrs",
3 | "version": "2.4.2",
4 | "description": "Promise based api for MSSQL Reporting Services with ntlm and basic security",
5 | "author": "Sorin Muresan ",
6 | "keywords": [
7 | "mssql",
8 | "sql",
9 | "ssrs",
10 | "reporting services",
11 | "soap",
12 | "ntlm"
13 | ],
14 | "repository": {
15 | "type": "git",
16 | "url": "https://github.com/vision10/mssql-ssrs.git"
17 | },
18 | "license": "MIT",
19 | "engines": {
20 | "node": ">= 12"
21 | },
22 | "main": "index.js",
23 | "directories": {
24 | "lib": "./lib"
25 | },
26 | "scripts": {
27 | "start": "node index.js"
28 | },
29 | "dependencies": {
30 | "axios-ntlm": "^1.4.4",
31 | "dayjs": "^1.11.13",
32 | "soap": "^1.1.11"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------