Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

rets-client

Package Overview
Dependencies
Maintainers
2
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rets-client - npm Package Compare versions

Comparing version 4.6.11 to 5.0.0

34

CHANGELOG.md

@@ -0,4 +1,31 @@

#### 5.0
A significant amount of internal cleanup, resulting in more consistent code and API. There are some minor breaking
changes, but they're small enough that migrating to 5.0 shouldn't be much effort. The
[Example Usage](https://github.com/sbruno81/rets-client#example-usage) has been updated to show 5.x patterns.
- object stream queries now have events with a `type` field to make discrimination easier, with the following
possibilities:
- `dataStream`, for a stream containing an object's raw data
- `location`, when no stream is available but a URL is available in the `headerInfo` (as per the `Location: 1` option)
- `headerInfo`, with the headers for the outer multipart response
- `error`, for an error corresponding to a single object rather than the stream as a whole
- search stream queries now return an object with a `retsStream` field rather than the bare stream
- the `searchRets` method now returns an object with a `rawStream` field rather than the bare stream
- headerInfo is now available on every query made
- login and logout set `client.loginHeaderInfo` and `client.logoutHeaderInfo`
- every streaming query will include an event with `type: 'headerInfo'`
- every buffered query (and most streaming queries) will return an object including a `headerInfo` field
- errors now consistently include response headers as well as the request options
- all calls made to the RETS server now obey `settings.method` for POST vs GET
#### 4.6.0
Added support for `Location: 1` option on `getObject` calls.
#### 4.5.0
Added a new error class for RETS permissions problems on login.
#### 4.4.0
Added a new `parserEncoding` param for `client.search.query()` and `client.search.stream.query()` calls, defaulting to
UTF-8.
Added a new `parserEncoding` param for `client.search.query()` and `client.search.stream.query()` calls. UTF-8 is the
default value, so this is to support RETS servers using ISO-8859-1 or some other encoding.

@@ -12,5 +39,4 @@ #### 4.3.0

#### 4.1.0
Added client configuration option to use POST instead of GET for all requests, as this seems to work better for some
RETS servers.
RETS servers. See the [Example Usage](https://github.com/sbruno81/rets-client#client-configuration).

@@ -17,0 +43,0 @@ #### 4.0.0

24

dist/client.js

@@ -89,13 +89,13 @@ // Generated by CoffeeScript 1.10.0

this.baseRetsSession = request.defaults(defaults);
this.loginRequest = Promise.promisify(this.baseRetsSession.defaults({
uri: this.settings.loginUrl
}));
}
Client.prototype.login = function() {
var options;
options = {
uri: this.settings.loginUrl
};
return auth.login(this.baseRetsSession.defaults(options), this).then((function(_this) {
return function(systemData) {
return auth.login(this.loginRequest, this).then((function(_this) {
return function(retsContext) {
var hasPermissions, key, missingPermissions, val;
_this.systemData = systemData;
_this.systemData = retsContext.systemData;
_this.loginHeaderInfo = retsContext.headerInfo;
_this.urls = {};

@@ -134,5 +134,5 @@ for (key in URL_KEYS) {

}
_this.logoutRequest = _this.baseRetsSession.defaults({
_this.logoutRequest = Promise.promisify(_this.baseRetsSession.defaults({
uri: _this.urls[URL_KEYS.LOGOUT]
});
}));
if (!hasPermissions) {

@@ -147,3 +147,7 @@ throw new errors.RetsPermissionError(missingPermissions);

Client.prototype.logout = function() {
return auth.logout(this.logoutRequest);
return auth.logout(this.logoutRequest, this).then((function(_this) {
return function(retsContext) {
return _this.logoutHeaderInfo = retsContext.headerInfo;
};
})(this));
};

@@ -150,0 +154,0 @@

@@ -25,7 +25,10 @@ // Generated by CoffeeScript 1.10.0

_getMetadataImpl = function(retsSession, type, options, client) {
_getMetadataImpl = function(retsSession, type, queryOptions, client) {
return new Promise(function(resolve, reject) {
var context, currEntry, result;
context = retsParsing.getStreamParser('getMetadata', type);
retsHttp.streamRetsMethod('getMetadata', retsSession, options, context.fail, context.response, client).pipe(context.parser);
var currEntry, result, retsContext;
retsContext = retsParsing.getStreamParser({
retsMethod: 'getMetadata',
queryOptions: queryOptions
}, type);
retsHttp.streamRetsMethod(retsContext, retsSession, client);
result = {

@@ -36,3 +39,3 @@ results: [],

currEntry = null;
return context.retsStream.pipe(through2.obj(function(event, encoding, callback) {
return retsContext.retsStream.pipe(through2.obj(function(event, encoding, callback) {
var key, ref, ref1, value;

@@ -96,3 +99,3 @@ switch (event.type) {

return function() {
var options;
var queryOptions;
if (!type) {

@@ -104,3 +107,3 @@ throw new errors.RetsParamError('Metadata type is required');

}
options = {
queryOptions = {
Type: type,

@@ -110,3 +113,6 @@ ID: id,

};
return retsHttp.callRetsMethod('getMetadata', _this.retsSession, options);
return retsHttp.callRetsMethod({
retsMethod: 'getMetadata',
queryOptions: queryOptions
}, _this.retsSession, _this.client);
};

@@ -122,7 +128,7 @@ })(this));

getSystem = function() {
return this.getMetadata('METADATA-SYSTEM', '0').then(function(xmlResponse) {
return this.getMetadata('METADATA-SYSTEM', '0').then(function(retsContext) {
return new Promise(function(resolve, reject) {
var comment, comments, gotMetaDataInfo, gotSystemInfo, result, retsParser;
result = {};
retsParser = retsParsing.getSimpleParser('getMetadata', reject, xmlResponse.headerInfo);
retsParser = retsParsing.getSimpleParser(retsContext, reject);
gotMetaDataInfo = false;

@@ -164,3 +170,3 @@ gotSystemInfo = false;

if (!gotSystemInfo || !gotMetaDataInfo) {
return reject(new errors.RetsProcessingError('getSystem', 'Failed to parse data'));
return reject(new errors.RetsProcessingError(retsContext, 'Failed to parse data'));
} else {

@@ -170,6 +176,7 @@ if (comments.length > 0) {

}
result.headerInfo = retsContext.headerInfo;
return resolve(result);
}
});
retsParser.parser.write(xmlResponse.body);
retsParser.parser.write(retsContext.body);
return retsParser.parser.end();

@@ -176,0 +183,0 @@ });

@@ -170,4 +170,2 @@ // Generated by CoffeeScript 1.10.0

return {
retsSession: _retsSession,
client: _client,
getObjects: getObjects,

@@ -174,0 +172,0 @@ getAllObjects: getAllObjects,

@@ -34,20 +34,21 @@ // Generated by CoffeeScript 1.10.0

_processBody = function(headers, bodyStream, preDecoded, options) {
_processBody = function(retsContext, preDecoded) {
return new Promise(function(resolve, reject) {
var b64, headerInfo, onError, ref, retsParser;
headerInfo = headersHelper.processHeaders(headers);
var b64, onError, ref, retsParser;
onError = function(error) {
return reject(errors.ensureRetsError('getObject', error, headerInfo));
return reject(errors.ensureRetsError(retsContext, error));
};
if (headerInfo.location && options.Location === 1) {
if (retsContext.headerInfo.location && retsContext.queryOptions.Location === 1) {
return resolve({
headerInfo: headerInfo
type: 'location',
headerInfo: retsContext.headerInfo
});
} else if (_insensitiveStartsWith(headerInfo.contentType, 'text/xml')) {
retsParser = retsParsing.getSimpleParser('getObject', onError, headerInfo);
return bodyStream.pipe(retsParser.parser);
} else if (_insensitiveStartsWith(headerInfo.contentType, 'multipart')) {
return multipart.getObjectStream(headerInfo, bodyStream, _processBody, options).then(function(objectStream) {
} else if (_insensitiveStartsWith(retsContext.headerInfo.contentType, 'text/xml')) {
retsParser = retsParsing.getSimpleParser(retsContext, onError);
return retsContext.parser.pipe(retsParser.parser);
} else if (_insensitiveStartsWith(retsContext.headerInfo.contentType, 'multipart')) {
return multipart.getObjectStream(retsContext, _processBody).then(function(objectStream) {
return resolve({
headerInfo: headerInfo,
type: 'objectStream',
headerInfo: retsContext.headerInfo,
objectStream: objectStream

@@ -59,20 +60,23 @@ });

} else {
if (preDecoded || ((ref = headerInfo.transferEncoding) === 'binary' || ref === '7bit' || ref === '8bit' || ref === (void 0))) {
if (preDecoded || ((ref = retsContext.headerInfo.transferEncoding) === 'binary' || ref === '7bit' || ref === '8bit' || ref === (void 0))) {
return resolve({
headerInfo: headerInfo,
dataStream: bodyStream
type: 'dataStream',
headerInfo: retsContext.headerInfo,
dataStream: retsContext.parser
});
} else if (headerInfo.transferEncoding === 'base64') {
} else if (retsContext.headerInfo.transferEncoding === 'base64') {
b64 = base64.decode();
bodyStream.on('error', function(err) {
return b64.emit('error', errors.ensureRetsError('getObject', err, headerInfo));
retsContext.parser.on('error', function(err) {
return b64.emit('error', errors.ensureRetsError(retsContext, err));
});
return resolve({
headerInfo: headerInfo,
dataStream: bodyStream.pipe(b64)
type: 'dataStream',
headerInfo: retsContext.headerInfo,
dataStream: retsContext.parser.pipe(b64)
});
} else {
return resolve({
headerInfo: headerInfo,
error: new errors.RetsProcessingError('getObject', "unknown transfer encoding: " + (JSON.stringify(headerInfo.transferEncoding)), headerInfo)
type: 'error',
headerInfo: retsContext.headerInfo,
error: new errors.RetsProcessingError(retsContext, "unknown transfer encoding: " + (JSON.stringify(retsContext.headerInfo.transferEncoding)))
});

@@ -152,3 +156,3 @@ }

return function() {
var alwaysGroupObjects, idArray, idString, mainOptions, objectIds, options, resourceId;
var alwaysGroupObjects, idArray, idString, mainOptions, objectIds, queryOptions, resourceId;
if (!resourceType) {

@@ -188,31 +192,30 @@ throw new errors.RetsParamError('Resource type id is required');

};
options = queryOptionHelpers.mergeOptions(mainOptions, _options, {
queryOptions = queryOptionHelpers.mergeOptions(mainOptions, _options, {
Location: 0
});
if (Array.isArray(options.ObjectData)) {
options.ObjectData = options.ObjectData.join(',');
if (Array.isArray(queryOptions.ObjectData)) {
queryOptions.ObjectData = queryOptions.ObjectData.join(',');
}
alwaysGroupObjects = !!options.alwaysGroupObjects;
delete options.alwaysGroupObjects;
alwaysGroupObjects = !!queryOptions.alwaysGroupObjects;
delete queryOptions.alwaysGroupObjects;
return new Promise(function(resolve, reject) {
var bodyStream, done, fail, req;
done = false;
fail = function(error) {
done = true;
return reject(errors.ensureRetsError('getObject', error));
var errorHandler, responseHandler, retsContext;
errorHandler = function(error) {
return reject(errors.ensureRetsError(retsContext, error));
};
req = retsHttp.streamRetsMethod('getObject', _this.retsSession, options, fail, null, _this.client);
req.on('error', fail);
req.on('response', function(response) {
if (done) {
return;
}
done = true;
return _processBody(response.rawHeaders, bodyStream, true, options).then(function(result) {
responseHandler = function(response) {
return _processBody(retsContext, true).then(function(result) {
return resolve(result);
})["catch"](function(error) {
return fail(error);
return errorHandler(error);
});
});
return bodyStream = req.pipe(through2());
};
retsContext = {
retsMethod: 'getObject',
queryOptions: queryOptions,
errorHandler: errorHandler,
responseHandler: responseHandler,
parser: through2()
};
return retsHttp.streamRetsMethod(retsContext, _this.retsSession, _this.client);
}).then(function(result) {

@@ -224,5 +227,10 @@ var wrappedResult;

wrappedResult = {
type: 'objectStream',
headerInfo: result.headerInfo,
objectStream: through2.obj()
};
wrappedResult.objectStream.write({
type: 'headerInfo',
headerInfo: result.headerInfo
});
wrappedResult.objectStream.write(result);

@@ -242,4 +250,4 @@ wrappedResult.objectStream.end();

getAllObjects = function(resourceType, objectType, ids, options) {
return this.getObjects(resourceType, objectType, _annotateIds(ids, '*'), options);
getAllObjects = function(resourceType, objectType, ids, queryOptions) {
return this.getObjects(resourceType, objectType, _annotateIds(ids, '*'), queryOptions);
};

@@ -253,4 +261,4 @@

getPreferredObjects = function(resourceType, objectType, ids, options) {
return this.getObjects(resourceType, objectType, _annotateIds(ids, '0'), options);
getPreferredObjects = function(resourceType, objectType, ids, queryOptions) {
return this.getObjects(resourceType, objectType, _annotateIds(ids, '0'), queryOptions);
};

@@ -257,0 +265,0 @@

@@ -48,9 +48,15 @@ // Generated by CoffeeScript 1.10.0

searchRets = function(queryOptions) {
searchRets = function(_queryOptions) {
return Promise["try"]((function(_this) {
return function() {
var finalQueryOptions;
finalQueryOptions = queryOptionHelpers.normalizeOptions(queryOptions);
return retsHttp.callRetsMethod('search', _this.retsSession, finalQueryOptions).then(function(result) {
return result.body;
var queryOptions;
queryOptions = queryOptionHelpers.normalizeOptions(_queryOptions);
return retsHttp.callRetsMethod({
retsMethod: 'search',
queryOptions: queryOptions
}, _this.retsSession, _this.client).then(function(retsContext) {
return {
text: retsContext.body,
headerInfo: retsContext.headerInfo
};
});

@@ -93,3 +99,3 @@ };

return function(resolve, reject) {
var currEntry, result;
var currEntry, result, retsContext;
result = {

@@ -100,3 +106,4 @@ results: [],

currEntry = null;
return _this.stream.query(resourceType, classType, queryString, options, null, parserEncoding).pipe(through2.obj(function(event, encoding, callback) {
retsContext = _this.stream.query(resourceType, classType, queryString, options, null, parserEncoding);
return retsContext.retsStream.pipe(through2.obj(function(event, encoding, callback) {
var key, ref, ref1, value;

@@ -125,2 +132,3 @@ switch (event.type) {

}
result.headerInfo = retsContext.headerInfo;
resolve(result);

@@ -127,0 +135,0 @@ break;

@@ -41,17 +41,18 @@ // Generated by CoffeeScript 1.10.0

searchRets = function(queryOptions, headerInfoCallback) {
searchRets = function(_options, responseHandler) {
return Promise["try"]((function(_this) {
return function() {
var finalQueryOptions, httpStream, onError, resultStream;
finalQueryOptions = queryOptionHelpers.normalizeOptions(queryOptions);
resultStream = through2();
onError = function(err) {
httpStream.unpipe(resultStream);
return resultStream.emit('error', err);
};
if (!headerInfoCallback) {
headerInfoCallback = function() {};
}
httpStream = retsHttp.streamRetsMethod('search', _this.retsSession, finalQueryOptions, onError, headerInfoCallback, _this.client);
return httpStream.pipe(resultStream);
var queryOptions;
queryOptions = queryOptionHelpers.normalizeOptions(_options);
return retsHttp.streamRetsMethod({
retsMethod: 'search',
queryOptions: queryOptions,
responseHandler: responseHandler,
parser: through2()
}, _this.retsSession, _this.client).then(function(retsContext) {
return {
headerInfo: retsContext.headerInfo,
rawStream: retsContext.parser
};
});
};

@@ -85,6 +86,6 @@ })(this));

query = function(resourceType, classType, queryString, options, rawData, parserEncoding) {
var baseOpts, context, finalQueryOptions, queryOptions;
if (options == null) {
options = {};
query = function(resourceType, classType, queryString, _options, rawData, parserEncoding) {
var baseOpts, mainOptions, queryOptions, retsContext;
if (_options == null) {
_options = {};
}

@@ -102,9 +103,15 @@ if (rawData == null) {

};
queryOptions = queryOptionHelpers.mergeOptions(baseOpts, options);
delete queryOptions.queryType;
delete queryOptions.format;
finalQueryOptions = queryOptionHelpers.normalizeOptions(queryOptions);
context = retsParsing.getStreamParser('search', null, rawData, parserEncoding);
retsHttp.streamRetsMethod('search', this.retsSession, finalQueryOptions, context.fail, context.response, this.client).pipe(context.parser);
return context.retsStream;
mainOptions = queryOptionHelpers.mergeOptions(baseOpts, _options);
delete mainOptions.queryType;
delete mainOptions.format;
queryOptions = queryOptionHelpers.normalizeOptions(mainOptions);
retsContext = retsParsing.getStreamParser({
retsMethod: 'search',
queryOptions: queryOptions
}, null, rawData, parserEncoding);
retsHttp.streamRetsMethod(retsContext, this.retsSession, this.client);
return {
headerInfo: retsContext.headerInfo,
retsStream: retsContext.retsStream
};
};

@@ -111,0 +118,0 @@

@@ -28,14 +28,16 @@ // Generated by CoffeeScript 1.10.0

login = function(retsSession, client) {
return retsHttp.callRetsMethod('login', Promise.promisify(retsSession), {}).then(function(retsResponse) {
return retsHttp.callRetsMethod({
retsMethod: 'login',
queryOptions: {}
}, retsSession, client).then(function(retsContext) {
return new Promise(function(resolve, reject) {
var gotData, headerCookie, headerCookies, headers, i, len, matches, retsParser, systemData, typeIsArray;
headers = headersHelper.processHeaders(retsResponse.response.rawHeaders);
if (client.settings.userAgentPassword && headers.setCookie) {
var gotData, headerCookie, headerCookies, i, len, matches, retsParser, systemData, typeIsArray;
if (client.settings.userAgentPassword && retsContext.headerInfo.setCookie) {
typeIsArray = Array.isArray || function(value) {
return {}.toString.call(value) === '[object Array]';
};
if (typeIsArray(headers.setCookie)) {
headerCookies = headers.setCookie;
if (typeIsArray(retsContext.headerInfo.setCookie)) {
headerCookies = retsContext.headerInfo.setCookie;
} else {
headerCookies = [headers.setCookie];
headerCookies = [retsContext.headerInfo.setCookie];
}

@@ -51,7 +53,4 @@ for (i = 0, len = headerCookies.length; i < len; i++) {

}
systemData = {
retsVersion: headers.retsVersion,
retsServer: headers.server
};
retsParser = retsParsing.getSimpleParser('login', reject, headers);
retsParser = retsParsing.getSimpleParser(retsContext, reject);
systemData = {};
gotData = false;

@@ -83,8 +82,11 @@ retsParser.parser.on('text', function(text) {

if (!gotData) {
return reject(new errors.RetsProcessingError('login', 'Failed to parse data', headers));
return reject(new errors.RetsProcessingError(retsContext, 'Failed to parse data'));
} else {
return resolve(systemData);
return resolve({
systemData: systemData,
headerInfo: retsContext.headerInfo
});
}
});
retsParser.parser.write(retsResponse.body);
retsParser.parser.write(retsContext.body);
return retsParser.parser.end();

@@ -100,4 +102,11 @@ });

logout = function(retsSession) {
return retsHttp.callRetsMethod('logout', Promise.promisify(retsSession), {});
logout = function(retsSession, client) {
return retsHttp.callRetsMethod({
retsMethod: 'logout',
queryOptions: {}
}, retsSession, client).then(function(retsContext) {
return {
headerInfo: retsContext.headerInfo
};
});
};

@@ -104,0 +113,0 @@

@@ -52,4 +52,3 @@ // Generated by CoffeeScript 1.10.0

function RetsReplyError(retsMethod1, replyCode, replyText, _headerInfo) {
this.retsMethod = retsMethod1;
function RetsReplyError(retsContext, replyCode, replyText) {
this.replyCode = replyCode;

@@ -59,4 +58,4 @@ this.replyText = replyText;

this.replyTag = replyCodes.tagMap[this.replyCode] != null ? replyCodes.tagMap[this.replyCode] : 'unknown reply code';
this.retsMethod = retsContext.retsMethod, this.queryOptions = retsContext.queryOptions, this.headerInfo = retsContext.headerInfo;
this.message = "RETS Server reply while attempting " + this.retsMethod + " - ReplyCode " + this.replyCode + " (" + this.replyTag + "); ReplyText: " + this.replyText;
this.headerInfo = headersHelper.processHeaders(_headerInfo);
Error.captureStackTrace(this, RetsReplyError);

@@ -72,9 +71,8 @@ }

function RetsServerError(retsMethod1, httpStatus, httpStatusMessage, _headerInfo) {
this.retsMethod = retsMethod1;
function RetsServerError(retsContext, httpStatus, httpStatusMessage) {
this.httpStatus = httpStatus;
this.httpStatusMessage = httpStatusMessage;
this.name = 'RetsServerError';
this.retsMethod = retsContext.retsMethod, this.queryOptions = retsContext.queryOptions, this.headerInfo = retsContext.headerInfo;
this.message = "RETS Server error while attempting " + this.retsMethod + " - HTTP Status " + this.httpStatus + " returned (" + this.httpStatusMessage + ")";
this.headerInfo = headersHelper.processHeaders(_headerInfo);
Error.captureStackTrace(this, RetsServerError);

@@ -90,8 +88,7 @@ }

function RetsProcessingError(retsMethod1, sourceError, _headerInfo) {
this.retsMethod = retsMethod1;
function RetsProcessingError(retsContext, sourceError) {
this.sourceError = sourceError;
this.name = 'RetsProcessingError';
this.retsMethod = retsContext.retsMethod, this.queryOptions = retsContext.queryOptions, this.headerInfo = retsContext.headerInfo;
this.message = "Error while processing RETS response for " + this.retsMethod + " - " + (getErrorMessage(this.sourceError));
this.headerInfo = headersHelper.processHeaders(_headerInfo);
Error.captureStackTrace(this, RetsProcessingError);

@@ -136,7 +133,7 @@ }

ensureRetsError = function(retsMethod, error, headerInfo) {
ensureRetsError = function(retsContext, error) {
if (error instanceof RetsError) {
return error;
} else {
return new RetsProcessingError(retsMethod, error, headerInfo);
return new RetsProcessingError(retsContext, error);
}

@@ -143,0 +140,0 @@ };

@@ -10,3 +10,3 @@ // Generated by CoffeeScript 1.10.0

'use strict';
var MultipartParser, Promise, debug, debugVerbose, errors, getObjectStream, retsParsing, through2;
var MultipartParser, Promise, debug, debugVerbose, errors, getObjectStream, headersHelper, retsParsing, through2;

@@ -27,14 +27,20 @@ MultipartParser = require('formidable/lib/multipart_parser').MultipartParser;

getObjectStream = function(headerInfo, stream, handler, options) {
headersHelper = require('./headers');
getObjectStream = function(retsContext, handler) {
return new Promise(function(resolve, reject) {
var bodyStream, done, flush, flushed, handleEnd, handleError, headerField, headerValue, headers, interceptor, multipartBoundary, objectStream, parser, partDone, ref, ref1, streamError;
multipartBoundary = (ref = headerInfo.contentType.match(/boundary="[^"]+"/ig)) != null ? ref[0].slice('boundary="'.length, -1) : void 0;
multipartBoundary = (ref = retsContext.headerInfo.contentType.match(/boundary="[^"]+"/ig)) != null ? ref[0].slice('boundary="'.length, -1) : void 0;
if (!multipartBoundary) {
multipartBoundary = (ref1 = headerInfo.contentType.match(/boundary=[^;]+/ig)) != null ? ref1[0].slice('boundary='.length) : void 0;
multipartBoundary = (ref1 = retsContext.headerInfo.contentType.match(/boundary=[^;]+/ig)) != null ? ref1[0].slice('boundary='.length) : void 0;
}
if (!multipartBoundary) {
throw new errors.RetsProcessingError('getObject', 'Could not find multipart boundary', headerInfo);
throw new errors.RetsProcessingError(retsContext, 'Could not find multipart boundary');
}
parser = new MultipartParser();
objectStream = through2.obj();
objectStream.write({
type: 'headerInfo',
headerInfo: retsContext.headerInfo
});
headerField = '';

@@ -59,3 +65,5 @@ headerValue = '';

err = {
error: err
type: 'error',
error: err,
headerInfo: retsContext.headerInfo
};

@@ -71,3 +79,3 @@ }

} else {
return debug("handleEnd not ready " + (JSON.stringify({
return debug("handleEnd not ready: " + (JSON.stringify({
done: done,

@@ -108,8 +116,15 @@ partDone: partDone,

parser.onHeadersEnd = function() {
var newRetsContext;
debug("onHeadersEnd: [" + (headers.length / 2) + " headers parsed]");
bodyStream = through2();
return handler(headers, bodyStream, false, options).then(function(object) {
newRetsContext = {
retsMethod: retsContext.retsMethod,
queryOptions: retsContext.queryOptions,
headerInfo: headersHelper.processHeaders(headers),
parser: bodyStream
};
return handler(newRetsContext, false).then(function(object) {
return objectStream != null ? objectStream.write(object) : void 0;
})["catch"](function(err) {
return handleError(errors.ensureRetsError('getObject', err, headers));
return handleError(errors.ensureRetsError(newRetsContext, err));
}).then(function() {

@@ -137,3 +152,3 @@ partDone = true;

parser.initWithBoundary(multipartBoundary);
stream.on('error', function(err) {
retsContext.parser.on('error', function(err) {
debug("stream error");

@@ -151,3 +166,3 @@ return handleError(err);

if (err) {
handleError(new errors.RetsProcessingError('getObject', "Unexpected end of data: " + (errors.getErrorMessage(err)), headerInfo));
handleError(new errors.RetsProcessingError(retsContext, "Unexpected end of data: " + (errors.getErrorMessage(err))));
}

@@ -158,3 +173,3 @@ flushed = true;

};
stream.pipe(through2(interceptor, flush));
retsContext.parser.pipe(through2(interceptor, flush));
return resolve(objectStream);

@@ -161,0 +176,0 @@ });

@@ -22,10 +22,15 @@ // Generated by CoffeeScript 1.10.0

callRetsMethod = function(methodName, retsSession, queryOptions) {
debug("RETS " + methodName + ":", queryOptions);
callRetsMethod = function(retsContext, promisifiedRetsSession, client) {
debug("RETS " + retsContext.retsMethod + ":", retsContext.queryOptions);
return Promise["try"](function() {
return retsSession({
qs: queryOptions
});
var request;
request = {};
if (client.settings.method === 'POST') {
request.form = retsContext.queryOptions;
} else {
request.qs = retsContext.queryOptions;
}
return promisifiedRetsSession(request);
})["catch"](function(error) {
debug("RETS " + methodName + " error:", error);
debug("RETS " + retsContext.retsMethod + " error:", error);
return Promise.reject(error);

@@ -35,17 +40,16 @@ }).spread(function(response, body) {

if (response.statusCode !== 200) {
error = new errors.RetsServerError(methodName, response.statusCode, response.statusMessage, response.rawHeaders);
debug("RETS " + methodName + " error: " + error.message);
error = new errors.RetsServerError(retsContext, response.statusCode, response.statusMessage);
debug("RETS " + retsContext.retsMethod + " error: " + error.message);
return Promise.reject(error);
}
return {
body: body,
response: response,
headerInfo: headersHelper.processHeaders(response.rawHeaders)
};
retsContext.headerInfo = headersHelper.processHeaders(response.rawHeaders);
retsContext.body = body;
retsContext.response = response;
return retsContext;
});
};
streamRetsMethod = function(methodName, retsSession, queryOptions, failCallback, responseCallback, client) {
streamRetsMethod = function(retsContext, regularRetsSession, client) {
var done, errorHandler, request, responseHandler, stream;
debug("RETS " + methodName + " (streaming)", queryOptions);
debug("RETS " + retsContext.retsMethod + " (streaming)", retsContext.queryOptions);
done = false;

@@ -57,4 +61,4 @@ errorHandler = function(error) {

done = true;
debug("RETS " + methodName + " (streaming) error:", error);
return failCallback(error);
debug("RETS " + retsContext.retsMethod + " (streaming) error:", error);
return retsContext.errorHandler(error);
};

@@ -67,8 +71,9 @@ responseHandler = function(response) {

done = true;
retsContext.headerInfo = headersHelper.processHeaders(response.rawHeaders);
if (response.statusCode !== 200) {
error = new errors.RetsServerError(methodName, response.statusCode, response.statusMessage, response.rawHeaders);
debug("RETS " + methodName + " (streaming) error: " + error.message);
return failCallback(error);
} else if (responseCallback) {
return responseCallback(response);
error = new errors.RetsServerError(retsContext, response.statusCode, response.statusMessage);
debug("RETS " + retsContext.retsMethod + " (streaming) error: " + error.message);
return typeof retsContext.errorHandler === "function" ? retsContext.errorHandler(error) : void 0;
} else {
return typeof retsContext.responseHandler === "function" ? retsContext.responseHandler(response) : void 0;
}

@@ -78,7 +83,7 @@ };

if (client.settings.method === 'POST') {
request.form = queryOptions;
request.form = retsContext.queryOptions;
} else {
request.qs = queryOptions;
request.qs = retsContext.queryOptions;
}
if (methodName === 'getObject') {
if (retsContext.retsMethod === 'getObject') {
request.headers = {

@@ -88,5 +93,7 @@ Accept: '*/*'

}
stream = retsSession(request);
stream = regularRetsSession(request);
stream.on('error', errorHandler);
return stream.on('response', responseHandler);
stream.on('response', responseHandler);
stream.pipe(retsContext.parser);
return retsContext;
};

@@ -93,0 +100,0 @@

@@ -24,3 +24,3 @@ // Generated by CoffeeScript 1.10.0

getSimpleParser = function(retsMethod, errCallback, headerInfo, parserEncoding) {
getSimpleParser = function(retsContext, errCallback, parserEncoding) {
var result;

@@ -41,3 +41,3 @@ if (parserEncoding == null) {

result.finish();
return errCallback(new errors.RetsProcessingError(retsMethod, 'Unexpected results. Please check the RETS URL.', headerInfo));
return errCallback(new errors.RetsProcessingError(retsContext, 'Unexpected results. Please check the RETS URL.'));
}

@@ -50,6 +50,10 @@ });

}
result.status = attrs;
result.status = {
replyCode: attrs.ReplyCode,
replyTag: replyCodes.tagMap[attrs.ReplyCode],
replyText: attrs.ReplyText
};
if (attrs.ReplyCode !== '0' && attrs.ReplyCode !== '20208') {
result.finish();
return errCallback(new errors.RetsReplyError(retsMethod, attrs.ReplyCode, attrs.ReplyText, headerInfo));
return errCallback(new errors.RetsReplyError(retsContext, attrs.ReplyCode, attrs.ReplyText));
}

@@ -59,7 +63,7 @@ });

result.finish();
return errCallback(new errors.RetsProcessingError(retsMethod, "XML parsing error: " + (errors.getErrorMessage(err)), headerInfo));
return errCallback(new errors.RetsProcessingError(retsContext, "XML parsing error: " + (errors.getErrorMessage(err))));
});
result.parser.on('end', function() {
result.finish();
return errCallback(new errors.RetsProcessingError(retsMethod, "Unexpected end of xml stream.", headerInfo));
return errCallback(new errors.RetsProcessingError(retsContext, "Unexpected end of xml stream."));
});

@@ -69,4 +73,4 @@ return result;

getStreamParser = function(retsMethod, metadataTag, rawData, parserEncoding) {
var columnText, columns, currElementName, dataText, delimiter, fail, finish, headers, parser, processStatus, response, result, retsStream, writeOutput;
getStreamParser = function(retsContext, metadataTag, rawData, parserEncoding) {
var columnText, columns, currElementName, dataText, delimiter, errorHandler, finish, headers, parser, processStatus, responseHandler, result, retsStream, writeOutput;
if (parserEncoding == null) {

@@ -108,3 +112,3 @@ parserEncoding = 'UTF-8';

};
fail = function(err) {
errorHandler = function(err) {
return finish('error', err);

@@ -118,5 +122,4 @@ };

};
response = function(response) {
headers = headersHelper.processHeaders(response.rawHeaders);
return writeOutput('headerInfo', headers);
responseHandler = function() {
return writeOutput('headerInfo', retsContext.headerInfo);
};

@@ -126,3 +129,3 @@ processStatus = function(attrs) {

if (attrs.ReplyCode !== '0' && attrs.ReplyCode !== '20208') {
return fail(new errors.RetsReplyError(retsMethod, attrs.ReplyCode, attrs.ReplyText, headers));
return errorHandler(new errors.RetsReplyError(retsContext, attrs.ReplyCode, attrs.ReplyText));
}

@@ -138,3 +141,3 @@ status = {

if (name !== 'RETS') {
return fail(new errors.RetsProcessingError(retsMethod, 'Unexpected results. Please check the RETS URL.', headers));
return errorHandler(new errors.RetsProcessingError(retsContext, 'Unexpected results. Please check the RETS URL.'));
}

@@ -200,3 +203,3 @@ processStatus(attrs);

if (!columns) {
return fail(new errors.RetsProcessingError(retsMethod, 'Failed to parse columns', headers));
return errorHandler(new errors.RetsProcessingError(retsContext, 'Failed to parse columns'));
}

@@ -214,3 +217,3 @@ data = dataText.split(delimiter);

if (!delimiter) {
return fail(new errors.RetsProcessingError(retsMethod, 'Failed to parse delimiter', headers));
return errorHandler(new errors.RetsProcessingError(retsContext, 'Failed to parse delimiter'));
}

@@ -231,13 +234,12 @@ columns = columnText.split(delimiter);

parser.on('error', function(err) {
return fail(new errors.RetsProcessingError(retsMethod, "XML parsing error: " + (errors.getErrorMessage(err)), headers));
return errorHandler(new errors.RetsProcessingError(retsContext, "XML parsing error: " + (errors.getErrorMessage(err))));
});
parser.on('end', function() {
return fail(new errors.RetsProcessingError(retsMethod, "Unexpected end of xml stream.", headers));
return errorHandler(new errors.RetsProcessingError(retsContext, "Unexpected end of xml stream."));
});
return {
parser: parser,
fail: fail,
retsStream: retsStream,
response: response
};
retsContext.parser = parser;
retsContext.errorHandler = errorHandler;
retsContext.responseHandler = responseHandler;
retsContext.retsStream = retsStream;
return retsContext;
};

@@ -244,0 +246,0 @@

{
"name": "rets-client",
"version": "4.6.11",
"version": "5.0.0",
"description": "A RETS client (Real Estate Transaction Standard).",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -8,26 +8,27 @@ rets-client

#### 4.6.0
Added support for `Location: 1` option on `getObject` calls.
#### 5.0
A significant amount of internal cleanup, resulting in more consistent code and API. There are some minor breaking
changes, but they're small enough that migrating to 5.0 shouldn't be much effort. The
[Example Usage](https://github.com/sbruno81/rets-client#example-usage) has been updated to show 5.x patterns.
#### 4.5.0
Added a new error class for RETS permissions problems on login.
- object stream queries now have events with a `type` field to make discrimination easier, with the following
possibilities:
- `dataStream`, for a stream containing an object's raw data
- `location`, when no stream is available but a URL is available in the `headerInfo` (as per the `Location: 1` option)
- `headerInfo`, with the headers for the outer multipart response
- `error`, for an error corresponding to a single object rather than the stream as a whole
- search stream queries now return an object with a `retsStream` field rather than the bare stream
- the `searchRets` method now returns an object with a `rawStream` field rather than the bare stream
- headerInfo is now available on every query made
- login and logout set `client.loginHeaderInfo` and `client.logoutHeaderInfo`
- every streaming query will include an event with `type: 'headerInfo'`
- every buffered query (and most streaming queries) will return an object including a `headerInfo` field
- errors now consistently include response headers as well as the request options
- all calls made to the RETS server now obey `settings.method` for POST vs GET
#### 4.4.0
Added a new `parserEncoding` param for `client.search.query()` and `client.search.stream.query()` calls. UTF-8 is the
default value, so this is to support RETS servers using ISO-8859-1 or some other encoding.
#### 4.3.0
Added support for TimeZoneOffset and Comments in the `metadata.getSystem()` call response.
#### 4.X and earlier
See [the changelog](./CHANGELOG.md) for earlier changes.
#### 4.2.0
Improved error handling and error classes. See the [error documentation](https://github.com/sbruno81/rets-client#errors).
#### 4.1.0
Added client configuration option to use POST instead of GET for all requests, as this seems to work better for some
RETS servers. See the [Example Usage](https://github.com/sbruno81/rets-client#client-configuration).
#### 4.0.0 and earlier
See [the changelog](./blob/master/CHANGELOG.md) for earlier changes.
## Implementation Notes

@@ -57,2 +58,3 @@

- create unit tests -- specifically ones that run off example RETS data rather than requiring access to a real RETS server
- refactor streaming API to correctly respond to backpressure

@@ -91,5 +93,8 @@

```javascript
function outputFields(obj, opts) {
function outputFields(obj, opts) {
if (!obj) {
console.log(" "+JSON.stringify(obj))
} else {
if (!opts) opts = {};
var excludeFields;

@@ -107,3 +112,3 @@ var loopFields;

}
for (var i=0; i<loopFields.length; i++) {
for (var i = 0; i < loopFields.length; i++) {
if (excludeFields.indexOf(loopFields[i]) != -1) {

@@ -113,9 +118,10 @@ continue;

if (typeof(obj[loopFields[i]]) == 'object') {
console.log(" "+loopFields[i]+": "+JSON.stringify(obj[loopFields[i]]));
console.log(" " + loopFields[i] + ": " + JSON.stringify(obj[loopFields[i]], null, 2).replace(/\n/g, '\n '));
} else {
console.log(" "+loopFields[i]+": "+obj[loopFields[i]]);
console.log(" " + loopFields[i] + ": " + JSON.stringify(obj[loopFields[i]]));
}
}
console.log("");
};
}
console.log("");
}
```

@@ -125,61 +131,73 @@

```javascript
var rets = require('rets-client');
var fs = require('fs');
var photoSourceId = '12345'; // <--- dummy example ID! this will usually be a MLS number / listing id
var rets = require('rets-client');
var fs = require('fs');
var photoSourceId = '12345'; // <--- dummy example ID! this will usually be a MLS number / listing id
// establish connection to RETS server which auto-logs out when we're done
rets.getAutoLogoutClient(clientSettings, function (client) {
console.log("===================================");
console.log("======== System Metadata ========");
console.log("===================================");
outputFields(client.systemData);
//get resources metadata
return client.metadata.getResources()
.then(function (data) {
console.log("======================================");
console.log("======== Resources Metadata ========");
console.log("======================================");
outputFields(data.results[0].info);
for (var dataItem = 0; dataItem < data.results[0].metadata.length; dataItem++) {
console.log("-------- Resource " + dataItem + " --------");
outputFields(data.results[0].metadata[dataItem], {fields: ['ResourceID', 'StandardName', 'VisibleName', 'ObjectVersion']});
}
}).then(function () {
//get class metadata
return client.metadata.getClass("Property");
}).then(function (data) {
console.log("===========================================================");
console.log("======== Class Metadata (from Property Resource) ========");
console.log("===========================================================");
outputFields(data.results[0].info);
for (var classItem = 0; classItem < data.results[0].metadata.length; classItem++) {
console.log("-------- Table " + classItem + " --------");
outputFields(data.results[0].metadata[classItem], {fields: ['ClassName', 'StandardName', 'VisibleName', 'TableVersion']});
}
}).then(function () {
//get field data for open houses
return client.metadata.getTable("Property", "RESIDENTIAL");
}).then(function (data) {
console.log("==============================================");
console.log("======== Residential Table Metadata ========");
console.log("===============================================");
outputFields(data.results[0].info);
for (var tableItem = 0; tableItem < data.results[0].metadata.length; tableItem++) {
console.log("-------- Field " + tableItem + " --------");
outputFields(data.results[0].metadata[tableItem], {fields: ['MetadataEntryID', 'SystemName', 'ShortName', 'LongName', 'DataType']});
}
return data.results[0].metadata
}).then(function (fieldsData) {
var plucked = [];
for (var fieldItem = 0; fieldItem < fieldsData.length; fieldItem++) {
plucked.push(fieldsData[fieldItem].SystemName);
}
return plucked;
}).then(function (fields) {
//perform a query using DMQL2 -- pass resource, class, and query, and options
return client.search.query("Property", "RESIDENTIAL", "(RecordModDate=2016-06-20+),(ActiveYN=1)", {limit:100, offset:10})
// establish connection to RETS server which auto-logs out when we're done
rets.getAutoLogoutClient(clientSettings, function (client) {
console.log("===================================");
console.log("======== System Metadata ========");
console.log("===================================");
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(client.loginHeaderInfo);
console.log(' ~~~~~~~~~ System Data ~~~~~~~~~');
outputFields(client.systemData);
//get resources metadata
return client.metadata.getResources()
.then(function (data) {
console.log("======================================");
console.log("======== Resources Metadata ========");
console.log("======================================");
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(data.headerInfo);
console.log(' ~~~~~~ Resources Metadata ~~~~~');
outputFields(data.results[0].info);
for (var dataItem = 0; dataItem < data.results[0].metadata.length; dataItem++) {
console.log(" -------- Resource " + dataItem + " --------");
outputFields(data.results[0].metadata[dataItem], {fields: ['ResourceID', 'StandardName', 'VisibleName', 'ObjectVersion']});
}
}).then(function () {
//get class metadata
return client.metadata.getClass("Property");
}).then(function (data) {
console.log("===========================================================");
console.log("======== Class Metadata (from Property Resource) ========");
console.log("===========================================================");
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(data.headerInfo);
console.log(' ~~~~~~~~ Class Metadata ~~~~~~~');
outputFields(data.results[0].info);
for (var classItem = 0; classItem < data.results[0].metadata.length; classItem++) {
console.log(" -------- Table " + classItem + " --------");
outputFields(data.results[0].metadata[classItem], {fields: ['ClassName', 'StandardName', 'VisibleName', 'TableVersion']});
}
}).then(function () {
//get field data for open houses
return client.metadata.getTable("Property", "RESIDENTIAL");
}).then(function (data) {
console.log("==============================================");
console.log("======== Residential Table Metadata ========");
console.log("===============================================");
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(data.headerInfo);
console.log(' ~~~~~~~~ Table Metadata ~~~~~~~');
outputFields(data.results[0].info);
for (var tableItem = 0; tableItem < data.results[0].metadata.length; tableItem++) {
console.log(" -------- Field " + tableItem + " --------");
outputFields(data.results[0].metadata[tableItem], {fields: ['MetadataEntryID', 'SystemName', 'ShortName', 'LongName', 'DataType']});
}
return data.results[0].metadata
}).then(function (fieldsData) {
var plucked = [];
for (var fieldItem = 0; fieldItem < fieldsData.length; fieldItem++) {
plucked.push(fieldsData[fieldItem].SystemName);
}
return plucked;
}).then(function (fields) {
//perform a query using DMQL2 -- pass resource, class, and query, and options
return client.search.query("Property", "RESIDENTIAL", "(RecordModDate=2016-06-20+),(ActiveYN=1)", {limit:100, offset:10})
.then(function (searchData) {

@@ -189,38 +207,44 @@ console.log("=============================================");

console.log("=============================================");
outputFields(searchData, {exclude: ['results']});
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(searchData.headerInfo);
console.log(' ~~~~~~~~~~ Query Info ~~~~~~~~~');
outputFields(searchData, {exclude: ['results','headerInfo']});
//iterate through search results
for (var dataItem = 0; dataItem < searchData.results.length; dataItem++) {
console.log("-------- Result " + dataItem + " --------");
console.log(" -------- Result " + dataItem + " --------");
outputFields(searchData.results[dataItem], {fields: fields});
}
if (searchData.maxRowsExceeded) {
console.log("-------- More rows available!");
console.log(" -------- More rows available!");
}
});
}).then(function () {
// get photos
return client.objects.getAllObjects("Property", "LargePhoto", photoSourceId, {alwaysGroupObjects: true, ObjectData: '*'})
}).then(function (photoResults) {
console.log("=================================");
console.log("======== Photo Results ========");
console.log("=================================");
for (var i = 0; i < photoResults.objects.length; i++) {
if (photoResults.objects[i].error) {
console.log("Photo " + (i + 1) + " had an error: " + photoResults.objects[i].error);
} else {
console.log("Photo " + (i + 1) + ":");
outputFields(photoResults.objects[i].headerInfo);
fs.writeFileSync(
"/tmp/photo" + (i + 1) + "." + photoResults.objects[i].headerInfo.contentType.match(/\w+\/(\w+)/i)[1],
photoResults.objects[i].data);
}
console.log("---------------------------------");
}).then(function () {
// get photos
return client.objects.getAllObjects("Property", "LargePhoto", photoSourceId, {alwaysGroupObjects: true, ObjectData: '*'})
}).then(function (photoResults) {
console.log("=================================");
console.log("======== Photo Results ========");
console.log("=================================");
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(photoResults.headerInfo);
for (var i = 0; i < photoResults.objects.length; i++) {
console.log(" -------- Photo " + (i + 1) + " --------");
if (photoResults.objects[i].error) {
console.log(" Error: " + photoResults.objects[i].error);
} else {
outputFields(photoResults.objects[i].headerInfo);
fs.writeFileSync(
"/tmp/photo" + (i + 1) + "." + photoResults.objects[i].headerInfo.contentType.match(/\w+\/(\w+)/i)[1],
photoResults.objects[i].data);
}
});
}).catch(function (errorInfo) {
var error = errorInfo.error || errorInfo;
console.log("ERROR: issue encountered: "+(error.stack||error));
});
}
});
}).catch(function (errorInfo) {
var error = errorInfo.error || errorInfo;
console.log(" ERROR: issue encountered:");
outputFields(error);
console.log(' '+(error.stack||error).replace(/\n/g, '\n '));
});
```

@@ -230,55 +254,66 @@

```javascript
var rets = require('rets-client');
var through2 = require('through2');
var Promise = require('bluebird');
var rets = require('rets-client');
var through2 = require('through2');
var Promise = require('bluebird');
// this function doesn't do much, it's just a placeholder for whatever you want to do with the results
function doAsyncProcessing(row, index, callback) {
console.log("-------- Result " + index + " --------");
outputFields(row);
// must be sure callback is called when this is done
callback();
}
// establish connection to RETS server which auto-logs out when we're done
rets.getAutoLogoutClient(clientSettings, function (client) {
// in order to have the auto-logout function work properly, we need to make a promise that either rejects or
// resolves only once we're done processing the stream
return new Promise(function (resolve, reject) {
console.log("====================================");
console.log("======== Streamed Results ========");
console.log("====================================");
var count = 0;
var retsStream = client.search.stream.query("OpenHouse", "OPENHOUSE", "(OpenHouseType=PUBLIC),(ActiveYN=1)", {limit:100, offset:10});
var processorStream = through2.obj(function (event, encoding, callback) {
switch (event.type) {
case 'data':
// event.payload is an object representing a single row of results
// make sure callback is called only when all processing is complete
count++;
doAsyncProcessing(event.payload, count, callback);
break;
case 'done':
// event.payload is an object containing a count of rows actually received, plus some other things
// now we can resolve the auto-logout promise
resolve(event.payload.rowsReceived);
callback();
break;
case 'error':
// event.payload is an Error object
console.log('Error streaming RETS results: '+event.payload);
retsStream.unpipe(processorStream);
processorStream.end();
// we need to reject the auto-logout promise
reject(event.payload);
callback();
break;
default:
// ignore other events
callback();
}
});
retsStream.pipe(processorStream);
// this function doesn't do much, it's just a placeholder for whatever you want to do with the results
function doAsyncProcessing(row, index, callback) {
console.log("-------- Result " + index + " --------");
outputFields(row);
// must be sure callback is called when this is done
callback();
}
// establish connection to RETS server which auto-logs out when we're done
rets.getAutoLogoutClient(clientSettings, function (client) {
// in order to have the auto-logout function work properly, we need to make a promise that either rejects or
// resolves only once we're done processing the stream
return new Promise(function (resolve, reject) {
console.log("====================================");
console.log("======== Streamed Results ========");
console.log("====================================");
var count = 0;
var streamResult = client.search.stream.query("Property", "RES", "(LastChangeTimestamp=2016-06-20+)", {limit:10, offset:4});
var processorStream = through2.obj(function (event, encoding, callback) {
switch (event.type) {
case 'headerInfo':
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(event.payload);
callback();
break;
case 'data':
// event.payload is an object representing a single row of results
// make sure callback is called only when all processing is complete
count++;
doAsyncProcessing(event.payload, count, callback);
break;
case 'done':
// event.payload is an object containing a count of rows actually received, plus some other things
// now we can resolve the auto-logout promise
resolve(event.payload.rowsReceived);
callback();
break;
case 'error':
// event.payload is an Error object
console.log('Error streaming RETS results: '+event.payload);
streamResult.retsStream.unpipe(processorStream);
processorStream.end();
// we need to reject the auto-logout promise
reject(event.payload);
callback();
break;
default:
// ignore other events
callback();
}
});
streamResult.retsStream.pipe(processorStream);
});
}).catch(function (errorInfo) {
var error = errorInfo.error || errorInfo;
console.log(" ERROR: issue encountered:");
outputFields(error);
console.log(' '+(error.stack||error).replace(/\n/g, '\n '));
});
```

@@ -288,27 +323,44 @@

```javascript
var rets = require('rets-client');
// establish connection to RETS server which auto-logs out when we're done
rets.getAutoLogoutClient(clientSettings, function (client) {
// getObjects will accept a single string, an array of strings, or an object as shown below
var photoIds = {
'11111': [1,3], // get photos #1 and #3 for listingId 11111
'22222': '*', // get all photos for listingId 22222
'33333': '0' // get 'preferred' photo for listingId 33333
};
return client.objects.stream.getObjects('Property', 'Photo', photoIds, {alwaysGroupObjects: true, ObjectData: '*'})
var rets = require('rets-client');
var fs = require('fs');
// establish connection to RETS server which auto-logs out when we're done
rets.getAutoLogoutClient(clientSettings, function (client) {
// getObjects will accept a single string, an array of strings, or an object as shown below
var photoIds = {
'11111': [1,3], // get photos #1 and #3 for listingId 11111
'22222': '*', // get all photos for listingId 22222
'33333': '0' // get 'preferred' photo for listingId 33333
};
return client.objects.stream.getObjects('Property', 'LargePhoto', photoIds, {alwaysGroupObjects: true, ObjectData: '*'})
.then(function (photoStream) {
console.log("========================================");
console.log("======== Photo Stream Results ========");
console.log("========================================");
return new Promise(function (resolve, reject) {
var i=0;
photoStream.objectStream.on('data', function (photoEvent) {
i++;
if (photoEvent.error) {
console.log("Photo " + i + " had an error: " + photoEvent.error);
} else {
console.log("Photo " + (i + 1) + ":");
outputFields(photoEvent.headerInfo);
fileStream = fs.createWriteStream(
"/tmp/photo" + i + "." + photoEvent.headerInfo.contentType.match(/\w+\/(\w+)/i)[1]);
photoEvent.dataStream.pipe(fileStream);
photoStream.objectStream.on('data', function (event) {
try {
if (event.type == 'headerInfo') {
console.log(' ~~~~~~~~~ Header Info ~~~~~~~~~');
outputFields(event.headerInfo);
return
}
console.log(" -------- Photo " + (i + 1) + " --------");
if (event.type == 'error') {
console.log(" Error: " + event.error);
} else if (event.type == 'dataStream') {
outputFields(event.headerInfo);
fileStream = fs.createWriteStream(
"/tmp/photo_" + event.headerInfo.contentId + "_" + event.headerInfo.objectId + "." + event.headerInfo.contentType.match(/\w+\/(\w+)/i)[1]);
event.dataStream.pipe(fileStream);
}
i++;
} catch (err) {
reject(err);
}
});
photoStream.objectStream.on('error', function (errorInfo) {
reject(errorInfo);
});
photoStream.objectStream.on('end', function () {

@@ -318,4 +370,9 @@ resolve();

});
}).catch(function (errorInfo) {
var error = errorInfo.error || errorInfo;
console.log(" ERROR: issue encountered:");
outputFields(error);
console.log(' '+(error.stack||error).replace(/\n/g, '\n '));
});
});
});
```

@@ -322,0 +379,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc