Comparing version 0.27.1 to 0.28.0
@@ -0,1 +1,18 @@ | ||
0.28.0 / 2019-06-20 | ||
=================== | ||
* [ENHANCEMENT] Added support for parsing of doubles and floats. (#1065) | ||
* [ENHANCEMENT] Adds promise server authentication (#1069) | ||
* [ENHANCEMENT] Expose the WSDL class (#1071) | ||
* [ENHANCEMENT] Now supporting XSI namespace overrides (#1079) | ||
* [ENHANCEMENT] added possibility to add action to content-type header (#1073) | ||
* [ENHANCEMENT] client.addSoapHeader() dynamic SOAP header (#1062) | ||
* [ENHANCEMENT] emit response events allowing user override on response XML (#1070) | ||
* [FIX] Fix description for recursive wsdl with extended element (#1078) | ||
* [FIX] Fixes issue with unknown ReadableStream type (#1076) | ||
* [FIX] Update types to make `options` optional for createClientAsync (#1068) | ||
* [FIX] fix for soap 1.2 content-type header, missing action key (#1075) | ||
* [FIX] types: move forceSoap12Headers to IWsdlBaseOptions (#1063) | ||
* [MAINTENANCE] Updated read me to reflect changes in soap.listen (#1060) | ||
0.27.1 / 2019-04-19 | ||
@@ -2,0 +19,0 @@ =================== |
@@ -47,4 +47,4 @@ /// <reference types="node" /> | ||
/** add soapHeader to soap:Header node */ | ||
addSoapHeader(soapHeader: any, name?: string, namespace?: string, xmlns?: string): number; | ||
changeSoapHeader(index: number, soapHeader: any, name?: string, namespace?: string, xmlns?: string): void; | ||
addSoapHeader(soapHeader: any, name?: string, namespace?: any, xmlns?: string): number; | ||
changeSoapHeader(index: any, soapHeader: any, name?: any, namespace?: any, xmlns?: any): void; | ||
/** return all defined headers */ | ||
@@ -72,3 +72,4 @@ getSoapHeaders(): string[]; | ||
private _defineMethod; | ||
private _processSoapHeader; | ||
private _invoke; | ||
} |
@@ -34,8 +34,8 @@ "use strict"; | ||
function Client(wsdl, endpoint, options) { | ||
var _this = _super.call(this) || this; | ||
var _this_1 = _super.call(this) || this; | ||
options = options || {}; | ||
_this.wsdl = wsdl; | ||
_this._initializeOptions(options); | ||
_this._initializeServices(endpoint); | ||
_this.httpClient = options.httpClient || new http_1.HttpClient(options); | ||
_this_1.wsdl = wsdl; | ||
_this_1._initializeOptions(options); | ||
_this_1._initializeServices(endpoint); | ||
_this_1.httpClient = options.httpClient || new http_1.HttpClient(options); | ||
var promiseOptions = { multiArgs: true }; | ||
@@ -45,4 +45,4 @@ if (options.overridePromiseSuffix) { | ||
} | ||
BluebirdPromise.promisifyAll(_this, promiseOptions); | ||
return _this; | ||
BluebirdPromise.promisifyAll(_this_1, promiseOptions); | ||
return _this_1; | ||
} | ||
@@ -54,5 +54,3 @@ /** add soapHeader to soap:Header node */ | ||
} | ||
if (typeof soapHeader === 'object') { | ||
soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); | ||
} | ||
soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns); | ||
return this.soapHeaders.push(soapHeader) - 1; | ||
@@ -64,5 +62,3 @@ }; | ||
} | ||
if (typeof soapHeader === 'object') { | ||
soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); | ||
} | ||
soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns); | ||
this.soapHeaders[index] = soapHeader; | ||
@@ -177,3 +173,3 @@ }; | ||
Client.prototype._defineMethod = function (method, location) { | ||
var _this = this; | ||
var _this_1 = this; | ||
var temp; | ||
@@ -196,3 +192,3 @@ return function (args, callback, options, extraHeaders) { | ||
} | ||
_this._invoke(method, args, location, function (error, result, rawResponse, soapHeader, rawRequest) { | ||
_this_1._invoke(method, args, location, function (error, result, rawResponse, soapHeader, rawRequest) { | ||
callback(error, result, rawResponse, soapHeader, rawRequest); | ||
@@ -202,4 +198,25 @@ }, options, extraHeaders); | ||
}; | ||
Client.prototype._processSoapHeader = function (soapHeader, name, namespace, xmlns) { | ||
switch (typeof soapHeader) { | ||
case 'object': | ||
return this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); | ||
case 'function': | ||
var _this_2 = this; | ||
// arrow function does not support arguments variable | ||
// tslint:disable-next-line | ||
return function () { | ||
var result = soapHeader.apply(null, arguments); | ||
if (typeof result === 'object') { | ||
return _this_2.wsdl.objectToXML(result, name, namespace, xmlns, true); | ||
} | ||
else { | ||
return result; | ||
} | ||
}; | ||
default: | ||
return soapHeader; | ||
} | ||
}; | ||
Client.prototype._invoke = function (method, args, location, callback, options, extraHeaders) { | ||
var _this = this; | ||
var _this_1 = this; | ||
var name = method.$name; | ||
@@ -234,3 +251,3 @@ var input = method.input; | ||
error.body = body; | ||
_this.emit('soapError', error, eid); | ||
_this_1.emit('soapError', error, eid); | ||
return callback(error, obj, body, obj.Header); | ||
@@ -265,3 +282,3 @@ } | ||
try { | ||
obj = _this.wsdl.xmlToObject(body); | ||
obj = _this_1.wsdl.xmlToObject(body); | ||
} | ||
@@ -281,3 +298,3 @@ catch (error) { | ||
error.body = body; | ||
_this.emit('soapError', error, eid); | ||
_this_1.emit('soapError', error, eid); | ||
return callback(error, response, body, undefined, xml); | ||
@@ -287,6 +304,2 @@ } | ||
}; | ||
if (this.wsdl.options.forceSoap12Headers) { | ||
headers['Content-Type'] = 'application/soap+xml; charset=utf-8'; | ||
xmlnsSoap = 'xmlns:' + envelopeKey + '="http://www.w3.org/2003/05/soap-envelope"'; | ||
} | ||
if (this.SOAPAction) { | ||
@@ -301,3 +314,7 @@ soapAction = this.SOAPAction; | ||
} | ||
if (!this.wsdl.options.forceSoap12Headers) { | ||
if (this.wsdl.options.forceSoap12Headers) { | ||
headers['Content-Type'] = "application/soap+xml; charset=utf-8; action=\"" + soapAction + "\""; | ||
xmlnsSoap = 'xmlns:' + envelopeKey + '="http://www.w3.org/2003/05/soap-envelope"'; | ||
} | ||
else { | ||
headers.SOAPAction = '"' + soapAction + '"'; | ||
@@ -330,2 +347,13 @@ } | ||
} | ||
var decodedHeaders; | ||
if (this.soapHeaders) { | ||
decodedHeaders = this.soapHeaders.map(function (header) { | ||
if (typeof header === 'function') { | ||
return header(method, location, soapAction, args); | ||
} | ||
else { | ||
return header; | ||
} | ||
}).join('\n'); | ||
} | ||
xml = '<?xml version="1.0" encoding="utf-8"?>' + | ||
@@ -337,5 +365,5 @@ '<' + envelopeKey + ':Envelope ' + | ||
this.wsdl.xmlnsInEnvelope + '>' + | ||
((this.soapHeaders || this.security) ? | ||
((decodedHeaders || this.security) ? | ||
('<' + envelopeKey + ':Header>' + | ||
(this.soapHeaders ? this.soapHeaders.join('\n') : '') + | ||
(decodedHeaders ? decodedHeaders : '') + | ||
(this.security && !this.security.postProcess ? this.security.toXML() : '') + | ||
@@ -378,6 +406,6 @@ '</' + envelopeKey + ':Header>') | ||
var onError_1 = function (err) { | ||
_this.lastResponse = null; | ||
_this.lastResponseHeaders = null; | ||
_this.lastElapsedTime = null; | ||
_this.emit('response', null, null, eid); | ||
_this_1.lastResponse = null; | ||
_this_1.lastResponseHeaders = null; | ||
_this_1.lastElapsedTime = null; | ||
_this_1.emit('response', null, null, eid); | ||
callback(err, undefined, undefined, undefined, xml); | ||
@@ -392,6 +420,6 @@ }; | ||
response.pipe(concatStream({ encoding: 'string' }, function (body) { | ||
_this.lastResponse = body; | ||
_this.lastResponseHeaders = response && response.headers; | ||
_this.lastElapsedTime = Date.now() - startTime_1; | ||
_this.emit('response', body, response, eid); | ||
_this_1.lastResponse = body; | ||
_this_1.lastResponseHeaders = response && response.headers; | ||
_this_1.lastElapsedTime = Date.now() - startTime_1; | ||
_this_1.emit('response', body, response, eid); | ||
return parseSync(body, response); | ||
@@ -401,11 +429,11 @@ })); | ||
} | ||
_this.wsdl.xmlToObject(response, function (error, obj) { | ||
_this.lastResponse = response; | ||
_this.lastResponseHeaders = response && response.headers; | ||
_this.lastElapsedTime = Date.now() - startTime_1; | ||
_this.emit('response', '<stream>', response, eid); | ||
_this_1.wsdl.xmlToObject(response, function (error, obj) { | ||
_this_1.lastResponse = response; | ||
_this_1.lastResponseHeaders = response && response.headers; | ||
_this_1.lastElapsedTime = Date.now() - startTime_1; | ||
_this_1.emit('response', '<stream>', response, eid); | ||
if (error) { | ||
error.response = response; | ||
error.body = '<stream>'; | ||
_this.emit('soapError', error, eid); | ||
_this_1.emit('soapError', error, eid); | ||
return callback(error, response, undefined, undefined, xml); | ||
@@ -419,6 +447,6 @@ } | ||
req = this.httpClient.request(location, xml, function (err, response, body) { | ||
_this.lastResponse = body; | ||
_this.lastResponseHeaders = response && response.headers; | ||
_this.lastElapsedTime = response && response.elapsedTime; | ||
_this.emit('response', body, response, eid); | ||
_this_1.lastResponse = body; | ||
_this_1.lastResponseHeaders = response && response.headers; | ||
_this_1.lastElapsedTime = response && response.elapsedTime; | ||
_this_1.emit('response', body, response, eid); | ||
if (err) { | ||
@@ -425,0 +453,0 @@ callback(err, undefined, undefined, undefined, xml); |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
import * as req from 'request'; | ||
@@ -10,3 +11,3 @@ import { IHeaders, IOptions } from './types'; | ||
mimetype: string; | ||
body: ReadableStream; | ||
body: NodeJS.ReadableStream; | ||
} | ||
@@ -13,0 +14,0 @@ export declare type Request = req.Request; |
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import * as http from 'http'; | ||
import { ISecurity, IServerOptions, IServices } from './types'; | ||
import { IServerOptions, IServices } from './types'; | ||
import { WSDL } from './wsdl'; | ||
@@ -18,2 +18,3 @@ interface IExpressApp { | ||
emit(event: 'headers', headers: any, methodName: string): boolean; | ||
emit(event: 'response', headers: any, methodName: string): boolean; | ||
/** Emitted for every received messages. */ | ||
@@ -23,2 +24,4 @@ on(event: 'request', listener: (request: any, methodName: string) => void): this; | ||
on(event: 'headers', listener: (headers: any, methodName: string) => void): this; | ||
/** Emitted before sending SOAP response. */ | ||
on(event: 'response', listener: (response: any, methodName: string) => void): this; | ||
} | ||
@@ -30,3 +33,3 @@ export declare class Server extends EventEmitter { | ||
authorizeConnection: (req: Request, res?: Response) => boolean; | ||
authenticate: (security: ISecurity, processAuthResult?: any) => boolean; | ||
authenticate: (security: any, processAuthResult?: (result: boolean) => void, req?: Request, obj?: any) => boolean | void | Promise<boolean>; | ||
private wsdl; | ||
@@ -33,0 +36,0 @@ private suppressStack; |
@@ -237,3 +237,3 @@ "use strict"; | ||
}; | ||
Server.prototype._process = function (input, req, callback) { | ||
Server.prototype._process = function (input, req, cb) { | ||
var _this_1 = this; | ||
@@ -250,2 +250,7 @@ var pathname = url.parse(req.url).pathname.replace(/\/$/, ''); | ||
var authenticate = this.authenticate || function defaultAuthenticate() { return true; }; | ||
var callback = function (result, statusCode) { | ||
var response = { result: result }; | ||
_this_1.emit('response', response, methodName); | ||
cb(response.result, statusCode); | ||
}; | ||
var process = function () { | ||
@@ -335,6 +340,21 @@ if (typeof _this_1.log === 'function') { | ||
var authResultProcessed_1 = false; | ||
var processAuthResult = function (authResult) { | ||
if (!authResultProcessed_1 && (authResult || authResult === false)) { | ||
authResultProcessed_1 = true; | ||
if (authResult) { | ||
var processAuthResult_1 = function (authResult) { | ||
if (authResultProcessed_1) { | ||
return; | ||
} | ||
authResultProcessed_1 = true; | ||
// Handle errors | ||
if (authResult instanceof Error) { | ||
return _this_1._sendError({ | ||
Code: { | ||
Value: 'SOAP-ENV:Server', | ||
Subcode: { value: 'InternalServerError' } | ||
}, | ||
Reason: { Text: authResult.toString() }, | ||
statusCode: 500 | ||
}, callback, includeTimestamp); | ||
} | ||
// Handle actual results | ||
if (typeof authResult === 'boolean') { | ||
if (authResult === true) { | ||
try { | ||
@@ -369,3 +389,13 @@ process(); | ||
}; | ||
processAuthResult(authenticate(obj.Header && obj.Header.Security, processAuthResult)); | ||
var functionResult = authenticate(obj.Header && obj.Header.Security, processAuthResult_1, req, obj); | ||
if (isPromiseLike(functionResult)) { | ||
functionResult.then(function (result) { | ||
processAuthResult_1(result); | ||
}, function (err) { | ||
processAuthResult_1(err); | ||
}); | ||
} | ||
if (typeof functionResult === 'boolean') { | ||
processAuthResult_1(functionResult); | ||
} | ||
} | ||
@@ -372,0 +402,0 @@ else { |
@@ -13,7 +13,8 @@ import * as BluebirdPromise from 'bluebird'; | ||
export * from './types'; | ||
export { WSDL } from './wsdl'; | ||
export declare type CreateClientCallback = (err: any, client: Client) => void; | ||
export declare function createClient(url: string, callback: CreateClientCallback, endpoint?: string): void; | ||
export declare function createClient(url: string, options: IOptions, callback: CreateClientCallback, endpoint?: string): void; | ||
export declare function createClientAsync(url: string, options: IOptions, endpoint?: string): BluebirdPromise<Client>; | ||
export declare function createClientAsync(url: string, options?: IOptions, endpoint?: string): BluebirdPromise<Client>; | ||
export declare function listen(server: ServerType, path: string, services: IServices, wsdl: string, callback?: (err: any, res: any) => void): Server; | ||
export declare function listen(server: ServerType, options: IServerOptions): Server; |
@@ -31,2 +31,4 @@ "use strict"; | ||
exports.passwordDigest = utils_1.passwordDigest; | ||
var wsdl_2 = require("./wsdl"); | ||
exports.WSDL = wsdl_2.WSDL; | ||
function createCache() { | ||
@@ -33,0 +35,0 @@ var cache = {}; |
@@ -87,2 +87,4 @@ import * as req from 'request'; | ||
}; | ||
/** set proper headers for SOAP v1.2. */ | ||
forceSoap12Headers?: boolean; | ||
} | ||
@@ -103,4 +105,2 @@ /** @deprecated use IOptions */ | ||
stream?: boolean; | ||
/** set proper headers for SOAP v1.2. */ | ||
forceSoap12Headers?: boolean; | ||
customDeserializer?: any; | ||
@@ -107,0 +107,0 @@ /** if your wsdl operations contains names with Async suffix, you will need to override the default promise suffix to a custom one, default: Async. */ |
@@ -392,3 +392,3 @@ "use strict"; | ||
var base = typeElement.description(definitions, schema.xmlns); | ||
desc = typeof base === 'string' ? base : _.defaultsDeep(base, desc); | ||
desc = typeof base === 'string' ? base : _.defaults(base, desc); | ||
} | ||
@@ -395,0 +395,0 @@ } |
@@ -22,2 +22,3 @@ "use strict"; | ||
var debug = debugBuilder('node-soap'); | ||
var XSI_URI = 'http://www.w3.org/2001/XMLSchema-instance'; | ||
function xmlEscape(obj) { | ||
@@ -267,3 +268,3 @@ if (typeof (obj) === 'string') { | ||
var res = utils_1.splitQName(attributeName); | ||
if (res.name === 'nil' && xmlns[res.prefix] === 'http://www.w3.org/2001/XMLSchema-instance' && elementAttributes[attributeName] && | ||
if (res.name === 'nil' && xmlns[res.prefix] === XSI_URI && elementAttributes[attributeName] && | ||
(elementAttributes[attributeName].toLowerCase() === 'true' || elementAttributes[attributeName] === '1')) { | ||
@@ -279,3 +280,9 @@ hasNilAttribute = true; | ||
var xsiTypeSchema; | ||
var xsiType = elementAttributes['xsi:type']; | ||
var xsiType; | ||
for (var prefix in xmlns) { | ||
if (xmlns[prefix] === XSI_URI && (prefix + ":type" in elementAttributes)) { | ||
xsiType = elementAttributes[prefix + ":type"]; | ||
break; | ||
} | ||
} | ||
if (xsiType) { | ||
@@ -390,2 +397,5 @@ var type = utils_1.splitQName(xsiType); | ||
} | ||
else if (name === 'double' || name === 'float') { | ||
value = Number(text); | ||
} | ||
else if (name === 'bool' || name === 'boolean') { | ||
@@ -392,0 +402,0 @@ value = text.toLowerCase() === 'true' || text === '1'; |
{ | ||
"name": "soap", | ||
"version": "0.27.1", | ||
"version": "0.28.0", | ||
"description": "A minimal node SOAP client", | ||
@@ -5,0 +5,0 @@ "engines": { |
@@ -19,3 +19,3 @@ # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url] | ||
- [soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclientasyncurl-options---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path) | ||
- [soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.](#soaplistenserver-path-services-wsdl---create-a-new-soap-server-that-listens-on-path-and-provides-services) | ||
- [soap.listen(*server*, *path*, *services*, *wsdl*, *callback*) - create a new SOAP server that listens on *path* and provides *services*.](#soaplistenserver-path-services-wsdl-callback---create-a-new-soap-server-that-listens-on-path-and-provides-services) | ||
- [Options](#options) | ||
@@ -149,5 +149,6 @@ - [Server Logging](#server-logging) | ||
### soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*. | ||
### soap.listen(*server*, *path*, *services*, *wsdl*, *callback*) - create a new SOAP server that listens on *path* and provides *services*. | ||
*server* can be a [http](https://nodejs.org/api/http.html) Server or [express](http://expressjs.com/) framework based server | ||
*wsdl* is an xml string that defines the service. | ||
*callback* a function to run after the server has been initialized. | ||
@@ -208,3 +209,5 @@ ``` javascript | ||
server.listen(8000); | ||
soap.listen(server, '/wsdl', myService, xml); | ||
soap.listen(server, '/wsdl', myService, xml, function(){ | ||
console.log('server initialized'); | ||
}); | ||
@@ -218,3 +221,5 @@ //express server example | ||
//and all other routes & middleware will continue to work | ||
soap.listen(app, '/wsdl', myService, xml); | ||
soap.listen(app, '/wsdl', myService, xml, function(){ | ||
console.log('server initialized'); | ||
}); | ||
}); | ||
@@ -272,2 +277,4 @@ | ||
The signature of the callback is `function(request, methodName)`. | ||
* response - Emitted before sending SOAP response. | ||
The signature of the callback is `function(response, methodName)`. | ||
* headers - Emitted when the SOAP Headers are not empty. | ||
@@ -671,3 +678,84 @@ The signature of the callback is `function(headers, methodName)`. | ||
## WSDL | ||
A WSDL instance can also be instantiated directly when you want to (un)marshal | ||
messages without doing SOAP calls. This can be used when a WSDL does not contain | ||
bindings for services (e.g. some Windows Communication Foundation SOAP web | ||
services). | ||
## WSDL.constructor(wsdl, baseURL, options): | ||
Construct a WSDL instance from either the WSDL content or the URL to the WSDL. | ||
#### Parameters | ||
- wsdl: A string wSDL or an URL to the WSDL | ||
- baseURL: base URL for the SOAP API | ||
- options: options (see source for details), use `{}` as default. | ||
### wsdl.xmlToObject(xml): | ||
Unmarshal XML to object. | ||
#### Parameters: | ||
- xml: SOAP response (XML) to unmarshal | ||
#### Returns: | ||
Object containing the object types from the xml as keys. | ||
### wsdl.objectToXML(object, typeName, namespacePrefix, namespaceURI, ...): | ||
Marshal an object to XML | ||
#### Parameters: | ||
- object: Object to marshal | ||
- typeName: type (as per the wsdl) of the object | ||
- namespacePrefix: namespace prefix | ||
- namespaceURI: URI of the namespace | ||
#### Returns: | ||
XML representation of object. | ||
#### Example: | ||
```typescript | ||
// Abstracted from a real use case | ||
import { AxiosInstance } from 'axios'; | ||
import { WSDL } from 'soap'; | ||
import { IProspectType } from './types'; | ||
// A WSDL in a string. | ||
const WSSDL_CONTENT = "..."; | ||
const httpClient: AxiosInstance = /* ... instantiate ... */; | ||
const url = 'http://example.org/SoapService.svc'; | ||
const wsdl = new WSDL(WSDL_CONTENT, baseURL, {}); | ||
async function sampleGetCall(): IProspectType | undefined { | ||
const res = await httpClient.get(`${baseURL}/GetProspect`); | ||
const object = wsdl.xmlToObject(res.data); | ||
if (!object.ProspectType) { | ||
// Response did not contain the expected type | ||
return undefined; | ||
} | ||
// Optionally, unwrap and set defaults for some fields | ||
// Ensure that the object meets the expected prototype | ||
// Finally cast and return the result. | ||
return object.ProspectType as IProspectType; | ||
} | ||
async function samplePostCall(prospect: IProspectType) { | ||
// objectToXML(object, typeName, namespacePrefix, namespaceURI, ...) | ||
const objectBody = wsdl.objectToXML(obj, 'ProspectType', '', ''); | ||
const data = `<?xml version="1.0" ?>${body}`; | ||
const res = await httpClient.post(`${baseURL}/ProcessProspect`, data); | ||
// Optionally, deserialize request and return response status. | ||
} | ||
``` | ||
## Security | ||
@@ -674,0 +762,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
424446
5526
1196