Comparing version 1.5.0 to 1.6.0
@@ -62,2 +62,8 @@ #!/usr/bin/env node | ||
console.error(err.stack || err); | ||
if (err.response) { | ||
console.error(err.response.statusCode); | ||
console.error(err.response.statusText); | ||
console.error(err.response.headers); | ||
console.error(err.response.body); | ||
} | ||
}); |
@@ -8,12 +8,2 @@ (function (exports) { | ||
/** | ||
* @type {RequestInit} defaultOpts | ||
*/ | ||
let defaultOpts = { | ||
headers: { | ||
Accept: "application/json", | ||
"Content-Type": "application/json", | ||
}, | ||
}; | ||
const DUFFS = 100000000; | ||
@@ -118,3 +108,3 @@ | ||
/** @type Array<InsightUtxo> */ | ||
let utxos = await utxoResp.json(); | ||
let utxos = utxoResp.body; | ||
return utxos; | ||
@@ -140,4 +130,5 @@ }; | ||
/** @type InsightTx */ | ||
let data = await txResp.json(); | ||
/** @type {InsightTx} */ | ||
//@ts-ignore | ||
let data = txResp.body; | ||
return data; | ||
@@ -152,3 +143,4 @@ }; | ||
/** @type {InsightTxResponse} */ | ||
let body = await txResp.json(); | ||
//@ts-ignore | ||
let body = txResp.body; | ||
@@ -170,7 +162,7 @@ let data = await getAllPages(body, addr, maxPages); | ||
); | ||
nextResp = await nextResp.json(); | ||
let nextBody = nextResp.body; | ||
// Note: this could still be wrong, but I don't think we have | ||
// a better way to page so... whatever | ||
// @ts-ignore | ||
body.txs = body.txs.concat(nextResp?.txs); | ||
body.txs = body.txs.concat(nextBody?.txs); | ||
} | ||
@@ -197,3 +189,3 @@ return body; | ||
} | ||
return txResp.json(); | ||
return txResp.body; | ||
}; | ||
@@ -291,15 +283,68 @@ | ||
/** @type {HeadersInit} */ | ||
let defaultHeaders = { | ||
Accept: "application/json", | ||
"Content-Type": "application/json", | ||
}; | ||
/** | ||
* @param {String | URL | Request} url | ||
* @param {RequestInit} [opts] | ||
* @param {RequestInit} [_opts] | ||
*/ | ||
Dashsight.fetch = async function dashfetch(url, opts) { | ||
opts = Object.assign({}, defaultOpts, opts); | ||
Dashsight.fetch = async function dashfetch(url, _opts) { | ||
let opts = Object.assign({ headers: {} }, _opts); | ||
Object.assign(opts.headers, defaultHeaders, _opts?.headers); | ||
if (opts.body) { | ||
opts.body = JSON.stringify(opts.body); | ||
//@ts-ignore | ||
let contentType = opts.headers["Content-Type"] || ""; | ||
let isJson = contentType.startsWith("application/json"); | ||
if (isJson) { | ||
opts.body = JSON.stringify(opts.body); | ||
} | ||
} | ||
let resp = await fetch(url, opts); | ||
let headers = Object.fromEntries(resp.headers.entries()); | ||
let rawBody = await resp.text(); | ||
let contentType = resp.headers.get("content-type") || ""; | ||
let isJson = contentType.startsWith("application/json"); | ||
/** @type {Object|Array<any>|String} */ | ||
let body = rawBody; | ||
if (isJson) { | ||
try { | ||
body = JSON.parse(rawBody); | ||
} catch (e) { | ||
// ignore | ||
} | ||
} | ||
let response = { | ||
ok: resp.ok, | ||
statusCode: resp.status, // backwards compat | ||
statusText: resp.statusText, | ||
headers: headers, | ||
body: body, | ||
toJSON: function () { | ||
return { | ||
ok: response.ok, | ||
statusCode: response.statusCode, | ||
statusText: response.statusText, | ||
headers: headers, | ||
body: body, | ||
}; | ||
}, | ||
get status() { | ||
console.warn( | ||
"deprecated: please use either 'statusText' or 'statusCode' (node.js and browser both have 'status', but flipped)", | ||
); | ||
return resp.statusText; | ||
}, | ||
_request: opts, | ||
_response: resp, | ||
}; | ||
if (resp.ok) { | ||
return resp; | ||
return response; | ||
} | ||
@@ -310,4 +355,5 @@ | ||
); | ||
// @ts-ignore | ||
err.response = resp.json(); | ||
err.response = response; | ||
throw err; | ||
@@ -314,0 +360,0 @@ }; |
@@ -11,3 +11,3 @@ (function (exports) { | ||
* @prop {String} [baseUrl] - (deprecated by dashsocketBaseUrl) ex: https://insight.dash.org | ||
* @prop {CookieStore} cookieStore - only needed for insight APIs hosted behind an AWS load balancer | ||
* @prop {import('./').CookieStore?} cookieStore - only needed for insight APIs hosted behind an AWS load balancer | ||
* @prop {Boolean} debug | ||
@@ -51,9 +51,6 @@ * @prop {Function} onClose | ||
let sidResp = await window.fetch(sidUrl, { | ||
mode: "cors", | ||
credentials: "include", | ||
}); | ||
let sidResp = await Ws.fetch(sidUrl); | ||
if (!sidResp.ok) { | ||
let err = new Error("bad response"); | ||
// TODO make error type consistent between browser and node? | ||
//@ts-ignore | ||
err.response = sidResp; | ||
@@ -64,4 +61,3 @@ throw err; | ||
// ex: `97:0{"sid":"xxxx",...}` | ||
let msg = await sidResp.text(); | ||
let session = parseSession(msg); | ||
let session = parseSession(sidResp.body || ""); | ||
return session; | ||
@@ -81,6 +77,4 @@ }; | ||
let subResp = await window.fetch(subUrl, { | ||
let subResp = await Ws.fetch(subUrl, { | ||
method: "POST", | ||
mode: "cors", | ||
credentials: "include", | ||
headers: { | ||
@@ -98,3 +92,3 @@ "Content-Type": "text/plain;charset=UTF-8", | ||
return await subResp.text(); | ||
return subResp.body; | ||
}; | ||
@@ -299,3 +293,3 @@ | ||
* @param {String} msg | ||
* @returns {SocketIoHello} | ||
* @returns {import('./').SocketIoHello} | ||
*/ | ||
@@ -460,2 +454,58 @@ function parseSession(msg) { | ||
}; | ||
/** @type {RequestInit} */ | ||
let defaultRequest = { | ||
mode: "cors", | ||
credentials: "include", | ||
}; | ||
/** | ||
* @param {String | URL | Request} url | ||
* @param {RequestInit} [_opts] | ||
*/ | ||
Ws.fetch = async function dashfetch(url, _opts) { | ||
let opts = Object.assign(defaultRequest, _opts); | ||
let resp = await fetch(url, opts); | ||
// this will not have arrays, only strings | ||
let headers = Object.fromEntries(resp.headers.entries()); | ||
let body = await resp.text(); | ||
let response = { | ||
ok: resp.ok, | ||
statusCode: resp.status, // backwards compat | ||
statusText: resp.statusText, | ||
headers: headers, | ||
body: body, | ||
toJSON: function () { | ||
return { | ||
ok: response.ok, | ||
statusCode: response.statusCode, | ||
statusText: response.statusText, | ||
headers: headers, | ||
body: body, | ||
}; | ||
}, | ||
get status() { | ||
console.warn( | ||
"deprecated: please use either 'statusText' or 'statusCode' (node.js and browser both have 'status', but flipped)", | ||
); | ||
return resp.statusText; | ||
}, | ||
_request: opts, | ||
_response: resp, | ||
}; | ||
if (resp.ok) { | ||
return response; | ||
} | ||
let err = new Error( | ||
`http request was ${resp.status}, not ok. See err.response for details.`, | ||
); | ||
// @ts-ignore | ||
err.response = response; | ||
throw err; | ||
}; | ||
})(("undefined" !== typeof module && module.exports) || window); |
{ | ||
"name": "dashsight", | ||
"version": "1.5.0", | ||
"version": "1.6.0", | ||
"description": "SDK for Dash's flavor of the Insight API", | ||
@@ -53,7 +53,6 @@ "main": "index.js", | ||
"optionalDependencies": { | ||
"dotenv": "^16.0.1" | ||
"dotenv": "^16.0.1", | ||
"tough-cookie": "^4.1.2", | ||
"ws": "^8.13.0" | ||
}, | ||
"dependencies": { | ||
"dashtx": "^0.9.0-3" | ||
}, | ||
"devDependencies": { | ||
@@ -63,4 +62,6 @@ "@dashincubator/base58check": "^1.3.1", | ||
"@dashincubator/secp256k1": "^1.7.1-1", | ||
"@types/tough-cookie": "^4.0.2" | ||
} | ||
"@types/tough-cookie": "^4.0.2", | ||
"dashtx": "^0.9.0-3" | ||
}, | ||
"dependencies": {} | ||
} |
@@ -7,6 +7,12 @@ # [dashsight.js](https://github.com/dashhive/dashsight.js) | ||
```bash | ||
npm install --save dashsight | ||
```sh | ||
npm install --save dashsight@1.x | ||
``` | ||
To use `WebSocket`s in Node.js: | ||
```sh | ||
npm install --save tough-cookie@4.x ws@8.x | ||
``` | ||
# Usage | ||
@@ -13,0 +19,0 @@ |
"use strict"; | ||
/** @type CookieStore */ | ||
/** @type {import('../').CookieStore} */ | ||
let Cookies = module.exports; | ||
@@ -11,3 +11,5 @@ | ||
let jar = new Cookie.CookieJar(/*cookies_store*/); | ||
//@ts-ignore | ||
jar.setCookieAsync = require("util").promisify(jar.setCookie); | ||
//@ts-ignore | ||
jar.getCookiesAsync = require("util").promisify(jar.getCookies); | ||
@@ -22,19 +24,25 @@ //cookies_store.saveAsync = require("util").promisify(cookies_store.save); | ||
Cookies.set = async function _setCookie(url, resp) { | ||
/** @type {Array<String>} */ | ||
let cookies; | ||
if (resp.headers["set-cookie"]) { | ||
if (Array.isArray(resp.headers["set-cookie"])) { | ||
cookies = resp.headers["set-cookie"].map(Cookie.parse); | ||
} else { | ||
cookies = [Cookie.parse(resp.headers["set-cookie"])]; | ||
} | ||
let moreCookies = resp.headers["set-cookie"]; | ||
if (!moreCookies) { | ||
return; | ||
} | ||
if (!Array.isArray(moreCookies)) { | ||
moreCookies = [moreCookies]; | ||
} | ||
//@ts-ignore | ||
cookies = moreCookies.map(Cookie.parse); | ||
// let Cookie = //require('set-cookie-parser'); | ||
// Cookie.parse(resp, { decodeValues: true }); | ||
await Promise.all( | ||
cookies.map(async function (cookie) { | ||
//console.log('DEBUG cookie:', cookie.toJSON()); | ||
await jar.setCookieAsync(cookie, url, { now: new Date() }); | ||
}), | ||
); | ||
let ps = cookies.map(async function (cookie) { | ||
//console.log('DEBUG cookie:', cookie.toJSON()); | ||
let jarOpts = { now: new Date() }; | ||
//@ts-ignore | ||
await jar.setCookieAsync(cookie, url, jarOpts); | ||
}); | ||
await Promise.all(ps); | ||
//await cookies_store.saveAsync(); | ||
@@ -48,3 +56,6 @@ }; | ||
Cookies.get = async function _getCookie(url) { | ||
return (await jar.getCookiesAsync(url)).toString(); | ||
//@ts-ignore | ||
let cookieObj = await jar.getCookiesAsync(url); | ||
let cookieStr = cookieObj.toString(); | ||
return cookieStr; | ||
}; |
189
ws/index.js
@@ -12,3 +12,3 @@ "use strict"; | ||
* @prop {String} [baseUrl] - (deprecated by dashsocketBaseUrl) ex: https://insight.dash.org | ||
* @prop {CookieStore} cookieStore - only needed for insight APIs hosted behind an AWS load balancer | ||
* @prop {import('../').CookieStore} cookieStore - only needed for insight APIs hosted behind an AWS load balancer | ||
* @prop {Boolean} debug | ||
@@ -52,18 +52,15 @@ * @prop {Function} onClose | ||
let cookies = await cookieStore.get(sidUrl); | ||
let sidResp = await fetch(sidUrl, { | ||
let cookiesStr = await cookieStore.get(sidUrl); | ||
let sidResp = await Ws.fetch(sidUrl, { | ||
//agent: httpAgent, | ||
//@ts-ignore - request function is not typed correctly | ||
headers: { | ||
Cookie: cookies, | ||
Cookie: cookiesStr, | ||
}, | ||
}); | ||
if (!sidResp.ok) { | ||
console.error(await sidResp.json()); | ||
throw new Error("bad response"); | ||
} | ||
await cookieStore.set(sidUrl, sidResp); | ||
// ex: `97:0{"sid":"xxxx",...}` | ||
let msg = await sidResp.json(); | ||
let msg = sidResp.body || ""; | ||
let colonIndex = msg.indexOf(":"); | ||
@@ -100,4 +97,4 @@ // 0 is CONNECT, which will always follow our first message | ||
let cookies = await cookieStore.get(subUrl); | ||
let subResp = await fetch(subUrl, { | ||
let cookiesStr = await cookieStore.get(subUrl); | ||
let subResp = await Ws.fetch(subUrl, { | ||
//agent: httpAgent, | ||
@@ -107,14 +104,11 @@ method: "POST", | ||
"Content-Type": "text/plain;charset=UTF-8", | ||
Cookie: cookies, | ||
Cookie: cookiesStr, | ||
}, | ||
body: body, | ||
}); | ||
if (!subResp.ok) { | ||
console.error(await subResp.json()); | ||
throw new Error("bad response"); | ||
} | ||
await cookieStore.set(subUrl, subResp); | ||
// "ok" | ||
return await subResp.json(); | ||
return subResp.body; | ||
}; | ||
@@ -154,4 +148,5 @@ | ||
let url = `ws${dashsocketBaseUrlPart}/?EIO=3&transport=websocket&sid=${sid}`; | ||
let sidUrl = `${dashsocketBaseUrl}/`; | ||
let cookies = await cookieStore.get(`${dashsocketBaseUrl}/`); | ||
let cookiesStr = await cookieStore.get(sidUrl); | ||
let ws = new WSClient(url, { | ||
@@ -162,3 +157,3 @@ //agent: httpAgent, | ||
headers: { | ||
Cookie: cookies, | ||
Cookie: cookiesStr, | ||
}, | ||
@@ -178,8 +173,23 @@ }); | ||
onError(err); | ||
} else { | ||
console.error("WebSocket Error:"); | ||
console.error(err); | ||
return; | ||
} | ||
console.error("WebSocket Error:"); | ||
console.error(err); | ||
}); | ||
ws.once("unexpected-response", function (req, res) { | ||
let err = new Error("unexpected-response"); | ||
//@ts-ignore | ||
err.response = res; | ||
if (onError) { | ||
onError(err); | ||
return; | ||
} | ||
console.error("WebSocket Unexpected Response:"); | ||
console.error(err); | ||
}); | ||
ws.once("message", function message(data) { | ||
@@ -271,3 +281,3 @@ if ("3probe" === data.toString()) { | ||
/** @type {InsightPush} */ | ||
/** @type {import('../').InsightPush} */ | ||
let [evname, data] = JSON.parse(msg.slice(2)); | ||
@@ -314,3 +324,3 @@ if (onMessage) { | ||
* @param {String} evname | ||
* @param {InsightSocketEventData} data | ||
* @param {import('../').InsightSocketEventData} data | ||
*/ | ||
@@ -371,4 +381,4 @@ | ||
* @param {Number} [maxTxLockWait] | ||
* @param {WsOpts} [opts] | ||
* @returns {Promise<SocketPayment>} | ||
* @param {Partial<WsOpts>} [opts] | ||
* @returns {Promise<import('../').SocketPayment>} | ||
*/ | ||
@@ -387,3 +397,3 @@ Ws.waitForVout = async function ( | ||
// Listen for Response | ||
/** @type SocketPayment */ | ||
/** @type {import('../').SocketPayment} */ | ||
let mempoolTx; | ||
@@ -394,3 +404,3 @@ return await Ws.listen(dashsocketBaseUrl, findResponse, opts); | ||
* @param {String} evname | ||
* @param {InsightSocketEventData} data | ||
* @param {import('../').InsightSocketEventData} data | ||
*/ | ||
@@ -412,30 +422,33 @@ function findResponse(evname, data) { | ||
// TODO should fetch tx and match hotwallet as vin | ||
data.vout.some(function (vout) { | ||
if (!(addr in vout)) { | ||
return false; | ||
} | ||
data.vout.some( | ||
/** @param {Record<String,Number>} vout */ | ||
function (vout) { | ||
if (!(addr in vout)) { | ||
return false; | ||
} | ||
let duffs = vout[addr]; | ||
if (amount && duffs !== amount) { | ||
return false; | ||
} | ||
let duffs = vout[addr]; | ||
if (amount && duffs !== amount) { | ||
return false; | ||
} | ||
let newTx = { | ||
address: addr, | ||
timestamp: now, | ||
txid: data.txid, | ||
satoshis: duffs, | ||
txlock: data.txlock, | ||
}; | ||
let newTx = { | ||
address: addr, | ||
timestamp: now, | ||
txid: data.txid, | ||
satoshis: duffs, | ||
txlock: data.txlock, | ||
}; | ||
if ("txlock" !== evname) { | ||
if (!mempoolTx) { | ||
mempoolTx = newTx; | ||
if ("txlock" !== evname) { | ||
if (!mempoolTx) { | ||
mempoolTx = newTx; | ||
} | ||
return false; | ||
} | ||
return false; | ||
} | ||
result = newTx; | ||
return true; | ||
}); | ||
result = newTx; | ||
return true; | ||
}, | ||
); | ||
@@ -446,2 +459,76 @@ return result; | ||
/** @type {RequestInit} */ | ||
let defaultRequest = { | ||
mode: "cors", | ||
credentials: "include", | ||
}; | ||
/** | ||
* @param {String | URL | Request} url | ||
* @param {RequestInit} [_opts] | ||
*/ | ||
Ws.fetch = async function dashfetch(url, _opts) { | ||
let opts = Object.assign(defaultRequest, _opts); | ||
let resp = await fetch(url, opts); | ||
/** @type {Record<String,String|Array<String>>} */ | ||
let headers = {}; | ||
// for the Set-Cookie headers through AWS load balancer | ||
let headerEntries = resp.headers.entries(); | ||
for (let [key, value] of headerEntries) { | ||
if (!headers[key]) { | ||
headers[key] = value; | ||
continue; | ||
} | ||
let isArray = Array.isArray(headers[key]); | ||
if (!isArray) { | ||
//@ts-ignore | ||
headers[key] = [headers[key]]; | ||
} | ||
//@ts-ignore | ||
headers[key].push(value); | ||
} | ||
let body = await resp.text(); | ||
let response = { | ||
ok: resp.ok, | ||
statusCode: resp.status, // backwards compat | ||
statusText: resp.statusText, | ||
headers: headers, | ||
body: body, | ||
toJSON: function () { | ||
return { | ||
ok: response.ok, | ||
statusCode: response.statusCode, | ||
statusText: response.statusText, | ||
headers: response.headers, | ||
body: response.body, | ||
}; | ||
}, | ||
get status() { | ||
console.warn( | ||
"deprecated: please use either 'statusText' or 'statusCode' (node.js and browser both have 'status', but flipped)", | ||
); | ||
return resp.statusText; | ||
}, | ||
_request: opts, | ||
_response: resp, | ||
}; | ||
if (resp.ok) { | ||
return response; | ||
} | ||
let err = new Error( | ||
`http request was ${resp.status}, not ok. See err.response for details.`, | ||
); | ||
// @ts-ignore | ||
err.response = response; | ||
throw err; | ||
}; | ||
/* | ||
@@ -448,0 +535,0 @@ async function sleep(ms) { |
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
76081
2274
397
3
5
+ Addedpsl@1.9.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedquerystringify@2.2.0(transitive)
+ Addedrequires-port@1.0.0(transitive)
+ Addedtough-cookie@4.1.4(transitive)
+ Addeduniversalify@0.2.0(transitive)
+ Addedurl-parse@1.5.10(transitive)
+ Addedws@8.18.0(transitive)
- Removeddashtx@^0.9.0-3
- Removeddashtx@0.9.0(transitive)