diff --git a/.eslintignore b/.eslintignore index 84c048a..12da7d1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ /build/ +/docs/ \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index 57479ba..98b6f97 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,6 +13,7 @@ "rules": { "@typescript-eslint/explicit-function-return-type": "warn", "@typescript-eslint/strict-boolean-expressions": "warn", + "@typescript-eslint/no-non-null-assertion": "off", "simple-import-sort/sort": "error" } } diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..2c1a5f6 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,14 @@ +# Push Server CRD API +## Overview +Clients can interact with the push server through a CRD API that allows for the creation, reading and deletion of `Task` documents. + + +## Routers +As a REST API, the following routers implement HTTP methods: + +|Router Name| HTTP Method | Description | +|-----------| ----------- | ----------- | +|`getTaskRoute`| GET | Expect to get an array of `taskIds`. If the array is empty, it will get all tasks for the given `userId`. | +|`createTaskRoute`| POST | Construct a body and returns it as an HttpResponse. The body will include a payload that conforms to the `Task` type. It will write to the CouchDB database to create such task. | +|`deleteTaskRoute`| DELETE | Remove tasks from the database. If the `taskIds` array is empty, it will remove all tasks under the `userId`. | + diff --git a/docs/assets/Action-Server.jpg b/docs/assets/Action-Server.jpg new file mode 100644 index 0000000..3d6313f Binary files /dev/null and b/docs/assets/Action-Server.jpg differ diff --git a/docs/assets/push-publisher-pseudocode.png b/docs/assets/push-publisher-pseudocode.png new file mode 100644 index 0000000..63c1469 Binary files /dev/null and b/docs/assets/push-publisher-pseudocode.png differ diff --git a/docs/assets/push-publisher-views.png b/docs/assets/push-publisher-views.png new file mode 100644 index 0000000..a6ca336 Binary files /dev/null and b/docs/assets/push-publisher-views.png differ diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 0000000..47761e7 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,17 @@ +# Push Server Overview + +## Introduction +The push server handles all the push notifications for end users. + +The server itself consists of an API interface and a number of publishers/listeners. Below you can find documentation for the API inteface and specific publishers/listeners. + +* [API](./api.md) +* [Push Publisher](./publishers/push-publisher.md) + + +## Architecture +The push server is constructed as a number of independent microservices: + + + +The core component of the server is the CouchDB database, with which publishers and listeners perform their operations based on the changes in the database. \ No newline at end of file diff --git a/docs/publishers/push-publisher.md b/docs/publishers/push-publisher.md new file mode 100644 index 0000000..c92cb97 --- /dev/null +++ b/docs/publishers/push-publisher.md @@ -0,0 +1,42 @@ +# Push Publisher +## Overview + +The push publisher is responsible for pushing notifications to end users. + +The new version of the push server is designed to accommodate the "action-queue" feature of the Edge app. Users will have the ability to configure an arbitrary number of transactional actions and to "chain" them all together with predefined sequences. + +Some servers will then process these actions. The push publisher's job, then, is to handle push notifications once tasks are done. + +## Architecture +The publisher directly interacts with a CouchDB database, named 'db_tasks'. However, for performance reasons, we create two "views" for the database. A view is simply an interface that displays a set of documents based on certain query conditions. + +### Views + +Since the push publisher only pushes notifications for completed tasks, it is best to have a view that shows all completed tasks, and another view to show all incompleted tasks. + + + +`Task` is a data type modeled as below: +```js +taskId: string +userId: string +actionEffects: ActionEffect[] +action: Action +``` + +The `task_publishing` view contains all `Task`s that have every `ActionEffect` marked as completed. This is the view that the push publisher is listening for changes. + +Similarly, the `task_listening` view contains `Task`s that have at least one incomplete `ActionEffect`. + +## Publisher Logics +The push publisher gets a stream of `Task` documents from the `task_publishing` view. For each eligible document, the publisher pushes a notfication to devices. + + + +Depending on the `Action` of each task, the publisher may delete a task document if the `Action`'s `repeat` flag is marked as false. + +Otherwise, the publisher loops through the array of `ActionEffect`s, and set the `completed` flag to false for each one. Upon updating the document, the `task_listening` view will automatically pick up the `Task`, thereby allowing the `Task` to be processed repeatedly. + +To prevent race conditions, the push publisher also manipulate the `inProgress` flag in the `Action` property. + +The mutex implementaion coupled with the dual-view design abstractly reap the benefits of a message queue where each task can only be picked up by one service. diff --git a/docs/references/.nojekyll b/docs/references/.nojekyll new file mode 100644 index 0000000..e2ac661 --- /dev/null +++ b/docs/references/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/references/assets/highlight.css b/docs/references/assets/highlight.css new file mode 100644 index 0000000..005cd66 --- /dev/null +++ b/docs/references/assets/highlight.css @@ -0,0 +1,36 @@ +:root { + --light-hl-0: #000000; + --dark-hl-0: #D4D4D4; + --light-hl-1: #008000; + --dark-hl-1: #6A9955; + --light-code-background: #FFFFFF; + --dark-code-background: #1E1E1E; +} + +@media (prefers-color-scheme: light) { :root { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --code-background: var(--light-code-background); +} } + +@media (prefers-color-scheme: dark) { :root { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --code-background: var(--dark-code-background); +} } + +:root[data-theme='light'] { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --code-background: var(--light-code-background); +} + +:root[data-theme='dark'] { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --code-background: var(--dark-code-background); +} + +.hl-0 { color: var(--hl-0); } +.hl-1 { color: var(--hl-1); } +pre, code { background: var(--code-background); } diff --git a/docs/references/assets/main.js b/docs/references/assets/main.js new file mode 100644 index 0000000..c815b33 --- /dev/null +++ b/docs/references/assets/main.js @@ -0,0 +1,54 @@ +"use strict"; +(()=>{var Qe=Object.create;var ae=Object.defineProperty;var Pe=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var Oe=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var _e=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Me=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ce(e))!Re.call(t,i)&&i!==n&&ae(t,i,{get:()=>e[i],enumerable:!(r=Pe(e,i))||r.enumerable});return t};var De=(t,e,n)=>(n=t!=null?Qe(Oe(t)):{},Me(e||!t||!t.__esModule?ae(n,"default",{value:t,enumerable:!0}):n,t));var de=_e((ce,he)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var h=t.utils.clone(n)||{};h.position=[a,l],h.index=s.length,s.push(new t.Token(r.slice(a,o),h))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ou?h+=2:a==u&&(n+=r[l+1]*i[h+1],l+=2,h+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),m=s.str.charAt(1),v;m in s.node.edges?v=s.node.edges[m]:(v=new t.TokenSet,s.node.edges[m]=v),s.str.length==1&&(v.final=!0),i.push({node:v,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof ce=="object"?he.exports=n():e.lunr=n()}(this,function(){return t})})()});var le=[];function j(t,e){le.push({selector:e,constructor:t})}var Y=class{constructor(){this.createComponents(document.body)}createComponents(e){le.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r}),r.dataset.hasInstance=String(!0))})})}};var k=class{constructor(e){this.el=e.el}};var J=class{constructor(){this.listeners={}}addEventListener(e,n){e in this.listeners||(this.listeners[e]=[]),this.listeners[e].push(n)}removeEventListener(e,n){if(!(e in this.listeners))return;let r=this.listeners[e];for(let i=0,s=r.length;i{let n=Date.now();return(...r)=>{n+e-Date.now()<0&&(t(...r),n=Date.now())}};var re=class extends J{constructor(){super();this.scrollTop=0;this.lastY=0;this.width=0;this.height=0;this.showToolbar=!0;this.toolbar=document.querySelector(".tsd-page-toolbar"),this.navigation=document.querySelector(".col-menu"),window.addEventListener("scroll",ne(()=>this.onScroll(),10)),window.addEventListener("resize",ne(()=>this.onResize(),10)),this.searchInput=document.querySelector("#tsd-search input"),this.searchInput&&this.searchInput.addEventListener("focus",()=>{this.hideShowToolbar()}),this.onResize(),this.onScroll()}triggerResize(){let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onResize(){this.width=window.innerWidth||0,this.height=window.innerHeight||0;let n=new CustomEvent("resize",{detail:{width:this.width,height:this.height}});this.dispatchEvent(n)}onScroll(){this.scrollTop=window.scrollY||0;let n=new CustomEvent("scroll",{detail:{scrollTop:this.scrollTop}});this.dispatchEvent(n),this.hideShowToolbar()}hideShowToolbar(){let n=this.showToolbar;this.showToolbar=this.lastY>=this.scrollTop||this.scrollTop<=0||!!this.searchInput&&this.searchInput===document.activeElement,n!==this.showToolbar&&(this.toolbar.classList.toggle("tsd-page-toolbar--hide"),this.navigation?.classList.toggle("col-menu--hide")),this.lastY=this.scrollTop}},R=re;R.instance=new re;var X=class extends k{constructor(n){super(n);this.anchors=[];this.index=-1;R.instance.addEventListener("resize",()=>this.onResize()),R.instance.addEventListener("scroll",r=>this.onScroll(r)),this.createAnchors()}createAnchors(){let n=window.location.href;n.indexOf("#")!=-1&&(n=n.substring(0,n.indexOf("#"))),this.el.querySelectorAll("a").forEach(r=>{let i=r.href;if(i.indexOf("#")==-1||i.substring(0,n.length)!=n)return;let s=i.substring(i.indexOf("#")+1),o=document.querySelector("a.tsd-anchor[name="+s+"]"),a=r.parentNode;!o||!a||this.anchors.push({link:a,anchor:o,position:0})}),this.onResize()}onResize(){let n;for(let i=0,s=this.anchors.length;ii.position-s.position);let r=new CustomEvent("scroll",{detail:{scrollTop:R.instance.scrollTop}});this.onScroll(r)}onScroll(n){let r=n.detail.scrollTop+5,i=this.anchors,s=i.length-1,o=this.index;for(;o>-1&&i[o].position>r;)o-=1;for(;o-1&&this.anchors[this.index].link.classList.remove("focus"),this.index=o,this.index>-1&&this.anchors[this.index].link.classList.add("focus"))}};var ue=(t,e=100)=>{let n;return(...r)=>{clearTimeout(n),n=setTimeout(()=>t(r),e)}};var me=De(de());function ve(){let t=document.getElementById("tsd-search");if(!t)return;let e=document.getElementById("search-script");t.classList.add("loading"),e&&(e.addEventListener("error",()=>{t.classList.remove("loading"),t.classList.add("failure")}),e.addEventListener("load",()=>{t.classList.remove("loading"),t.classList.add("ready")}),window.searchData&&t.classList.remove("loading"));let n=document.querySelector("#tsd-search input"),r=document.querySelector("#tsd-search .results");if(!n||!r)throw new Error("The input field or the result list wrapper was not found");let i=!1;r.addEventListener("mousedown",()=>i=!0),r.addEventListener("mouseup",()=>{i=!1,t.classList.remove("has-focus")}),n.addEventListener("focus",()=>t.classList.add("has-focus")),n.addEventListener("blur",()=>{i||(i=!1,t.classList.remove("has-focus"))});let s={base:t.dataset.base+"/"};Fe(t,r,n,s)}function Fe(t,e,n,r){n.addEventListener("input",ue(()=>{Ae(t,e,n,r)},200));let i=!1;n.addEventListener("keydown",s=>{i=!0,s.key=="Enter"?Ve(e,n):s.key=="Escape"?n.blur():s.key=="ArrowUp"?fe(e,-1):s.key==="ArrowDown"?fe(e,1):i=!1}),n.addEventListener("keypress",s=>{i&&s.preventDefault()}),document.body.addEventListener("keydown",s=>{s.altKey||s.ctrlKey||s.metaKey||!n.matches(":focus")&&s.key==="/"&&(n.focus(),s.preventDefault())})}function He(t,e){t.index||window.searchData&&(e.classList.remove("loading"),e.classList.add("ready"),t.data=window.searchData,t.index=me.Index.load(window.searchData.index))}function Ae(t,e,n,r){if(He(r,t),!r.index||!r.data)return;e.textContent="";let i=n.value.trim(),s=i?r.index.search(`*${i}*`):[];for(let o=0;oa.score-o.score);for(let o=0,a=Math.min(10,s.length);o${pe(u.parent,i)}.${l}`);let h=document.createElement("li");h.classList.value=u.classes??"";let m=document.createElement("a");m.href=r.base+u.url,m.innerHTML=l,h.append(m),e.appendChild(h)}}function fe(t,e){let n=t.querySelector(".current");if(!n)n=t.querySelector(e==1?"li:first-child":"li:last-child"),n&&n.classList.add("current");else{let r=n;if(e===1)do r=r.nextElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);else do r=r.previousElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);r&&(n.classList.remove("current"),r.classList.add("current"))}}function Ve(t,e){let n=t.querySelector(".current");if(n||(n=t.querySelector("li:first-child")),n){let r=n.querySelector("a");r&&(window.location.href=r.href),e.blur()}}function pe(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(ie(t.substring(s,o)),`${ie(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(ie(t.substring(s))),i.join("")}var Ne={"&":"&","<":"<",">":">","'":"'",'"':"""};function ie(t){return t.replace(/[&<>"'"]/g,e=>Ne[e])}var F="mousedown",ye="mousemove",B="mouseup",Z={x:0,y:0},ge=!1,se=!1,je=!1,H=!1,xe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(xe?"is-mobile":"not-mobile");xe&&"ontouchstart"in document.documentElement&&(je=!0,F="touchstart",ye="touchmove",B="touchend");document.addEventListener(F,t=>{se=!0,H=!1;let e=F=="touchstart"?t.targetTouches[0]:t;Z.y=e.pageY||0,Z.x=e.pageX||0});document.addEventListener(ye,t=>{if(!!se&&!H){let e=F=="touchstart"?t.targetTouches[0]:t,n=Z.x-(e.pageX||0),r=Z.y-(e.pageY||0);H=Math.sqrt(n*n+r*r)>10}});document.addEventListener(B,()=>{se=!1});document.addEventListener("click",t=>{ge&&(t.preventDefault(),t.stopImmediatePropagation(),ge=!1)});var K=class extends k{constructor(n){super(n);this.className=this.el.dataset.toggle||"",this.el.addEventListener(B,r=>this.onPointerUp(r)),this.el.addEventListener("click",r=>r.preventDefault()),document.addEventListener(F,r=>this.onDocumentPointerDown(r)),document.addEventListener(B,r=>this.onDocumentPointerUp(r))}setActive(n){if(this.active==n)return;this.active=n,document.documentElement.classList.toggle("has-"+this.className,n),this.el.classList.toggle("active",n);let r=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(r),setTimeout(()=>document.documentElement.classList.remove(r),500)}onPointerUp(n){H||(this.setActive(!0),n.preventDefault())}onDocumentPointerDown(n){if(this.active){if(n.target.closest(".col-menu, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(n){if(!H&&this.active&&n.target.closest(".col-menu")){let r=n.target.closest("a");if(r){let i=window.location.href;i.indexOf("#")!=-1&&(i=i.substring(0,i.indexOf("#"))),r.href.substring(0,i.length)==i&&setTimeout(()=>this.setActive(!1),250)}}}};var oe;try{oe=localStorage}catch{oe={getItem(){return null},setItem(){}}}var Q=oe;var Le=document.head.appendChild(document.createElement("style"));Le.dataset.for="filters";var ee=class extends k{constructor(n){super(n);this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),Le.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } +`}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.checked}setLocalStorage(n){Q.setItem(this.key,n.toString()),this.value=n,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),document.querySelectorAll(".tsd-index-section").forEach(n=>{n.style.display="block";let r=Array.from(n.querySelectorAll(".tsd-index-link")).every(i=>i.offsetParent==null);n.style.display=r?"none":"block"})}};var te=class extends k{constructor(n){super(n);this.calculateHeights(),this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.textContent.replace(/\s+/g,"-").toLowerCase()}`,this.setLocalStorage(this.fromLocalStorage(),!0),this.summary.addEventListener("click",r=>this.toggleVisibility(r)),this.icon.style.transform=this.getIconRotation()}getIconRotation(n=this.el.open){return`rotate(${n?0:-90}deg)`}calculateHeights(){let n=this.el.open,{position:r,left:i}=this.el.style;this.el.style.position="fixed",this.el.style.left="-9999px",this.el.open=!0,this.expandedHeight=this.el.offsetHeight+"px",this.el.open=!1,this.collapsedHeight=this.el.offsetHeight+"px",this.el.open=n,this.el.style.height=n?this.expandedHeight:this.collapsedHeight,this.el.style.position=r,this.el.style.left=i}toggleVisibility(n){n.preventDefault(),this.el.style.overflow="hidden",this.el.open?this.collapse():this.expand()}expand(n=!0){this.el.open=!0,this.animate(this.collapsedHeight,this.expandedHeight,{opening:!0,duration:n?300:0})}collapse(n=!0){this.animate(this.expandedHeight,this.collapsedHeight,{opening:!1,duration:n?300:0})}animate(n,r,{opening:i,duration:s=300}){if(this.animation)return;let o={duration:s,easing:"ease"};this.animation=this.el.animate({height:[n,r]},o),this.icon.animate({transform:[this.icon.style.transform||this.getIconRotation(!i),this.getIconRotation(i)]},o).addEventListener("finish",()=>{this.icon.style.transform=this.getIconRotation(i)}),this.animation.addEventListener("finish",()=>this.animationEnd(i))}animationEnd(n){this.el.open=n,this.animation=void 0,this.el.style.height="auto",this.el.style.overflow="visible",this.setLocalStorage(n)}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.open}setLocalStorage(n,r=!1){this.fromLocalStorage()===n&&!r||(Q.setItem(this.key,n.toString()),this.el.open=n,this.handleValueChange(r))}handleValueChange(n=!1){this.fromLocalStorage()===this.el.open&&!n||(this.fromLocalStorage()?this.expand(!1):this.collapse(!1))}};function be(t){let e=Q.getItem("tsd-theme")||"os";t.value=e,Ee(e),t.addEventListener("change",()=>{Q.setItem("tsd-theme",t.value),Ee(t.value)})}function Ee(t){document.documentElement.dataset.theme=t}ve();j(X,".menu-highlight");j(K,"a[data-toggle]");j(te,".tsd-index-accordion");j(ee,".tsd-filter-item input[type=checkbox]");var Se=document.getElementById("theme");Se&&be(Se);var Be=new Y;Object.defineProperty(window,"app",{value:Be});})(); +/*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + */ +/*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + */ +/*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + */ +/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + */ diff --git a/docs/references/assets/search.js b/docs/references/assets/search.js new file mode 100644 index 0000000..b88a5d7 --- /dev/null +++ b/docs/references/assets/search.js @@ -0,0 +1 @@ +window.searchData = JSON.parse("{\"kinds\":{\"2\":\"Module\",\"32\":\"Variable\",\"64\":\"Function\",\"256\":\"Interface\",\"1024\":\"Property\",\"65536\":\"Type literal\",\"4194304\":\"Type alias\"},\"rows\":[{\"kind\":2,\"name\":\"types/http/request-types\",\"url\":\"modules/types_http_request_types.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":256,\"name\":\"ExtendedRequest\",\"url\":\"interfaces/types_http_request_types.ExtendedRequest.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/http/request-types\"},{\"kind\":1024,\"name\":\"body\",\"url\":\"interfaces/types_http_request_types.ExtendedRequest.html#body\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/http/request-types.ExtendedRequest\"},{\"kind\":256,\"name\":\"ApiRequest\",\"url\":\"interfaces/types_http_request_types.ApiRequest.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/http/request-types\"},{\"kind\":1024,\"name\":\"apiKey\",\"url\":\"interfaces/types_http_request_types.ApiRequest.html#apiKey\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/http/request-types.ApiRequest\"},{\"kind\":1024,\"name\":\"payload\",\"url\":\"interfaces/types_http_request_types.ApiRequest.html#payload\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/http/request-types.ApiRequest\"},{\"kind\":1024,\"name\":\"body\",\"url\":\"interfaces/types_http_request_types.ApiRequest.html#body\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/http/request-types.ApiRequest\"},{\"kind\":2,\"name\":\"types/http/response-types\",\"url\":\"modules/types_http_response_types.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":64,\"name\":\"jsonResponse\",\"url\":\"functions/types_http_response_types.jsonResponse.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/http/response-types\"},{\"kind\":64,\"name\":\"statusResponse\",\"url\":\"functions/types_http_response_types.statusResponse.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/http/response-types\"},{\"kind\":32,\"name\":\"statusCodes\",\"url\":\"variables/types_http_response_types.statusCodes.html\",\"classes\":\"tsd-kind-variable tsd-parent-kind-module\",\"parent\":\"types/http/response-types\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-variable\",\"parent\":\"types/http/response-types.statusCodes\"},{\"kind\":1024,\"name\":\"SUCCESS\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.SUCCESS\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-3\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type\"},{\"kind\":1024,\"name\":\"httpStatus\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-3.httpStatus-2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type.__type\"},{\"kind\":1024,\"name\":\"message\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-3.message-2\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type.__type\"},{\"kind\":1024,\"name\":\"INTERNAL_SERVER_ERROR\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.INTERNAL_SERVER_ERROR\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-1\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type\"},{\"kind\":1024,\"name\":\"httpStatus\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-1.httpStatus\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type.__type\"},{\"kind\":1024,\"name\":\"message\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-1.message\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type.__type\"},{\"kind\":1024,\"name\":\"PAGE_NOT_FOUND\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.PAGE_NOT_FOUND\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-2\",\"classes\":\"tsd-kind-type-literal tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type\"},{\"kind\":1024,\"name\":\"httpStatus\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-2.httpStatus-1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type.__type\"},{\"kind\":1024,\"name\":\"message\",\"url\":\"variables/types_http_response_types.statusCodes.html#__type.__type-2.message-1\",\"classes\":\"tsd-kind-property tsd-parent-kind-type-literal\",\"parent\":\"types/http/response-types.statusCodes.__type.__type\"},{\"kind\":2,\"name\":\"types/task/Action\",\"url\":\"modules/types_task_Action.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":256,\"name\":\"Action\",\"url\":\"interfaces/types_task_Action.Action.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/Action\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/types_task_Action.Action.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Action.Action\"},{\"kind\":1024,\"name\":\"repeat\",\"url\":\"interfaces/types_task_Action.Action.html#repeat\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Action.Action\"},{\"kind\":1024,\"name\":\"inProgress\",\"url\":\"interfaces/types_task_Action.Action.html#inProgress\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Action.Action\"},{\"kind\":1024,\"name\":\"data\",\"url\":\"interfaces/types_task_Action.Action.html#data\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Action.Action\"},{\"kind\":64,\"name\":\"asAction\",\"url\":\"functions/types_task_Action.asAction.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/Action\"},{\"kind\":2,\"name\":\"types/task/ActionData\",\"url\":\"modules/types_task_ActionData.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":256,\"name\":\"GeneralActionData\",\"url\":\"interfaces/types_task_ActionData.GeneralActionData.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":1024,\"name\":\"additionalData\",\"url\":\"interfaces/types_task_ActionData.GeneralActionData.html#additionalData\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionData.GeneralActionData\"},{\"kind\":256,\"name\":\"PushActionData\",\"url\":\"interfaces/types_task_ActionData.PushActionData.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":1024,\"name\":\"apiKey\",\"url\":\"interfaces/types_task_ActionData.PushActionData.html#apiKey\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionData.PushActionData\"},{\"kind\":1024,\"name\":\"title\",\"url\":\"interfaces/types_task_ActionData.PushActionData.html#title\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionData.PushActionData\"},{\"kind\":1024,\"name\":\"body\",\"url\":\"interfaces/types_task_ActionData.PushActionData.html#body\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionData.PushActionData\"},{\"kind\":1024,\"name\":\"tokenIds\",\"url\":\"interfaces/types_task_ActionData.PushActionData.html#tokenIds\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionData.PushActionData\"},{\"kind\":1024,\"name\":\"additionalData\",\"url\":\"interfaces/types_task_ActionData.PushActionData.html#additionalData\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionData.PushActionData\"},{\"kind\":256,\"name\":\"BroadcastTxActionData\",\"url\":\"interfaces/types_task_ActionData.BroadcastTxActionData.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":1024,\"name\":\"SOMETHING\",\"url\":\"interfaces/types_task_ActionData.BroadcastTxActionData.html#SOMETHING\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionData.BroadcastTxActionData\"},{\"kind\":1024,\"name\":\"additionalData\",\"url\":\"interfaces/types_task_ActionData.BroadcastTxActionData.html#additionalData\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionData.BroadcastTxActionData\"},{\"kind\":256,\"name\":\"ClientActionData\",\"url\":\"interfaces/types_task_ActionData.ClientActionData.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":1024,\"name\":\"SOMETHING\",\"url\":\"interfaces/types_task_ActionData.ClientActionData.html#SOMETHING\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionData.ClientActionData\"},{\"kind\":1024,\"name\":\"additionalData\",\"url\":\"interfaces/types_task_ActionData.ClientActionData.html#additionalData\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionData.ClientActionData\"},{\"kind\":4194304,\"name\":\"ActionData\",\"url\":\"types/types_task_ActionData.ActionData.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":64,\"name\":\"asGeneralActionData\",\"url\":\"functions/types_task_ActionData.asGeneralActionData.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":64,\"name\":\"asPushActionData\",\"url\":\"functions/types_task_ActionData.asPushActionData.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":64,\"name\":\"asBroadcastTxActionData\",\"url\":\"functions/types_task_ActionData.asBroadcastTxActionData.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":64,\"name\":\"asClientActionData\",\"url\":\"functions/types_task_ActionData.asClientActionData.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":64,\"name\":\"asActionData\",\"url\":\"functions/types_task_ActionData.asActionData.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionData\"},{\"kind\":2,\"name\":\"types/task/ActionEffect\",\"url\":\"modules/types_task_ActionEffect.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":256,\"name\":\"GeneralActionEffect\",\"url\":\"interfaces/types_task_ActionEffect.GeneralActionEffect.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":1024,\"name\":\"completed\",\"url\":\"interfaces/types_task_ActionEffect.GeneralActionEffect.html#completed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.GeneralActionEffect\"},{\"kind\":256,\"name\":\"SeqActionEffect\",\"url\":\"interfaces/types_task_ActionEffect.SeqActionEffect.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/types_task_ActionEffect.SeqActionEffect.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.SeqActionEffect\"},{\"kind\":1024,\"name\":\"opIndex\",\"url\":\"interfaces/types_task_ActionEffect.SeqActionEffect.html#opIndex\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.SeqActionEffect\"},{\"kind\":1024,\"name\":\"childEffect\",\"url\":\"interfaces/types_task_ActionEffect.SeqActionEffect.html#childEffect\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.SeqActionEffect\"},{\"kind\":1024,\"name\":\"completed\",\"url\":\"interfaces/types_task_ActionEffect.SeqActionEffect.html#completed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionEffect.SeqActionEffect\"},{\"kind\":256,\"name\":\"ParActionEffect\",\"url\":\"interfaces/types_task_ActionEffect.ParActionEffect.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/types_task_ActionEffect.ParActionEffect.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.ParActionEffect\"},{\"kind\":1024,\"name\":\"childEffects\",\"url\":\"interfaces/types_task_ActionEffect.ParActionEffect.html#childEffects\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.ParActionEffect\"},{\"kind\":1024,\"name\":\"completed\",\"url\":\"interfaces/types_task_ActionEffect.ParActionEffect.html#completed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionEffect.ParActionEffect\"},{\"kind\":256,\"name\":\"BalanceActionEffect\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.BalanceActionEffect\"},{\"kind\":1024,\"name\":\"address\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html#address\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.BalanceActionEffect\"},{\"kind\":1024,\"name\":\"aboveAmount\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html#aboveAmount\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.BalanceActionEffect\"},{\"kind\":1024,\"name\":\"belowAmount\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html#belowAmount\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.BalanceActionEffect\"},{\"kind\":1024,\"name\":\"walletId\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html#walletId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.BalanceActionEffect\"},{\"kind\":1024,\"name\":\"tokenId\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html#tokenId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.BalanceActionEffect\"},{\"kind\":1024,\"name\":\"completed\",\"url\":\"interfaces/types_task_ActionEffect.BalanceActionEffect.html#completed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionEffect.BalanceActionEffect\"},{\"kind\":256,\"name\":\"TxConfsActionEffect\",\"url\":\"interfaces/types_task_ActionEffect.TxConfsActionEffect.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/types_task_ActionEffect.TxConfsActionEffect.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.TxConfsActionEffect\"},{\"kind\":1024,\"name\":\"txId\",\"url\":\"interfaces/types_task_ActionEffect.TxConfsActionEffect.html#txId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.TxConfsActionEffect\"},{\"kind\":1024,\"name\":\"walletId\",\"url\":\"interfaces/types_task_ActionEffect.TxConfsActionEffect.html#walletId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.TxConfsActionEffect\"},{\"kind\":1024,\"name\":\"confirmations\",\"url\":\"interfaces/types_task_ActionEffect.TxConfsActionEffect.html#confirmations\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.TxConfsActionEffect\"},{\"kind\":1024,\"name\":\"completed\",\"url\":\"interfaces/types_task_ActionEffect.TxConfsActionEffect.html#completed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionEffect.TxConfsActionEffect\"},{\"kind\":256,\"name\":\"PriceActionEffect\",\"url\":\"interfaces/types_task_ActionEffect.PriceActionEffect.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":1024,\"name\":\"type\",\"url\":\"interfaces/types_task_ActionEffect.PriceActionEffect.html#type\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.PriceActionEffect\"},{\"kind\":1024,\"name\":\"currencyPair\",\"url\":\"interfaces/types_task_ActionEffect.PriceActionEffect.html#currencyPair\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.PriceActionEffect\"},{\"kind\":1024,\"name\":\"aboveRate\",\"url\":\"interfaces/types_task_ActionEffect.PriceActionEffect.html#aboveRate\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.PriceActionEffect\"},{\"kind\":1024,\"name\":\"belowRate\",\"url\":\"interfaces/types_task_ActionEffect.PriceActionEffect.html#belowRate\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/ActionEffect.PriceActionEffect\"},{\"kind\":1024,\"name\":\"completed\",\"url\":\"interfaces/types_task_ActionEffect.PriceActionEffect.html#completed\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface tsd-is-inherited\",\"parent\":\"types/task/ActionEffect.PriceActionEffect\"},{\"kind\":4194304,\"name\":\"ActionEffect\",\"url\":\"types/types_task_ActionEffect.ActionEffect.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":64,\"name\":\"asSeqActionEffect\",\"url\":\"functions/types_task_ActionEffect.asSeqActionEffect.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":64,\"name\":\"asParActionEffect\",\"url\":\"functions/types_task_ActionEffect.asParActionEffect.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":64,\"name\":\"asBalanceActionEffect\",\"url\":\"functions/types_task_ActionEffect.asBalanceActionEffect.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":64,\"name\":\"asTxConfsActionEffect\",\"url\":\"functions/types_task_ActionEffect.asTxConfsActionEffect.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":64,\"name\":\"asPriceActionEffect\",\"url\":\"functions/types_task_ActionEffect.asPriceActionEffect.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":64,\"name\":\"asActionEffect\",\"url\":\"functions/types_task_ActionEffect.asActionEffect.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/ActionEffect\"},{\"kind\":2,\"name\":\"types/task/Task\",\"url\":\"modules/types_task_Task.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":256,\"name\":\"Task\",\"url\":\"interfaces/types_task_Task.Task.html\",\"classes\":\"tsd-kind-interface tsd-parent-kind-module\",\"parent\":\"types/task/Task\"},{\"kind\":1024,\"name\":\"taskId\",\"url\":\"interfaces/types_task_Task.Task.html#taskId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Task.Task\"},{\"kind\":1024,\"name\":\"userId\",\"url\":\"interfaces/types_task_Task.Task.html#userId\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Task.Task\"},{\"kind\":1024,\"name\":\"actionEffects\",\"url\":\"interfaces/types_task_Task.Task.html#actionEffects\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Task.Task\"},{\"kind\":1024,\"name\":\"action\",\"url\":\"interfaces/types_task_Task.Task.html#action\",\"classes\":\"tsd-kind-property tsd-parent-kind-interface\",\"parent\":\"types/task/Task.Task\"},{\"kind\":64,\"name\":\"asTask\",\"url\":\"functions/types_task_Task.asTask.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"types/task/Task\"},{\"kind\":2,\"name\":\"utils/HTTPHelpers\",\"url\":\"modules/utils_HTTPHelpers.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":64,\"name\":\"getQueryParamObject\",\"url\":\"functions/utils_HTTPHelpers.getQueryParamObject.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/HTTPHelpers\"},{\"kind\":65536,\"name\":\"__type\",\"url\":\"functions/utils_HTTPHelpers.getQueryParamObject.html#getQueryParamObject.__type\",\"classes\":\"tsd-kind-type-literal\",\"parent\":\"utils/HTTPHelpers.getQueryParamObject.getQueryParamObject\"},{\"kind\":64,\"name\":\"convertStringToArray\",\"url\":\"functions/utils_HTTPHelpers.convertStringToArray.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/HTTPHelpers\"},{\"kind\":2,\"name\":\"utils/dbUtils\",\"url\":\"modules/utils_dbUtils.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":4194304,\"name\":\"TaskDoc\",\"url\":\"types/utils_dbUtils.TaskDoc.html\",\"classes\":\"tsd-kind-type-alias tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"asTaskDoc\",\"url\":\"functions/utils_dbUtils.asTaskDoc.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":32,\"name\":\"dbTasks\",\"url\":\"variables/utils_dbUtils.dbTasks.html\",\"classes\":\"tsd-kind-variable tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"wrappedSaveToDb\",\"url\":\"functions/utils_dbUtils.wrappedSaveToDb.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"wrappedGetFromDb\",\"url\":\"functions/utils_dbUtils.wrappedGetFromDb.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"wrappedDeleteFromDb\",\"url\":\"functions/utils_dbUtils.wrappedDeleteFromDb.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"saveToDb\",\"url\":\"functions/utils_dbUtils.saveToDb.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"deleteFromDb\",\"url\":\"functions/utils_dbUtils.deleteFromDb.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"getFromDb\",\"url\":\"functions/utils_dbUtils.getFromDb.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"logger\",\"url\":\"functions/utils_dbUtils.logger.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":64,\"name\":\"packChange\",\"url\":\"functions/utils_dbUtils.packChange.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"utils/dbUtils\"},{\"kind\":2,\"name\":\"publishers/push\",\"url\":\"modules/publishers_push.html\",\"classes\":\"tsd-kind-module\"},{\"kind\":64,\"name\":\"runPushPublisher\",\"url\":\"functions/publishers_push.runPushPublisher.html\",\"classes\":\"tsd-kind-function tsd-parent-kind-module\",\"parent\":\"publishers/push\"}],\"index\":{\"version\":\"2.3.9\",\"fields\":[\"name\",\"comment\"],\"fieldVectors\":[[\"name/0\",[0,31.226,1,27.565]],[\"comment/0\",[]],[\"name/1\",[2,43.871]],[\"comment/1\",[]],[\"name/2\",[3,35.339]],[\"comment/2\",[]],[\"name/3\",[4,43.871]],[\"comment/3\",[]],[\"name/4\",[5,38.727]],[\"comment/4\",[]],[\"name/5\",[6,43.871]],[\"comment/5\",[]],[\"name/6\",[3,35.339]],[\"comment/6\",[]],[\"name/7\",[1,27.565,7,31.226]],[\"comment/7\",[]],[\"name/8\",[8,43.871]],[\"comment/8\",[]],[\"name/9\",[9,43.871]],[\"comment/9\",[]],[\"name/10\",[10,43.871]],[\"comment/10\",[]],[\"name/11\",[11,30.788]],[\"comment/11\",[]],[\"name/12\",[12,43.871]],[\"comment/12\",[]],[\"name/13\",[11,30.788]],[\"comment/13\",[]],[\"name/14\",[13,35.339]],[\"comment/14\",[]],[\"name/15\",[14,35.339]],[\"comment/15\",[]],[\"name/16\",[15,43.871]],[\"comment/16\",[]],[\"name/17\",[11,30.788]],[\"comment/17\",[]],[\"name/18\",[13,35.339]],[\"comment/18\",[]],[\"name/19\",[14,35.339]],[\"comment/19\",[]],[\"name/20\",[16,43.871]],[\"comment/20\",[]],[\"name/21\",[11,30.788]],[\"comment/21\",[]],[\"name/22\",[13,35.339]],[\"comment/22\",[]],[\"name/23\",[14,35.339]],[\"comment/23\",[]],[\"name/24\",[17,43.871]],[\"comment/24\",[]],[\"name/25\",[18,38.727]],[\"comment/25\",[]],[\"name/26\",[19,29.106]],[\"comment/26\",[]],[\"name/27\",[20,43.871]],[\"comment/27\",[]],[\"name/28\",[21,43.871]],[\"comment/28\",[]],[\"name/29\",[22,43.871]],[\"comment/29\",[]],[\"name/30\",[23,43.871]],[\"comment/30\",[]],[\"name/31\",[24,43.871]],[\"comment/31\",[]],[\"name/32\",[25,43.871]],[\"comment/32\",[]],[\"name/33\",[26,32.808]],[\"comment/33\",[]],[\"name/34\",[27,43.871]],[\"comment/34\",[]],[\"name/35\",[5,38.727]],[\"comment/35\",[]],[\"name/36\",[28,43.871]],[\"comment/36\",[]],[\"name/37\",[3,35.339]],[\"comment/37\",[]],[\"name/38\",[29,43.871]],[\"comment/38\",[]],[\"name/39\",[26,32.808]],[\"comment/39\",[]],[\"name/40\",[30,43.871]],[\"comment/40\",[]],[\"name/41\",[31,38.727]],[\"comment/41\",[]],[\"name/42\",[26,32.808]],[\"comment/42\",[]],[\"name/43\",[32,43.871]],[\"comment/43\",[]],[\"name/44\",[31,38.727]],[\"comment/44\",[]],[\"name/45\",[26,32.808]],[\"comment/45\",[]],[\"name/46\",[33,43.871]],[\"comment/46\",[]],[\"name/47\",[34,43.871]],[\"comment/47\",[]],[\"name/48\",[35,43.871]],[\"comment/48\",[]],[\"name/49\",[36,43.871]],[\"comment/49\",[]],[\"name/50\",[37,43.871]],[\"comment/50\",[]],[\"name/51\",[38,43.871]],[\"comment/51\",[]],[\"name/52\",[39,43.871]],[\"comment/52\",[]],[\"name/53\",[40,43.871]],[\"comment/53\",[]],[\"name/54\",[41,29.106]],[\"comment/54\",[]],[\"name/55\",[42,43.871]],[\"comment/55\",[]],[\"name/56\",[19,29.106]],[\"comment/56\",[]],[\"name/57\",[43,43.871]],[\"comment/57\",[]],[\"name/58\",[44,43.871]],[\"comment/58\",[]],[\"name/59\",[41,29.106]],[\"comment/59\",[]],[\"name/60\",[45,43.871]],[\"comment/60\",[]],[\"name/61\",[19,29.106]],[\"comment/61\",[]],[\"name/62\",[46,43.871]],[\"comment/62\",[]],[\"name/63\",[41,29.106]],[\"comment/63\",[]],[\"name/64\",[47,43.871]],[\"comment/64\",[]],[\"name/65\",[19,29.106]],[\"comment/65\",[]],[\"name/66\",[48,43.871]],[\"comment/66\",[]],[\"name/67\",[49,43.871]],[\"comment/67\",[]],[\"name/68\",[50,43.871]],[\"comment/68\",[]],[\"name/69\",[51,38.727]],[\"comment/69\",[]],[\"name/70\",[52,43.871]],[\"comment/70\",[]],[\"name/71\",[41,29.106]],[\"comment/71\",[]],[\"name/72\",[53,43.871]],[\"comment/72\",[]],[\"name/73\",[19,29.106]],[\"comment/73\",[]],[\"name/74\",[54,43.871]],[\"comment/74\",[]],[\"name/75\",[51,38.727]],[\"comment/75\",[]],[\"name/76\",[55,43.871]],[\"comment/76\",[]],[\"name/77\",[41,29.106]],[\"comment/77\",[]],[\"name/78\",[56,43.871]],[\"comment/78\",[]],[\"name/79\",[19,29.106]],[\"comment/79\",[]],[\"name/80\",[57,43.871]],[\"comment/80\",[]],[\"name/81\",[58,43.871]],[\"comment/81\",[]],[\"name/82\",[59,43.871]],[\"comment/82\",[]],[\"name/83\",[41,29.106]],[\"comment/83\",[]],[\"name/84\",[60,43.871]],[\"comment/84\",[]],[\"name/85\",[61,43.871]],[\"comment/85\",[]],[\"name/86\",[62,43.871]],[\"comment/86\",[]],[\"name/87\",[63,43.871]],[\"comment/87\",[]],[\"name/88\",[64,43.871]],[\"comment/88\",[]],[\"name/89\",[65,43.871]],[\"comment/89\",[]],[\"name/90\",[66,43.871]],[\"comment/90\",[]],[\"name/91\",[67,43.871]],[\"comment/91\",[]],[\"name/92\",[68,43.871]],[\"comment/92\",[]],[\"name/93\",[69,43.871]],[\"comment/93\",[]],[\"name/94\",[70,43.871]],[\"comment/94\",[]],[\"name/95\",[71,43.871]],[\"comment/95\",[]],[\"name/96\",[18,38.727]],[\"comment/96\",[]],[\"name/97\",[72,43.871]],[\"comment/97\",[]],[\"name/98\",[73,43.871]],[\"comment/98\",[]],[\"name/99\",[74,43.871]],[\"comment/99\",[]],[\"name/100\",[11,30.788]],[\"comment/100\",[]],[\"name/101\",[75,43.871]],[\"comment/101\",[]],[\"name/102\",[76,43.871]],[\"comment/102\",[]],[\"name/103\",[77,43.871]],[\"comment/103\",[]],[\"name/104\",[78,43.871]],[\"comment/104\",[]],[\"name/105\",[79,43.871]],[\"comment/105\",[]],[\"name/106\",[80,43.871]],[\"comment/106\",[]],[\"name/107\",[81,43.871]],[\"comment/107\",[]],[\"name/108\",[82,43.871]],[\"comment/108\",[]],[\"name/109\",[83,43.871]],[\"comment/109\",[]],[\"name/110\",[84,43.871]],[\"comment/110\",[]],[\"name/111\",[85,43.871]],[\"comment/111\",[]],[\"name/112\",[86,43.871]],[\"comment/112\",[]],[\"name/113\",[87,43.871]],[\"comment/113\",[]],[\"name/114\",[88,43.871]],[\"comment/114\",[]],[\"name/115\",[89,43.871]],[\"comment/115\",[]]],\"invertedIndex\":[[\"__type\",{\"_index\":11,\"name\":{\"11\":{},\"13\":{},\"17\":{},\"21\":{},\"100\":{}},\"comment\":{}}],[\"aboveamount\",{\"_index\":49,\"name\":{\"67\":{}},\"comment\":{}}],[\"aboverate\",{\"_index\":58,\"name\":{\"81\":{}},\"comment\":{}}],[\"action\",{\"_index\":18,\"name\":{\"25\":{},\"96\":{}},\"comment\":{}}],[\"actiondata\",{\"_index\":33,\"name\":{\"46\":{}},\"comment\":{}}],[\"actioneffect\",{\"_index\":60,\"name\":{\"84\":{}},\"comment\":{}}],[\"actioneffects\",{\"_index\":71,\"name\":{\"95\":{}},\"comment\":{}}],[\"additionaldata\",{\"_index\":26,\"name\":{\"33\":{},\"39\":{},\"42\":{},\"45\":{}},\"comment\":{}}],[\"address\",{\"_index\":48,\"name\":{\"66\":{}},\"comment\":{}}],[\"apikey\",{\"_index\":5,\"name\":{\"4\":{},\"35\":{}},\"comment\":{}}],[\"apirequest\",{\"_index\":4,\"name\":{\"3\":{}},\"comment\":{}}],[\"asaction\",{\"_index\":23,\"name\":{\"30\":{}},\"comment\":{}}],[\"asactiondata\",{\"_index\":38,\"name\":{\"51\":{}},\"comment\":{}}],[\"asactioneffect\",{\"_index\":66,\"name\":{\"90\":{}},\"comment\":{}}],[\"asbalanceactioneffect\",{\"_index\":63,\"name\":{\"87\":{}},\"comment\":{}}],[\"asbroadcasttxactiondata\",{\"_index\":36,\"name\":{\"49\":{}},\"comment\":{}}],[\"asclientactiondata\",{\"_index\":37,\"name\":{\"50\":{}},\"comment\":{}}],[\"asgeneralactiondata\",{\"_index\":34,\"name\":{\"47\":{}},\"comment\":{}}],[\"asparactioneffect\",{\"_index\":62,\"name\":{\"86\":{}},\"comment\":{}}],[\"aspriceactioneffect\",{\"_index\":65,\"name\":{\"89\":{}},\"comment\":{}}],[\"aspushactiondata\",{\"_index\":35,\"name\":{\"48\":{}},\"comment\":{}}],[\"asseqactioneffect\",{\"_index\":61,\"name\":{\"85\":{}},\"comment\":{}}],[\"astask\",{\"_index\":72,\"name\":{\"97\":{}},\"comment\":{}}],[\"astaskdoc\",{\"_index\":78,\"name\":{\"104\":{}},\"comment\":{}}],[\"astxconfsactioneffect\",{\"_index\":64,\"name\":{\"88\":{}},\"comment\":{}}],[\"balanceactioneffect\",{\"_index\":47,\"name\":{\"64\":{}},\"comment\":{}}],[\"belowamount\",{\"_index\":50,\"name\":{\"68\":{}},\"comment\":{}}],[\"belowrate\",{\"_index\":59,\"name\":{\"82\":{}},\"comment\":{}}],[\"body\",{\"_index\":3,\"name\":{\"2\":{},\"6\":{},\"37\":{}},\"comment\":{}}],[\"broadcasttxactiondata\",{\"_index\":30,\"name\":{\"40\":{}},\"comment\":{}}],[\"childeffect\",{\"_index\":44,\"name\":{\"58\":{}},\"comment\":{}}],[\"childeffects\",{\"_index\":46,\"name\":{\"62\":{}},\"comment\":{}}],[\"clientactiondata\",{\"_index\":32,\"name\":{\"43\":{}},\"comment\":{}}],[\"completed\",{\"_index\":41,\"name\":{\"54\":{},\"59\":{},\"63\":{},\"71\":{},\"77\":{},\"83\":{}},\"comment\":{}}],[\"confirmations\",{\"_index\":55,\"name\":{\"76\":{}},\"comment\":{}}],[\"convertstringtoarray\",{\"_index\":75,\"name\":{\"101\":{}},\"comment\":{}}],[\"currencypair\",{\"_index\":57,\"name\":{\"80\":{}},\"comment\":{}}],[\"data\",{\"_index\":22,\"name\":{\"29\":{}},\"comment\":{}}],[\"dbtasks\",{\"_index\":79,\"name\":{\"105\":{}},\"comment\":{}}],[\"deletefromdb\",{\"_index\":84,\"name\":{\"110\":{}},\"comment\":{}}],[\"extendedrequest\",{\"_index\":2,\"name\":{\"1\":{}},\"comment\":{}}],[\"generalactiondata\",{\"_index\":25,\"name\":{\"32\":{}},\"comment\":{}}],[\"generalactioneffect\",{\"_index\":40,\"name\":{\"53\":{}},\"comment\":{}}],[\"getfromdb\",{\"_index\":85,\"name\":{\"111\":{}},\"comment\":{}}],[\"getqueryparamobject\",{\"_index\":74,\"name\":{\"99\":{}},\"comment\":{}}],[\"httpstatus\",{\"_index\":13,\"name\":{\"14\":{},\"18\":{},\"22\":{}},\"comment\":{}}],[\"inprogress\",{\"_index\":21,\"name\":{\"28\":{}},\"comment\":{}}],[\"internal_server_error\",{\"_index\":15,\"name\":{\"16\":{}},\"comment\":{}}],[\"jsonresponse\",{\"_index\":8,\"name\":{\"8\":{}},\"comment\":{}}],[\"logger\",{\"_index\":86,\"name\":{\"112\":{}},\"comment\":{}}],[\"message\",{\"_index\":14,\"name\":{\"15\":{},\"19\":{},\"23\":{}},\"comment\":{}}],[\"opindex\",{\"_index\":43,\"name\":{\"57\":{}},\"comment\":{}}],[\"packchange\",{\"_index\":87,\"name\":{\"113\":{}},\"comment\":{}}],[\"page_not_found\",{\"_index\":16,\"name\":{\"20\":{}},\"comment\":{}}],[\"paractioneffect\",{\"_index\":45,\"name\":{\"60\":{}},\"comment\":{}}],[\"payload\",{\"_index\":6,\"name\":{\"5\":{}},\"comment\":{}}],[\"priceactioneffect\",{\"_index\":56,\"name\":{\"78\":{}},\"comment\":{}}],[\"publishers/push\",{\"_index\":88,\"name\":{\"114\":{}},\"comment\":{}}],[\"pushactiondata\",{\"_index\":27,\"name\":{\"34\":{}},\"comment\":{}}],[\"repeat\",{\"_index\":20,\"name\":{\"27\":{}},\"comment\":{}}],[\"runpushpublisher\",{\"_index\":89,\"name\":{\"115\":{}},\"comment\":{}}],[\"savetodb\",{\"_index\":83,\"name\":{\"109\":{}},\"comment\":{}}],[\"seqactioneffect\",{\"_index\":42,\"name\":{\"55\":{}},\"comment\":{}}],[\"something\",{\"_index\":31,\"name\":{\"41\":{},\"44\":{}},\"comment\":{}}],[\"statuscodes\",{\"_index\":10,\"name\":{\"10\":{}},\"comment\":{}}],[\"statusresponse\",{\"_index\":9,\"name\":{\"9\":{}},\"comment\":{}}],[\"success\",{\"_index\":12,\"name\":{\"12\":{}},\"comment\":{}}],[\"task\",{\"_index\":68,\"name\":{\"92\":{}},\"comment\":{}}],[\"taskdoc\",{\"_index\":77,\"name\":{\"103\":{}},\"comment\":{}}],[\"taskid\",{\"_index\":69,\"name\":{\"93\":{}},\"comment\":{}}],[\"title\",{\"_index\":28,\"name\":{\"36\":{}},\"comment\":{}}],[\"tokenid\",{\"_index\":52,\"name\":{\"70\":{}},\"comment\":{}}],[\"tokenids\",{\"_index\":29,\"name\":{\"38\":{}},\"comment\":{}}],[\"txconfsactioneffect\",{\"_index\":53,\"name\":{\"72\":{}},\"comment\":{}}],[\"txid\",{\"_index\":54,\"name\":{\"74\":{}},\"comment\":{}}],[\"type\",{\"_index\":19,\"name\":{\"26\":{},\"56\":{},\"61\":{},\"65\":{},\"73\":{},\"79\":{}},\"comment\":{}}],[\"types\",{\"_index\":1,\"name\":{\"0\":{},\"7\":{}},\"comment\":{}}],[\"types/http/request\",{\"_index\":0,\"name\":{\"0\":{}},\"comment\":{}}],[\"types/http/response\",{\"_index\":7,\"name\":{\"7\":{}},\"comment\":{}}],[\"types/task/action\",{\"_index\":17,\"name\":{\"24\":{}},\"comment\":{}}],[\"types/task/actiondata\",{\"_index\":24,\"name\":{\"31\":{}},\"comment\":{}}],[\"types/task/actioneffect\",{\"_index\":39,\"name\":{\"52\":{}},\"comment\":{}}],[\"types/task/task\",{\"_index\":67,\"name\":{\"91\":{}},\"comment\":{}}],[\"userid\",{\"_index\":70,\"name\":{\"94\":{}},\"comment\":{}}],[\"utils/dbutils\",{\"_index\":76,\"name\":{\"102\":{}},\"comment\":{}}],[\"utils/httphelpers\",{\"_index\":73,\"name\":{\"98\":{}},\"comment\":{}}],[\"walletid\",{\"_index\":51,\"name\":{\"69\":{},\"75\":{}},\"comment\":{}}],[\"wrappeddeletefromdb\",{\"_index\":82,\"name\":{\"108\":{}},\"comment\":{}}],[\"wrappedgetfromdb\",{\"_index\":81,\"name\":{\"107\":{}},\"comment\":{}}],[\"wrappedsavetodb\",{\"_index\":80,\"name\":{\"106\":{}},\"comment\":{}}]],\"pipeline\":[]}}"); \ No newline at end of file diff --git a/docs/references/assets/style.css b/docs/references/assets/style.css new file mode 100644 index 0000000..8f6ed2c --- /dev/null +++ b/docs/references/assets/style.css @@ -0,0 +1,1224 @@ +:root { + /* Light */ + --light-color-background: #f2f4f8; + --light-color-background-secondary: #eff0f1; + --light-color-icon-background: var(--light-color-background); + --light-color-accent: #c5c7c9; + --light-color-text: #222; + --light-color-text-aside: #707070; + --light-color-link: #4da6ff; + --light-color-ts: #db1373; + --light-color-ts-interface: #139d2c; + --light-color-ts-enum: #9c891a; + --light-color-ts-class: #2484e5; + --light-color-ts-function: #572be7; + --light-color-ts-namespace: #b111c9; + --light-color-ts-private: #707070; + --light-color-ts-variable: #4d68ff; + --light-external-icon: url("data:image/svg+xml;utf8,"); + --light-color-scheme: light; + + /* Dark */ + --dark-color-background: #2b2e33; + --dark-color-background-secondary: #1e2024; + --dark-color-icon-background: var(--dark-color-background-secondary); + --dark-color-accent: #9096a2; + --dark-color-text: #f5f5f5; + --dark-color-text-aside: #dddddd; + --dark-color-link: #00aff4; + --dark-color-ts: #ff6492; + --dark-color-ts-interface: #6cff87; + --dark-color-ts-enum: #f4d93e; + --dark-color-ts-class: #61b0ff; + --dark-color-ts-function: #9772ff; + --dark-color-ts-namespace: #e14dff; + --dark-color-ts-private: #e2e2e2; + --dark-color-ts-variable: #4d68ff; + --dark-external-icon: url("data:image/svg+xml;utf8,"); + --dark-color-scheme: dark; +} + +@media (prefers-color-scheme: light) { + :root { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + --color-ts: var(--light-color-ts); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-class: var(--light-color-ts-class); + --color-ts-function: var(--light-color-ts-function); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-private: var(--light-color-ts-private); + --color-ts-variable: var(--light-color-ts-variable); + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + --color-ts: var(--dark-color-ts); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-private: var(--dark-color-ts-private); + --color-ts-variable: var(--dark-color-ts-variable); + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } +} + +html { + color-scheme: var(--color-scheme); +} + +body { + margin: 0; +} + +:root[data-theme="light"] { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + --color-ts: var(--light-color-ts); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-class: var(--light-color-ts-class); + --color-ts-function: var(--light-color-ts-function); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-private: var(--light-color-ts-private); + --color-ts-variable: var(--light-color-ts-variable); + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); +} + +:root[data-theme="dark"] { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + --color-ts: var(--dark-color-ts); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-private: var(--dark-color-ts-private); + --color-ts-variable: var(--dark-color-ts-variable); + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1.2; +} + +h1 { + font-size: 1.875rem; + margin: 0.67rem 0; +} + +h2 { + font-size: 1.5rem; + margin: 0.83rem 0; +} + +h3 { + font-size: 1.25rem; + margin: 1rem 0; +} + +h4 { + font-size: 1.05rem; + margin: 1.33rem 0; +} + +h5 { + font-size: 1rem; + margin: 1.5rem 0; +} + +h6 { + font-size: 0.875rem; + margin: 2.33rem 0; +} + +.uppercase { + text-transform: uppercase; +} + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +dl, +menu, +ol, +ul { + margin: 1em 0; +} + +dd { + margin: 0 0 0 40px; +} + +.container { + max-width: 1600px; + padding: 0 2rem; +} + +@media (min-width: 640px) { + .container { + padding: 0 4rem; + } +} +@media (min-width: 1200px) { + .container { + padding: 0 8rem; + } +} +@media (min-width: 1600px) { + .container { + padding: 0 12rem; + } +} + +/* Footer */ +.tsd-generator { + border-top: 1px solid var(--color-accent); + padding-top: 1rem; + padding-bottom: 1rem; + max-height: 3.5rem; +} + +.tsd-generator > p { + margin-top: 0; + margin-bottom: 0; + padding: 0 1rem; +} + +.container-main { + display: flex; + justify-content: space-between; + position: relative; + margin: 0 auto; +} + +.col-4, +.col-8 { + box-sizing: border-box; + float: left; + padding: 2rem 1rem; +} + +.col-4 { + flex: 0 0 25%; +} +.col-8 { + flex: 1 0; + flex-wrap: wrap; + padding-left: 0; +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +@keyframes fade-out { + from { + opacity: 1; + visibility: visible; + } + to { + opacity: 0; + } +} +@keyframes fade-in-delayed { + 0% { + opacity: 0; + } + 33% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +@keyframes fade-out-delayed { + 0% { + opacity: 1; + visibility: visible; + } + 66% { + opacity: 0; + } + 100% { + opacity: 0; + } +} +@keyframes shift-to-left { + from { + transform: translate(0, 0); + } + to { + transform: translate(-25%, 0); + } +} +@keyframes unshift-to-left { + from { + transform: translate(-25%, 0); + } + to { + transform: translate(0, 0); + } +} +@keyframes pop-in-from-right { + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } +} +@keyframes pop-out-to-right { + from { + transform: translate(0, 0); + visibility: visible; + } + to { + transform: translate(100%, 0); + } +} +body { + background: var(--color-background); + font-family: "Segoe UI", sans-serif; + font-size: 16px; + color: var(--color-text); +} + +a { + color: var(--color-link); + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +a.external[target="_blank"] { + background-image: var(--external-icon); + background-position: top 3px right; + background-repeat: no-repeat; + padding-right: 13px; +} + +code, +pre { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 0.2em; + margin: 0; + font-size: 0.875rem; + border-radius: 0.8em; +} + +pre { + padding: 10px; + border: 0.1em solid var(--color-accent); +} +pre code { + padding: 0; + font-size: 100%; +} + +blockquote { + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid gray; +} + +.tsd-typography { + line-height: 1.333em; +} +.tsd-typography ul { + list-style: square; + padding: 0 0 0 20px; + margin: 0; +} +.tsd-typography h4, +.tsd-typography .tsd-index-panel h3, +.tsd-index-panel .tsd-typography h3, +.tsd-typography h5, +.tsd-typography h6 { + font-size: 1em; + margin: 0; +} +.tsd-typography h5, +.tsd-typography h6 { + font-weight: normal; +} +.tsd-typography p, +.tsd-typography ul, +.tsd-typography ol { + margin: 1em 0; +} + +@media (max-width: 1024px) { + html .col-content { + float: none; + max-width: 100%; + width: 100%; + padding-top: 3rem; + } + html .col-menu { + position: fixed !important; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 1024; + top: 0 !important; + bottom: 0 !important; + left: auto !important; + right: 0 !important; + padding: 1.5rem 1.5rem 0 0; + max-width: 25rem; + visibility: hidden; + background-color: var(--color-background); + transform: translate(100%, 0); + } + html .col-menu > *:last-child { + padding-bottom: 20px; + } + html .overlay { + content: ""; + display: block; + position: fixed; + z-index: 1023; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + visibility: hidden; + } + + .to-has-menu .overlay { + animation: fade-in 0.4s; + } + + .to-has-menu :is(header, footer, .col-content) { + animation: shift-to-left 0.4s; + } + + .to-has-menu .col-menu { + animation: pop-in-from-right 0.4s; + } + + .from-has-menu .overlay { + animation: fade-out 0.4s; + } + + .from-has-menu :is(header, footer, .col-content) { + animation: unshift-to-left 0.4s; + } + + .from-has-menu .col-menu { + animation: pop-out-to-right 0.4s; + } + + .has-menu body { + overflow: hidden; + } + .has-menu .overlay { + visibility: visible; + } + .has-menu :is(header, footer, .col-content) { + transform: translate(-25%, 0); + } + .has-menu .col-menu { + visibility: visible; + transform: translate(0, 0); + display: grid; + align-items: center; + grid-template-rows: auto 1fr; + grid-gap: 1.5rem; + max-height: 100vh; + padding: 1rem 2rem; + } + .has-menu .tsd-navigation { + max-height: 100%; + } +} + +.tsd-breadcrumb { + margin: 0; + padding: 0; + color: var(--color-text-aside); +} +.tsd-breadcrumb a { + color: var(--color-text-aside); + text-decoration: none; +} +.tsd-breadcrumb a:hover { + text-decoration: underline; +} +.tsd-breadcrumb li { + display: inline; +} +.tsd-breadcrumb li:after { + content: " / "; +} + +.tsd-comment-tags { + display: flex; + flex-direction: column; +} +dl.tsd-comment-tag-group { + display: flex; + align-items: center; + overflow: hidden; + margin: 0.5em 0; +} +dl.tsd-comment-tag-group dt { + display: flex; + margin-right: 0.5em; + font-size: 0.875em; + font-weight: normal; +} +dl.tsd-comment-tag-group dd { + margin: 0; +} +code.tsd-tag { + padding: 0.25em 0.4em; + border: 0.1em solid var(--color-accent); + margin-right: 0.25em; + font-size: 70%; +} +h1 code.tsd-tag:first-of-type { + margin-left: 0.25em; +} + +dl.tsd-comment-tag-group dd:before, +dl.tsd-comment-tag-group dd:after { + content: " "; +} +dl.tsd-comment-tag-group dd pre, +dl.tsd-comment-tag-group dd:after { + clear: both; +} +dl.tsd-comment-tag-group p { + margin: 0; +} + +.tsd-panel.tsd-comment .lead { + font-size: 1.1em; + line-height: 1.333em; + margin-bottom: 2em; +} +.tsd-panel.tsd-comment .lead:last-child { + margin-bottom: 0; +} + +.tsd-filter-visibility h4 { + font-size: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.5rem; + margin: 0; +} +.tsd-filter-item:not(:last-child) { + margin-bottom: 0.5rem; +} +.tsd-filter-input { + display: flex; + width: fit-content; + width: -moz-fit-content; + align-items: center; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + cursor: pointer; +} +.tsd-filter-input input[type="checkbox"] { + cursor: pointer; + position: absolute; + width: 1.5em; + height: 1.5em; + opacity: 0; +} +.tsd-filter-input input[type="checkbox"]:disabled { + pointer-events: none; +} +.tsd-filter-input svg { + cursor: pointer; + width: 1.5em; + height: 1.5em; + margin-right: 0.5em; + border-radius: 0.33em; + /* Leaving this at full opacity breaks event listeners on Firefox. + Don't remove unless you know what you're doing. */ + opacity: 0.99; +} +.tsd-filter-input input[type="checkbox"]:focus + svg { + transform: scale(0.95); +} +.tsd-filter-input input[type="checkbox"]:focus:not(:focus-visible) + svg { + transform: scale(1); +} +.tsd-checkbox-background { + fill: var(--color-accent); +} +input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { + stroke: var(--color-text); +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { + fill: var(--color-background); + stroke: var(--color-accent); + stroke-width: 0.25rem; +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { + stroke: var(--color-accent); +} + +.tsd-theme-toggle { + padding-top: 0.75rem; +} +.tsd-theme-toggle > h4 { + display: inline; + vertical-align: middle; + margin-right: 0.75rem; +} + +.tsd-hierarchy { + list-style: square; + margin: 0; +} +.tsd-hierarchy .target { + font-weight: bold; +} + +.tsd-panel-group.tsd-index-group { + margin-bottom: 0; +} +.tsd-index-panel .tsd-index-list { + list-style: none; + line-height: 1.333em; + margin: 0; + padding: 0.25rem 0 0 0; + overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + column-gap: 1rem; + grid-template-rows: auto; +} +@media (max-width: 1024px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(2, 1fr); + } +} +@media (max-width: 768px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(1, 1fr); + } +} +.tsd-index-panel .tsd-index-list li { + -webkit-page-break-inside: avoid; + -moz-page-break-inside: avoid; + -ms-page-break-inside: avoid; + -o-page-break-inside: avoid; + page-break-inside: avoid; +} +.tsd-index-panel a, +.tsd-index-panel a.tsd-parent-kind-module { + color: var(--color-ts); +} +.tsd-index-panel a.tsd-parent-kind-interface { + color: var(--color-ts-interface); +} +.tsd-index-panel a.tsd-parent-kind-enum { + color: var(--color-ts-enum); +} +.tsd-index-panel a.tsd-parent-kind-class { + color: var(--color-ts-class); +} +.tsd-index-panel a.tsd-kind-module { + color: var(--color-ts-namespace); +} +.tsd-index-panel a.tsd-kind-interface { + color: var(--color-ts-interface); +} +.tsd-index-panel a.tsd-kind-enum { + color: var(--color-ts-enum); +} +.tsd-index-panel a.tsd-kind-class { + color: var(--color-ts-class); +} +.tsd-index-panel a.tsd-kind-function { + color: var(--color-ts-function); +} +.tsd-index-panel a.tsd-kind-namespace { + color: var(--color-ts-namespace); +} +.tsd-index-panel a.tsd-kind-variable { + color: var(--color-ts-variable); +} +.tsd-index-panel a.tsd-is-private { + color: var(--color-ts-private); +} + +.tsd-flag { + display: inline-block; + padding: 0.25em 0.4em; + border-radius: 4px; + color: var(--color-comment-tag-text); + background-color: var(--color-comment-tag); + text-indent: 0; + font-size: 75%; + line-height: 1; + font-weight: normal; +} + +.tsd-anchor { + position: absolute; + top: -100px; +} + +.tsd-member { + position: relative; +} +.tsd-member .tsd-anchor + h3 { + display: flex; + align-items: center; + margin-top: 0; + margin-bottom: 0; + border-bottom: none; +} +.tsd-member [data-tsd-kind] { + color: var(--color-ts); +} +.tsd-member [data-tsd-kind="Interface"] { + color: var(--color-ts-interface); +} +.tsd-member [data-tsd-kind="Enum"] { + color: var(--color-ts-enum); +} +.tsd-member [data-tsd-kind="Class"] { + color: var(--color-ts-class); +} +.tsd-member [data-tsd-kind="Private"] { + color: var(--color-ts-private); +} + +.tsd-navigation a { + display: block; + margin: 0.4rem 0; + border-left: 2px solid transparent; + color: var(--color-text); + text-decoration: none; + transition: border-left-color 0.1s; +} +.tsd-navigation a:hover { + text-decoration: underline; +} +.tsd-navigation ul { + margin: 0; + padding: 0; + list-style: none; +} +.tsd-navigation li { + padding: 0; +} + +.tsd-navigation.primary .tsd-accordion-details > ul { + margin-top: 0.75rem; +} +.tsd-navigation.primary a { + padding: 0.75rem 0.5rem; + margin: 0; +} +.tsd-navigation.primary ul li a { + margin-left: 0.5rem; +} +.tsd-navigation.primary ul li li a { + margin-left: 1.5rem; +} +.tsd-navigation.primary ul li li li a { + margin-left: 2.5rem; +} +.tsd-navigation.primary ul li li li li a { + margin-left: 3.5rem; +} +.tsd-navigation.primary ul li li li li li a { + margin-left: 4.5rem; +} +.tsd-navigation.primary ul li li li li li li a { + margin-left: 5.5rem; +} +.tsd-navigation.primary li.current > a { + border-left: 0.15rem var(--color-text) solid; +} +.tsd-navigation.primary li.selected > a { + font-weight: bold; + border-left: 0.2rem var(--color-text) solid; +} +.tsd-navigation.primary ul li a:hover { + border-left: 0.2rem var(--color-text-aside) solid; +} +.tsd-navigation.primary li.globals + li > span, +.tsd-navigation.primary li.globals + li > a { + padding-top: 20px; +} + +.tsd-navigation.secondary.tsd-navigation--toolbar-hide { + max-height: calc(100vh - 1rem); + top: 0.5rem; +} +.tsd-navigation.secondary > ul { + display: inline; + padding-right: 0.5rem; + transition: opacity 0.2s; +} +.tsd-navigation.secondary ul li a { + padding-left: 0; +} +.tsd-navigation.secondary ul li li a { + padding-left: 1.1rem; +} +.tsd-navigation.secondary ul li li li a { + padding-left: 2.2rem; +} +.tsd-navigation.secondary ul li li li li a { + padding-left: 3.3rem; +} +.tsd-navigation.secondary ul li li li li li a { + padding-left: 4.4rem; +} +.tsd-navigation.secondary ul li li li li li li a { + padding-left: 5.5rem; +} + +a.tsd-index-link { + margin: 0.25rem 0; + font-size: 1rem; + line-height: 1.25rem; + display: inline-flex; + align-items: center; +} +.tsd-accordion-summary > h1, +.tsd-accordion-summary > h2, +.tsd-accordion-summary > h3, +.tsd-accordion-summary > h4, +.tsd-accordion-summary > h5 { + display: inline-flex; + align-items: center; + vertical-align: middle; + margin-bottom: 0; + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; +} +.tsd-accordion-summary { + display: block; + cursor: pointer; +} +.tsd-accordion-summary > * { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} +.tsd-accordion-summary::-webkit-details-marker { + display: none; +} +.tsd-index-accordion .tsd-accordion-summary svg { + margin-right: 0.25rem; +} +.tsd-index-content > :not(:first-child) { + margin-top: 0.75rem; +} +.tsd-index-heading { + margin-top: 1.5rem; + margin-bottom: 0.75rem; +} + +.tsd-kind-icon { + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; + min-width: 1.25rem; + min-height: 1.25rem; +} +.tsd-kind-icon path { + transform-origin: center; + transform: scale(1.1); +} +.tsd-signature > .tsd-kind-icon { + margin-right: 0.8rem; +} + +@media (min-width: 1024px) { + .col-content { + margin: 2rem auto; + } + + .menu-sticky-wrap { + position: sticky; + height: calc(100vh - 2rem); + top: 4rem; + right: 0; + padding: 0 1.5rem; + padding-top: 1rem; + margin-top: 3rem; + transition: 0.3s ease-in-out; + transition-property: top, padding-top, padding, height; + overflow-y: auto; + } + .col-menu { + border-left: 1px solid var(--color-accent); + } + .col-menu--hide { + top: 1rem; + } + .col-menu .tsd-navigation:not(:last-child) { + padding-bottom: 1.75rem; + } +} + +.tsd-panel { + margin-bottom: 2.5rem; +} +.tsd-panel.tsd-member { + margin-bottom: 4rem; +} +.tsd-panel:empty { + display: none; +} +.tsd-panel > h1, +.tsd-panel > h2, +.tsd-panel > h3 { + margin: 1.5rem -1.5rem 0.75rem -1.5rem; + padding: 0 1.5rem 0.75rem 1.5rem; +} +.tsd-panel > h1.tsd-before-signature, +.tsd-panel > h2.tsd-before-signature, +.tsd-panel > h3.tsd-before-signature { + margin-bottom: 0; + border-bottom: none; +} + +.tsd-panel-group { + margin: 4rem 0; +} +.tsd-panel-group.tsd-index-group { + margin: 2rem 0; +} +.tsd-panel-group.tsd-index-group details { + margin: 2rem 0; +} + +#tsd-search { + transition: background-color 0.2s; +} +#tsd-search .title { + position: relative; + z-index: 2; +} +#tsd-search .field { + position: absolute; + left: 0; + top: 0; + right: 2.5rem; + height: 100%; +} +#tsd-search .field input { + box-sizing: border-box; + position: relative; + top: -50px; + z-index: 1; + width: 100%; + padding: 0 10px; + opacity: 0; + outline: 0; + border: 0; + background: transparent; + color: var(--color-text); +} +#tsd-search .field label { + position: absolute; + overflow: hidden; + right: -40px; +} +#tsd-search .field input, +#tsd-search .title { + transition: opacity 0.2s; +} +#tsd-search .results { + position: absolute; + visibility: hidden; + top: 40px; + width: 100%; + margin: 0; + padding: 0; + list-style: none; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); +} +#tsd-search .results li { + padding: 0 10px; + background-color: var(--color-background); +} +#tsd-search .results li:nth-child(even) { + background-color: var(--color-background-secondary); +} +#tsd-search .results li.state { + display: none; +} +#tsd-search .results li.current, +#tsd-search .results li:hover { + background-color: var(--color-accent); +} +#tsd-search .results a { + display: block; +} +#tsd-search .results a:before { + top: 10px; +} +#tsd-search .results span.parent { + color: var(--color-text-aside); + font-weight: normal; +} +#tsd-search.has-focus { + background-color: var(--color-accent); +} +#tsd-search.has-focus .field input { + top: 0; + opacity: 1; +} +#tsd-search.has-focus .title { + z-index: 0; + opacity: 0; +} +#tsd-search.has-focus .results { + visibility: visible; +} +#tsd-search.loading .results li.state.loading { + display: block; +} +#tsd-search.failure .results li.state.failure { + display: block; +} + +.tsd-signature { + margin: 0 0 1rem 0; + padding: 1rem 0.5rem; + border: 1px solid var(--color-accent); + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 14px; + overflow-x: auto; +} + +.tsd-signature-symbol { + color: var(--color-text-aside); + font-weight: normal; +} + +.tsd-signature-type { + font-style: italic; + font-weight: normal; +} + +.tsd-signatures { + padding: 0; + margin: 0 0 1em 0; + list-style-type: none; +} +.tsd-signatures .tsd-signature { + margin: 0; + border-color: var(--color-accent); + border-width: 1px 0; + transition: background-color 0.1s; +} +.tsd-description .tsd-signatures .tsd-signature { + border-width: 1px; +} + +ul.tsd-parameter-list, +ul.tsd-type-parameter-list { + list-style: square; + margin: 0; + padding-left: 20px; +} +ul.tsd-parameter-list > li.tsd-parameter-signature, +ul.tsd-type-parameter-list > li.tsd-parameter-signature { + list-style: none; + margin-left: -20px; +} +ul.tsd-parameter-list h5, +ul.tsd-type-parameter-list h5 { + font-size: 16px; + margin: 1em 0 0.5em 0; +} +.tsd-sources { + margin-top: 1rem; + font-size: 0.875em; +} +.tsd-sources a { + color: var(--color-text-aside); + text-decoration: underline; +} +.tsd-sources ul { + list-style: none; + padding: 0; +} + +.tsd-page-toolbar { + position: fixed; + z-index: 1; + top: 0; + left: 0; + width: 100%; + color: var(--color-text); + background: var(--color-background-secondary); + border-bottom: 1px var(--color-accent) solid; + transition: transform 0.3s ease-in-out; +} +.tsd-page-toolbar a { + color: var(--color-text); + text-decoration: none; +} +.tsd-page-toolbar a.title { + font-weight: bold; +} +.tsd-page-toolbar a.title:hover { + text-decoration: underline; +} +.tsd-page-toolbar .tsd-toolbar-contents { + display: flex; + justify-content: space-between; + height: 2.5rem; +} +.tsd-page-toolbar .table-cell { + position: relative; + white-space: nowrap; + line-height: 40px; +} +.tsd-page-toolbar .table-cell:first-child { + width: 100%; +} + +.tsd-page-toolbar--hide { + transform: translateY(-100%); +} + +.tsd-widget { + display: inline-block; + overflow: hidden; + opacity: 0.8; + height: 40px; + transition: opacity 0.1s, background-color 0.2s; + vertical-align: bottom; + cursor: pointer; +} +.tsd-widget:hover { + opacity: 0.9; +} +.tsd-widget.active { + opacity: 1; + background-color: var(--color-accent); +} +.tsd-widget.no-caption { + width: 40px; +} +.tsd-widget.no-caption:before { + margin: 0; +} + +.tsd-widget.options, +.tsd-widget.menu { + display: none; +} +@media (max-width: 1024px) { + .tsd-widget.options, + .tsd-widget.menu { + display: inline-block; + } +} +input[type="checkbox"] + .tsd-widget:before { + background-position: -120px 0; +} +input[type="checkbox"]:checked + .tsd-widget:before { + background-position: -160px 0; +} + +img { + max-width: 100%; +} + +.tsd-anchor-icon { + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + vertical-align: middle; + color: var(--color-text); +} + +.tsd-anchor-icon svg { + width: 1em; + height: 1em; + visibility: hidden; +} + +.tsd-anchor-link:hover > .tsd-anchor-icon svg { + visibility: visible; +} + +.deprecated { + text-decoration: line-through; +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--color-accent) var(--color-icon-background); +} + +*::-webkit-scrollbar { + width: 0.75rem; +} + +*::-webkit-scrollbar-track { + background: var(--color-icon-background); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--color-accent); + border-radius: 999rem; + border: 0.25rem solid var(--color-icon-background); +} diff --git a/docs/references/assets/widgets.png b/docs/references/assets/widgets.png new file mode 100644 index 0000000..c738053 Binary files /dev/null and b/docs/references/assets/widgets.png differ diff --git a/docs/references/assets/widgets@2x.png b/docs/references/assets/widgets@2x.png new file mode 100644 index 0000000..4bbbd57 Binary files /dev/null and b/docs/references/assets/widgets@2x.png differ diff --git a/docs/references/functions/publishers_push.runPushPublisher.html b/docs/references/functions/publishers_push.runPushPublisher.html new file mode 100644 index 0000000..b9625a5 --- /dev/null +++ b/docs/references/functions/publishers_push.runPushPublisher.html @@ -0,0 +1,70 @@ +runPushPublisher | edge-push-server
+
+ +
+
+
+
+ +

Function runPushPublisher

+
+
    + +
  • +

    Begins listening to the 'tasks_publishing' view defined in +tasksPublishing. For every new task document received, the +publisher checks if the action is in progress. If it is, skip the +processing. If it is not, the publisher will pick up the task by +executing the push notification action.

    +

    If the action is marked as repeatable, the publisher will then mark +all ActionEffects as completed so that 'task_listening' +view can pick the task up again for processing.

    + +

    Returns

    0 if the connection is closed.

    +
    +

    Returns Promise<number>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_http_response_types.jsonResponse.html b/docs/references/functions/types_http_response_types.jsonResponse.html new file mode 100644 index 0000000..d2772ca --- /dev/null +++ b/docs/references/functions/types_http_response_types.jsonResponse.html @@ -0,0 +1,75 @@ +jsonResponse | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Construct an HttpResponse object with a JSON body.

    +
    +
    +

    Parameters

    +
      +
    • +
      body: unknown
    • +
    • +
      opts: { headers?: HttpHeaders; status?: number } = {}
      +
        +
      • +
        Optional headers?: HttpHeaders
      • +
      • +
        Optional status?: number
    +

    Returns HttpResponse

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_http_response_types.statusResponse.html b/docs/references/functions/types_http_response_types.statusResponse.html new file mode 100644 index 0000000..0f727cd --- /dev/null +++ b/docs/references/functions/types_http_response_types.statusResponse.html @@ -0,0 +1,70 @@ +statusResponse | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    A generic success or failure response.

    +
    +
    +

    Parameters

    +
      +
    • +
      statusCode: StatusCode = statusCodes.SUCCESS
    • +
    • +
      message: string = statusCode.message
    +

    Returns HttpResponse

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_Action.asAction.html b/docs/references/functions/types_task_Action.asAction.html new file mode 100644 index 0000000..ce3b57d --- /dev/null +++ b/docs/references/functions/types_task_Action.asAction.html @@ -0,0 +1,67 @@ +asAction | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns Action

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionData.asActionData.html b/docs/references/functions/types_task_ActionData.asActionData.html new file mode 100644 index 0000000..8eaf961 --- /dev/null +++ b/docs/references/functions/types_task_ActionData.asActionData.html @@ -0,0 +1,75 @@ +asActionData | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns ActionData

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionData.asBroadcastTxActionData.html b/docs/references/functions/types_task_ActionData.asBroadcastTxActionData.html new file mode 100644 index 0000000..fb80816 --- /dev/null +++ b/docs/references/functions/types_task_ActionData.asBroadcastTxActionData.html @@ -0,0 +1,75 @@ +asBroadcastTxActionData | edge-push-server
+
+ +
+
+
+
+ +

Function asBroadcastTxActionData

+
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns BroadcastTxActionData

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionData.asClientActionData.html b/docs/references/functions/types_task_ActionData.asClientActionData.html new file mode 100644 index 0000000..ed3cdce --- /dev/null +++ b/docs/references/functions/types_task_ActionData.asClientActionData.html @@ -0,0 +1,75 @@ +asClientActionData | edge-push-server
+
+ +
+
+
+
+ +

Function asClientActionData

+
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns ClientActionData

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionData.asGeneralActionData.html b/docs/references/functions/types_task_ActionData.asGeneralActionData.html new file mode 100644 index 0000000..9e1c537 --- /dev/null +++ b/docs/references/functions/types_task_ActionData.asGeneralActionData.html @@ -0,0 +1,75 @@ +asGeneralActionData | edge-push-server
+
+ +
+
+
+
+ +

Function asGeneralActionData

+
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns GeneralActionData

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionData.asPushActionData.html b/docs/references/functions/types_task_ActionData.asPushActionData.html new file mode 100644 index 0000000..1c30fc1 --- /dev/null +++ b/docs/references/functions/types_task_ActionData.asPushActionData.html @@ -0,0 +1,75 @@ +asPushActionData | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns PushActionData

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionEffect.asActionEffect.html b/docs/references/functions/types_task_ActionEffect.asActionEffect.html new file mode 100644 index 0000000..95dcc1d --- /dev/null +++ b/docs/references/functions/types_task_ActionEffect.asActionEffect.html @@ -0,0 +1,78 @@ +asActionEffect | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns ActionEffect

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionEffect.asBalanceActionEffect.html b/docs/references/functions/types_task_ActionEffect.asBalanceActionEffect.html new file mode 100644 index 0000000..9c5af69 --- /dev/null +++ b/docs/references/functions/types_task_ActionEffect.asBalanceActionEffect.html @@ -0,0 +1,78 @@ +asBalanceActionEffect | edge-push-server
+
+ +
+
+
+
+ +

Function asBalanceActionEffect

+
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns BalanceActionEffect

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionEffect.asParActionEffect.html b/docs/references/functions/types_task_ActionEffect.asParActionEffect.html new file mode 100644 index 0000000..04cc768 --- /dev/null +++ b/docs/references/functions/types_task_ActionEffect.asParActionEffect.html @@ -0,0 +1,78 @@ +asParActionEffect | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns ParActionEffect

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionEffect.asPriceActionEffect.html b/docs/references/functions/types_task_ActionEffect.asPriceActionEffect.html new file mode 100644 index 0000000..59e04f1 --- /dev/null +++ b/docs/references/functions/types_task_ActionEffect.asPriceActionEffect.html @@ -0,0 +1,78 @@ +asPriceActionEffect | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns PriceActionEffect

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionEffect.asSeqActionEffect.html b/docs/references/functions/types_task_ActionEffect.asSeqActionEffect.html new file mode 100644 index 0000000..c9fd6c2 --- /dev/null +++ b/docs/references/functions/types_task_ActionEffect.asSeqActionEffect.html @@ -0,0 +1,78 @@ +asSeqActionEffect | edge-push-server
+
+ +
+
+
+ +
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns SeqActionEffect

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_ActionEffect.asTxConfsActionEffect.html b/docs/references/functions/types_task_ActionEffect.asTxConfsActionEffect.html new file mode 100644 index 0000000..142e7df --- /dev/null +++ b/docs/references/functions/types_task_ActionEffect.asTxConfsActionEffect.html @@ -0,0 +1,78 @@ +asTxConfsActionEffect | edge-push-server
+
+ +
+
+
+
+ +

Function asTxConfsActionEffect

+
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns TxConfsActionEffect

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/types_task_Task.asTask.html b/docs/references/functions/types_task_Task.asTask.html new file mode 100644 index 0000000..d487459 --- /dev/null +++ b/docs/references/functions/types_task_Task.asTask.html @@ -0,0 +1,67 @@ +asTask | edge-push-server
+
+ +
+
+
+
+ +

Function asTask

+
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns Task

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_HTTPHelpers.convertStringToArray.html b/docs/references/functions/utils_HTTPHelpers.convertStringToArray.html new file mode 100644 index 0000000..f426ccf --- /dev/null +++ b/docs/references/functions/utils_HTTPHelpers.convertStringToArray.html @@ -0,0 +1,71 @@ +convertStringToArray | edge-push-server
+
+ +
+
+
+
+ +

Function convertStringToArray

+
+
    + +
  • +

    Converts a string to an array of strings.

    + +

    Returns

    An array of strings.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: string
      +

      The string to be converted to an array.

      +
    +

    Returns undefined | string[]

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_HTTPHelpers.getQueryParamObject.html b/docs/references/functions/utils_HTTPHelpers.getQueryParamObject.html new file mode 100644 index 0000000..565bc5e --- /dev/null +++ b/docs/references/functions/utils_HTTPHelpers.getQueryParamObject.html @@ -0,0 +1,83 @@ +getQueryParamObject | edge-push-server
+
+ +
+
+
+
+ +

Function getQueryParamObject

+
+
    + +
  • +

    Given a URL path and an array of query parameter names, returns an +object with keys for each query parameter name and values for each +query

    +

    For example, given the following URL path: v1/device?deviceId=12345 +and the query parameter name deviceId, the function will return the +string 12345.

    + +

    Returns

    The object of query parameters.

    +
    +
    +

    Parameters

    +
      +
    • +
      query: string[]
      +

      An array of query parameter names.

      +
    • +
    • +
      path: string
      +

      The URL path.

      +
    +

    Returns { [index: string]: any }

    +
      +
    • +
      [index: string]: any
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.asTaskDoc.html b/docs/references/functions/utils_dbUtils.asTaskDoc.html new file mode 100644 index 0000000..4343865 --- /dev/null +++ b/docs/references/functions/utils_dbUtils.asTaskDoc.html @@ -0,0 +1,76 @@ +asTaskDoc | edge-push-server
+
+ +
+
+
+
+ +

Function asTaskDoc

+
+
    + +
  • +

    Reads & checks an untrusted value. Throws an exception if it's wrong.

    +
    +
    +

    Parameters

    +
      +
    • +
      raw: any
    +

    Returns CouchDoc<Task>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.deleteFromDb.html b/docs/references/functions/utils_dbUtils.deleteFromDb.html new file mode 100644 index 0000000..94f6869 --- /dev/null +++ b/docs/references/functions/utils_dbUtils.deleteFromDb.html @@ -0,0 +1,83 @@ +deleteFromDb | edge-push-server
+
+ +
+
+
+
+ +

Function deleteFromDb

+
+
    + +
  • +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      db: DocumentScope<CouchDoc<T>>
    • +
    • +
      keys: string[]
    • +
    • +
      userId: string
    +

    Returns Promise<void>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.getFromDb.html b/docs/references/functions/utils_dbUtils.getFromDb.html new file mode 100644 index 0000000..fca228e --- /dev/null +++ b/docs/references/functions/utils_dbUtils.getFromDb.html @@ -0,0 +1,85 @@ +getFromDb | edge-push-server
+
+ +
+
+
+
+ +

Function getFromDb

+
+
    + +
  • +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      db: DocumentScope<CouchDoc<T>>
    • +
    • +
      keys: string[]
    • +
    • +
      userId: string
    • +
    • +
      cleaner: Cleaner<CouchDoc<T>>
    +

    Returns Promise<CouchDoc<T>[]>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.logger.html b/docs/references/functions/utils_dbUtils.logger.html new file mode 100644 index 0000000..ff37430 --- /dev/null +++ b/docs/references/functions/utils_dbUtils.logger.html @@ -0,0 +1,74 @@ +logger | edge-push-server
+
+ +
+
+
+
+ +

Function logger

+
+
    + +
  • +
    +

    Parameters

    +
      +
    • +
      Rest ...args: any
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.packChange.html b/docs/references/functions/utils_dbUtils.packChange.html new file mode 100644 index 0000000..00bffa7 --- /dev/null +++ b/docs/references/functions/utils_dbUtils.packChange.html @@ -0,0 +1,90 @@ +packChange | edge-push-server
+
+ +
+
+
+
+ +

Function packChange

+
+
    + +
  • +

    Convert a Task object into a TaskDoc object that +implements CouchDoc.

    + +

    Returns

    +
    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      doc: T
      +

      A Task object.

      +
    • +
    • +
      id: string
    +

    Returns CouchDoc<T>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.saveToDb.html b/docs/references/functions/utils_dbUtils.saveToDb.html new file mode 100644 index 0000000..9539d25 --- /dev/null +++ b/docs/references/functions/utils_dbUtils.saveToDb.html @@ -0,0 +1,81 @@ +saveToDb | edge-push-server
+
+ +
+
+
+
+ +

Function saveToDb

+
+
    + +
  • +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      db: DocumentScope<CouchDoc<T>>
    • +
    • +
      docs: CouchDoc<T>[]
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.wrappedDeleteFromDb.html b/docs/references/functions/utils_dbUtils.wrappedDeleteFromDb.html new file mode 100644 index 0000000..c86cbce --- /dev/null +++ b/docs/references/functions/utils_dbUtils.wrappedDeleteFromDb.html @@ -0,0 +1,76 @@ +wrappedDeleteFromDb | edge-push-server
+
+ +
+
+
+
+ +

Function wrappedDeleteFromDb

+
+
    + +
  • +
    +

    Parameters

    +
      +
    • +
      keys: string[]
    • +
    • +
      userId: string
    +

    Returns Promise<void>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.wrappedGetFromDb.html b/docs/references/functions/utils_dbUtils.wrappedGetFromDb.html new file mode 100644 index 0000000..496ae4e --- /dev/null +++ b/docs/references/functions/utils_dbUtils.wrappedGetFromDb.html @@ -0,0 +1,76 @@ +wrappedGetFromDb | edge-push-server
+
+ +
+
+
+
+ +

Function wrappedGetFromDb

+
+
    + +
  • +
    +

    Parameters

    +
      +
    • +
      keys: string[]
    • +
    • +
      userId: string
    +

    Returns Promise<TaskDoc[]>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/functions/utils_dbUtils.wrappedSaveToDb.html b/docs/references/functions/utils_dbUtils.wrappedSaveToDb.html new file mode 100644 index 0000000..426d1ef --- /dev/null +++ b/docs/references/functions/utils_dbUtils.wrappedSaveToDb.html @@ -0,0 +1,74 @@ +wrappedSaveToDb | edge-push-server
+
+ +
+
+
+
+ +

Function wrappedSaveToDb

+
+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/index.html b/docs/references/index.html new file mode 100644 index 0000000..f8dce95 --- /dev/null +++ b/docs/references/index.html @@ -0,0 +1,78 @@ +edge-push-server
+
+ +
+
+
+
+

edge-push-server

+
+ +

edge-push-server

+
+

This server sends push notifications to Edge client apps. It contains an HTTP server that clients can use to register for notifications, and a background process that checks for price changes and actually sends the messages.

+ + +

Setup

+
+

This server requires a working copies of Node.js, Yarn, PM2, and CouchDB. We also recommend using Caddy to terminate SSL connections.

+ + +

Set up logging

+
+

Run these commands as a server admin:

+
touch /var/log/pushServer.log
touch /var/log/priceDaemon.log
chown edgy /var/log/pushServer.log /var/log/priceDaemon.log
cp ./docs/logrotate /etc/logrotate.d/pushServer +
+ + +

Manage server using pm2

+
+

First, tell pm2 how to run the server script:

+
# install:
pm2 start pm2.json
pm2 save

# check status:
pm2 monit
tail -f /var/log/pushServer.log
tail -f /var/log/priceDaemon.log

# manage:
pm2 reload pm2.json
pm2 restart pm2.json
pm2 stop pm2.json

pm2 restart pushServer // Just the HTTP server
pm2 restart priceDaemon // Just the price checker +
+ + +

Updating

+
+

To update the code running on the production server, use the following procedure:

+
git pull
yarn
yarn prepare
pm2 restart pm2.json +
+

Each deployment should come with its own version bump, changelog update, and git tag.

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_http_request_types.ApiRequest.html b/docs/references/interfaces/types_http_request_types.ApiRequest.html new file mode 100644 index 0000000..5838f42 --- /dev/null +++ b/docs/references/interfaces/types_http_request_types.ApiRequest.html @@ -0,0 +1,133 @@ +ApiRequest | edge-push-server
+
+ +
+
+
+ +
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
apiKey: ApiKey
+
+ +
body: any
+
+ +
headers: HttpHeaders
+
+ +
method: string
+
+ +
path: string
+
+ +
payload: unknown
+
+ +
req: Request<ParamsDictionary, any, any, ParsedQs>
+
+ +
version: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_http_request_types.ExtendedRequest.html b/docs/references/interfaces/types_http_request_types.ExtendedRequest.html new file mode 100644 index 0000000..bc0914f --- /dev/null +++ b/docs/references/interfaces/types_http_request_types.ExtendedRequest.html @@ -0,0 +1,120 @@ +ExtendedRequest | edge-push-server
+
+ +
+
+
+ +
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
body: any
+
+ +
headers: HttpHeaders
+
+ +
method: string
+
+ +
path: string
+
+ +
req: Request<ParamsDictionary, any, any, ParsedQs>
+
+ +
version: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_Action.Action.html b/docs/references/interfaces/types_task_Action.Action.html new file mode 100644 index 0000000..c65b020 --- /dev/null +++ b/docs/references/interfaces/types_task_Action.Action.html @@ -0,0 +1,125 @@ +Action | edge-push-server
+
+ +
+
+
+
+ +

Interface Action

+
+

Describes types of action to be done by some service. Some properties +are optional because certain types of actions do not require the +optional properties.

+
+
+

Hierarchy

+
    +
  • Action
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ + +

Additional payload for consumption. For 'push' action type, data +must contain apiKey, body, message, and tokenIds to send +notifications.

+ +

See

    +
  • ApiKey
  • +
  • NotificationManager.init
  • +
  • NotificationManager.send
  • +
+
+
+ +
inProgress?: boolean
+

Mutex implementation to prevent race conditions.

+
+
+ +
repeat?: boolean
+

If true, the task will be reused, otherwise, the task will be +deleted after the action is completed.

+
+
+ +
type: "push" | "broadcast-tx" | "client"
+

The type of the action.

+
    +
  • 'push': An action for pushing a notification to a device.
  • +
  • 'broadcast-tx': An action for broadcasting transactions to a +network provider such as Blockbook.
  • +
  • 'client': // TODO: Add description
  • +
+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionData.BroadcastTxActionData.html b/docs/references/interfaces/types_task_ActionData.BroadcastTxActionData.html new file mode 100644 index 0000000..745b963 --- /dev/null +++ b/docs/references/interfaces/types_task_ActionData.BroadcastTxActionData.html @@ -0,0 +1,86 @@ +BroadcastTxActionData | edge-push-server
+
+ +
+
+
+
+ +

Interface BroadcastTxActionData

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
SOMETHING: string
+
+ +
additionalData?: Object
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionData.ClientActionData.html b/docs/references/interfaces/types_task_ActionData.ClientActionData.html new file mode 100644 index 0000000..c52e13f --- /dev/null +++ b/docs/references/interfaces/types_task_ActionData.ClientActionData.html @@ -0,0 +1,86 @@ +ClientActionData | edge-push-server
+
+ +
+
+
+
+ +

Interface ClientActionData

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
SOMETHING: string
+
+ +
additionalData?: Object
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionData.GeneralActionData.html b/docs/references/interfaces/types_task_ActionData.GeneralActionData.html new file mode 100644 index 0000000..a51872a --- /dev/null +++ b/docs/references/interfaces/types_task_ActionData.GeneralActionData.html @@ -0,0 +1,80 @@ +GeneralActionData | edge-push-server
+
+ +
+
+
+
+ +

Interface GeneralActionData

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
additionalData?: Object
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionData.PushActionData.html b/docs/references/interfaces/types_task_ActionData.PushActionData.html new file mode 100644 index 0000000..409c943 --- /dev/null +++ b/docs/references/interfaces/types_task_ActionData.PushActionData.html @@ -0,0 +1,107 @@ +PushActionData | edge-push-server
+
+ +
+
+
+
+ +

Interface PushActionData

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
additionalData?: Object
+
+ +
apiKey: string | ApiKey
+
+ +
body: string
+
+ +
title: string
+
+ +
tokenIds: string[]
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionEffect.BalanceActionEffect.html b/docs/references/interfaces/types_task_ActionEffect.BalanceActionEffect.html new file mode 100644 index 0000000..835ea4a --- /dev/null +++ b/docs/references/interfaces/types_task_ActionEffect.BalanceActionEffect.html @@ -0,0 +1,121 @@ +BalanceActionEffect | edge-push-server
+
+ +
+
+
+
+ +

Interface BalanceActionEffect

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+ +
aboveAmount?: string
+
+ +
address: string
+
+ +
belowAmount?: string
+
+ +
completed: boolean
+
+ +
tokenId?: string
+
+ +
type: "balance"
+
+ +
walletId: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionEffect.GeneralActionEffect.html b/docs/references/interfaces/types_task_ActionEffect.GeneralActionEffect.html new file mode 100644 index 0000000..1e609df --- /dev/null +++ b/docs/references/interfaces/types_task_ActionEffect.GeneralActionEffect.html @@ -0,0 +1,82 @@ +GeneralActionEffect | edge-push-server
+
+ +
+
+
+
+ +

Interface GeneralActionEffect

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
completed: boolean
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionEffect.ParActionEffect.html b/docs/references/interfaces/types_task_ActionEffect.ParActionEffect.html new file mode 100644 index 0000000..4deac6f --- /dev/null +++ b/docs/references/interfaces/types_task_ActionEffect.ParActionEffect.html @@ -0,0 +1,93 @@ +ParActionEffect | edge-push-server
+
+ +
+
+
+ +
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
childEffects: ActionEffect[]
+
+ +
completed: boolean
+
+ +
type: "par"
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionEffect.PriceActionEffect.html b/docs/references/interfaces/types_task_ActionEffect.PriceActionEffect.html new file mode 100644 index 0000000..b603ea1 --- /dev/null +++ b/docs/references/interfaces/types_task_ActionEffect.PriceActionEffect.html @@ -0,0 +1,107 @@ +PriceActionEffect | edge-push-server
+
+ +
+
+
+ +
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+ +
aboveRate?: string
+
+ +
belowRate?: string
+
+ +
completed: boolean
+
+ +
currencyPair: string
+
+ +
type: "price"
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionEffect.SeqActionEffect.html b/docs/references/interfaces/types_task_ActionEffect.SeqActionEffect.html new file mode 100644 index 0000000..bde4857 --- /dev/null +++ b/docs/references/interfaces/types_task_ActionEffect.SeqActionEffect.html @@ -0,0 +1,100 @@ +SeqActionEffect | edge-push-server
+
+ +
+
+
+ +
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
childEffect: ActionEffect
+
+ +
completed: boolean
+
+ +
opIndex: number
+
+ +
type: "seq"
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_ActionEffect.TxConfsActionEffect.html b/docs/references/interfaces/types_task_ActionEffect.TxConfsActionEffect.html new file mode 100644 index 0000000..719f59c --- /dev/null +++ b/docs/references/interfaces/types_task_ActionEffect.TxConfsActionEffect.html @@ -0,0 +1,107 @@ +TxConfsActionEffect | edge-push-server
+
+ +
+
+
+
+ +

Interface TxConfsActionEffect

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
completed: boolean
+
+ +
confirmations: number
+
+ +
txId: string
+
+ +
type: "tx-confs"
+
+ +
walletId: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/interfaces/types_task_Task.Task.html b/docs/references/interfaces/types_task_Task.Task.html new file mode 100644 index 0000000..dfb7cd0 --- /dev/null +++ b/docs/references/interfaces/types_task_Task.Task.html @@ -0,0 +1,103 @@ +Task | edge-push-server
+
+ +
+
+
+
+ +

Interface Task

+
+

Describes a task that can be stored in the db_tasks database.

+

taskId and userId are required to construct the _id of the +couchDB document. The _id is used to partition the documents by +user for performance and security reasons.

+
+
+

Hierarchy

+
    +
  • Task
+
+
+
+ +
+
+

Properties

+
+
+

Properties

+
+ +
action: Action
+
+ +
actionEffects: ActionEffect[]
+
+ +
taskId: string
+
+ +
userId: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules.html b/docs/references/modules.html new file mode 100644 index 0000000..290b0c7 --- /dev/null +++ b/docs/references/modules.html @@ -0,0 +1,60 @@ +edge-push-server
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/publishers_push.html b/docs/references/modules/publishers_push.html new file mode 100644 index 0000000..8144805 --- /dev/null +++ b/docs/references/modules/publishers_push.html @@ -0,0 +1,62 @@ +publishers/push | edge-push-server
+
+ +
+
+
+
+ +

Module publishers/push

+
+
+
+
+

Index

+
+

Functions

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/types_http_request_types.html b/docs/references/modules/types_http_request_types.html new file mode 100644 index 0000000..0e052cb --- /dev/null +++ b/docs/references/modules/types_http_request_types.html @@ -0,0 +1,64 @@ +types/http/request-types | edge-push-server
+
+ +
+
+
+
+ +

Module types/http/request-types

+
+
+
+
+

Index

+
+

Interfaces

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/types_http_response_types.html b/docs/references/modules/types_http_response_types.html new file mode 100644 index 0000000..929693b --- /dev/null +++ b/docs/references/modules/types_http_response_types.html @@ -0,0 +1,69 @@ +types/http/response-types | edge-push-server
+
+ +
+
+
+
+ +

Module types/http/response-types

+
+
+
+
+

Index

+
+

Variables

+
+
+

Functions

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/types_task_Action.html b/docs/references/modules/types_task_Action.html new file mode 100644 index 0000000..75a9793 --- /dev/null +++ b/docs/references/modules/types_task_Action.html @@ -0,0 +1,67 @@ +types/task/Action | edge-push-server
+
+ +
+
+
+
+ +

Module types/task/Action

+
+
+
+
+

Index

+
+

Interfaces

+
+
+

Functions

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/types_task_ActionData.html b/docs/references/modules/types_task_ActionData.html new file mode 100644 index 0000000..0a46861 --- /dev/null +++ b/docs/references/modules/types_task_ActionData.html @@ -0,0 +1,86 @@ +types/task/ActionData | edge-push-server
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/types_task_ActionEffect.html b/docs/references/modules/types_task_ActionEffect.html new file mode 100644 index 0000000..924b828 --- /dev/null +++ b/docs/references/modules/types_task_ActionEffect.html @@ -0,0 +1,92 @@ +types/task/ActionEffect | edge-push-server
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/types_task_Task.html b/docs/references/modules/types_task_Task.html new file mode 100644 index 0000000..08a94a6 --- /dev/null +++ b/docs/references/modules/types_task_Task.html @@ -0,0 +1,67 @@ +types/task/Task | edge-push-server
+
+ +
+
+
+
+ +

Module types/task/Task

+
+
+
+
+

Index

+
+

Interfaces

+
+
+

Functions

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/utils_HTTPHelpers.html b/docs/references/modules/utils_HTTPHelpers.html new file mode 100644 index 0000000..0b2f14c --- /dev/null +++ b/docs/references/modules/utils_HTTPHelpers.html @@ -0,0 +1,64 @@ +utils/HTTPHelpers | edge-push-server
+
+ +
+
+
+
+ +

Module utils/HTTPHelpers

+
+
+
+
+

Index

+
+

Functions

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/modules/utils_dbUtils.html b/docs/references/modules/utils_dbUtils.html new file mode 100644 index 0000000..a5aa9f6 --- /dev/null +++ b/docs/references/modules/utils_dbUtils.html @@ -0,0 +1,88 @@ +utils/dbUtils | edge-push-server
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/types/types_task_ActionData.ActionData.html b/docs/references/types/types_task_ActionData.ActionData.html new file mode 100644 index 0000000..d345e82 --- /dev/null +++ b/docs/references/types/types_task_ActionData.ActionData.html @@ -0,0 +1,64 @@ +ActionData | edge-push-server
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/types/types_task_ActionEffect.ActionEffect.html b/docs/references/types/types_task_ActionEffect.ActionEffect.html new file mode 100644 index 0000000..37087f9 --- /dev/null +++ b/docs/references/types/types_task_ActionEffect.ActionEffect.html @@ -0,0 +1,67 @@ +ActionEffect | edge-push-server
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/types/utils_dbUtils.TaskDoc.html b/docs/references/types/utils_dbUtils.TaskDoc.html new file mode 100644 index 0000000..2cfc091 --- /dev/null +++ b/docs/references/types/utils_dbUtils.TaskDoc.html @@ -0,0 +1,65 @@ +TaskDoc | edge-push-server
+
+ +
+ +
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/variables/types_http_response_types.statusCodes.html b/docs/references/variables/types_http_response_types.statusCodes.html new file mode 100644 index 0000000..e11cd89 --- /dev/null +++ b/docs/references/variables/types_http_response_types.statusCodes.html @@ -0,0 +1,81 @@ +statusCodes | edge-push-server
+
+ +
+
+
+
+ +

Variable statusCodesConst

+
statusCodes: { INTERNAL_SERVER_ERROR: { httpStatus: number; message: string }; PAGE_NOT_FOUND: { httpStatus: number; message: string }; SUCCESS: { httpStatus: number; message: string } } = ...
+
+

Type declaration

+
    +
  • +
    INTERNAL_SERVER_ERROR: { httpStatus: number; message: string }
    +
      +
    • +
      httpStatus: number
    • +
    • +
      message: string
  • +
  • +
    PAGE_NOT_FOUND: { httpStatus: number; message: string }
    +
      +
    • +
      httpStatus: number
    • +
    • +
      message: string
  • +
  • +
    SUCCESS: { httpStatus: number; message: string }
    +
      +
    • +
      httpStatus: number
    • +
    • +
      message: string
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/references/variables/utils_dbUtils.dbTasks.html b/docs/references/variables/utils_dbUtils.dbTasks.html new file mode 100644 index 0000000..ae0b989 --- /dev/null +++ b/docs/references/variables/utils_dbUtils.dbTasks.html @@ -0,0 +1,65 @@ +dbTasks | edge-push-server
+
+ +
+
+
+
+ +

Variable dbTasksConst

+
dbTasks: nano.DocumentScope<TaskDoc> = ...
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/package.json b/package.json index 7059d34..fb5f56f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "main": "build/index.js", "scripts": { "build": "sucrase -q -t typescript,imports -d ./lib ./src", - "clean": "rimraf lib", + "clean": "rimraf lib", "compile": "tsc", "fix": "npm run lint -- --fix", "lint": "eslint --ext .js,.ts .", @@ -30,13 +30,14 @@ "cleaners": "^0.3.12", "compression": "^1.7.4", "cors": "^2.8.5", - "edge-server-tools": "^0.2.11", + "edge-server-tools": "^0.2.13", "express": "^4.17.1", "firebase-admin": "^8.12.1", "morgan": "^1.10.0", "nano": "10.0.0", "node-schedule": "^1.3.2", - "serverlet": "^0.1.1" + "serverlet": "^0.1.1", + "typedoc": "^0.23.8" }, "devDependencies": { "@types/cors": "^2.8.7", diff --git a/src/NotificationManager.ts b/src/NotificationManager.ts new file mode 100644 index 0000000..39e8c88 --- /dev/null +++ b/src/NotificationManager.ts @@ -0,0 +1,64 @@ +import io from '@pm2/io' +import admin from 'firebase-admin' + +import { ApiKey } from './models' + +import BatchResponse = admin.messaging.BatchResponse + +const successCounter = io.counter({ + id: 'notifications:success:total', + name: 'Total Successful Notifications' +}) +const failureCounter = io.counter({ + id: 'notifications:failure:total', + name: 'Total Failed Notifications' +}) + +export const createNotificationManager = async ( + apiKey: ApiKey | string +): Promise => { + if (typeof apiKey === 'string') apiKey = await ApiKey.fetch(apiKey) + + const name = `app:${apiKey.appId}` + let app: admin.app.App + try { + app = admin.app(name) + } catch (err) { + app = admin.initializeApp( + { + credential: admin.credential.cert(apiKey.adminsdk) + }, + name + ) + } + return app +} + +export const sendNotification = async ( + app: admin.app.App, + title: string, + body: string, + tokens: string[], + data = {} +): Promise => { + const message: admin.messaging.MulticastMessage = { + notification: { + title, + body + }, + data, + tokens + } + + try { + const response = await app.messaging().sendMulticast(message) + + successCounter.inc(response.successCount) + failureCounter.inc(response.failureCount) + + return response + } catch (err) { + console.error(JSON.stringify(err, null, 2)) + throw err + } +} diff --git a/src/api/index.ts b/src/api/index.ts deleted file mode 100644 index 6fb9cfc..0000000 --- a/src/api/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { makeExpressRoute } from 'serverlet/express' - -import { config } from '../config' -import { pushNotificationRouterV2 } from './router' -import { createServer } from './server' -// Create server -const server = createServer(makeExpressRoute(pushNotificationRouterV2), config) - -// Start Server -server.listen(server.get('httpPort'), server.get('httpHost'), () => { - console.log( - `Express server listening on port ${JSON.stringify(server.get('httpPort'))}` - ) -}) diff --git a/src/api/router.ts b/src/api/router.ts index 701c311..73dac4d 100644 --- a/src/api/router.ts +++ b/src/api/router.ts @@ -1,4 +1,4 @@ -import { asArray, asObject, asString, asUnknown } from 'cleaners' +import { asArray, asObject, asString } from 'cleaners' import { type HttpRequest, type HttpResponse, @@ -10,10 +10,13 @@ import { jsonResponse, statusCodes, statusResponse -} from '../types/response-types' +} from '../types/http/response-types' +import { asAction } from '../types/task/Action' +import { asActionEffect } from '../types/task/ActionEffect' import { - DbDoc, + asTaskDoc, logger, + TaskDoc, wrappedDeleteFromDb, wrappedGetFromDb, wrappedSaveToDb @@ -51,31 +54,34 @@ const getTaskRoute = async (request: HttpRequest): Promise => { } // Construct a body and returns it as an HttpResponse. -// The body should have triggers, action, and taskId. +// The body should have actionEffects, action, userId, _id and taskId. const createTaskRoute = async (request: HttpRequest): Promise => { try { const asBody = asObject({ taskId: asString, - triggers: asArray(asUnknown), - action: asUnknown + actionEffects: asArray(asActionEffect), + action: asAction }) const queryObject = getQueryParamObject( - ['taskId', 'triggers', 'action'], + ['taskId', 'actionEffects', 'action'], request.path ) - const triggersAsString = queryObject.triggers - const triggersAsArray = convertStringToArray(triggersAsString) - queryObject.triggers = triggersAsArray ?? [] - const { taskId, triggers, action } = asBody(queryObject) + const actionEffectsAsString = queryObject.actionEffects + const actionEffectsAsArray = convertStringToArray(actionEffectsAsString) + queryObject.actionEffects = actionEffectsAsArray ?? [] + const { taskId, actionEffects, action } = asBody(queryObject) + const cleanedAction = asAction(action) - const doc: DbDoc = { - taskId, + const doc: TaskDoc = asTaskDoc({ + taskId: taskId, userId: request.headers.userId, - triggers, - action, + actionEffects: actionEffects.map(actionEffect => + asActionEffect(actionEffect) + ), + cleanedAction, _id: `${request.headers.userId}:${taskId}` // To help with partitioning - } + }) await wrappedSaveToDb([doc]) return statusResponse(statusCodes.SUCCESS, 'Successfully created the task') @@ -85,6 +91,8 @@ const createTaskRoute = async (request: HttpRequest): Promise => { } } +// Remove tasks from the database. If the taskIds array is empty, it +// will delete all tasks under the userId. const deleteTaskRoute = async (request: HttpRequest): Promise => { try { const asQuery = asObject({ diff --git a/src/config.ts b/src/config.ts deleted file mode 100644 index aa5a5ce..0000000 --- a/src/config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { makeConfig } from 'cleaner-config' -import { asNumber, asObject, asOptional, asString } from 'cleaners' - -const { COUCH_HOSTNAME = 'localhost', COUCH_PASSWORD = 'password' } = - process.env - -export const asServerConfig = asObject({ - couchUri: asOptional( - asString, - `http://username:${COUCH_PASSWORD}@${COUCH_HOSTNAME}:5984` - ), - // for running the local server - httpPort: asOptional(asNumber, 8008), - httpHost: asOptional(asString, '127.0.0.1') -}) - -export const config = makeConfig(asServerConfig, 'pushServerConfig.json') diff --git a/src/couchSetup.ts b/src/couchSetup.ts index 0e38581..dd3b802 100644 --- a/src/couchSetup.ts +++ b/src/couchSetup.ts @@ -8,6 +8,7 @@ import { } from 'edge-server-tools' import { ServerScope } from 'nano' +import { tasksListening, tasksPublishing } from './database/views/couch-tasks' import { serverConfig } from './serverConfig' // --------------------------------------------------------------------------- @@ -48,21 +49,18 @@ export const settingsSetup: DatabaseSetup = { const apiKeysSetup: DatabaseSetup = { name: 'db_api_keys' } -const thresholdsSetup: DatabaseSetup = { name: 'db_currency_thresholds' } - -const devicesSetup: DatabaseSetup = { name: 'db_devices' } - -const usersSetup: DatabaseSetup = { - name: 'db_user_settings' - // documents: { - // '_design/filter': makeJsDesign('by-currency', ?), - // '_design/map': makeJsDesign('currency-codes', ?) - // } -} - -const defaultsSetup: DatabaseSetup = { - name: 'defaults' - // syncedDocuments: ['thresholds'] +const tasksSetup: DatabaseSetup = { + name: 'db_tasks', + // Turn on partition by userId for performance and security reasons. + // https://docs.couchdb.org/en/3.2.2/partitioned-dbs/index.html + options: { + partitioned: true + }, + // Set up the views + documents: { + '_design/tasks_listening': tasksListening, + '_design/tasks_publishing': tasksPublishing + } } // --------------------------------------------------------------------------- @@ -79,13 +77,12 @@ export async function setupDatabases( replicatorSetup: syncedReplicators, disableWatching } - + // @ts-expect-error await setupDatabase(connection, settingsSetup, options) await Promise.all([ + // @ts-expect-error setupDatabase(connection, apiKeysSetup, options), - setupDatabase(connection, thresholdsSetup, options), - setupDatabase(connection, devicesSetup, options), - setupDatabase(connection, usersSetup, options), - setupDatabase(connection, defaultsSetup, options) + // @ts-expect-error + setupDatabase(connection, tasksSetup, options) ]) } diff --git a/src/database/views/couch-tasks.ts b/src/database/views/couch-tasks.ts new file mode 100644 index 0000000..9cbc62c --- /dev/null +++ b/src/database/views/couch-tasks.ts @@ -0,0 +1,81 @@ +/** + * Configures couchDB views that are used to model message queues. + * Associated helper functions are also provided. + * + * Publishers listen to these views to perform actions on update. One + * way of doing this is to use the {@link viewToStream} function from + * `edge-server-tools`. + * + * A key advantage of using views is that documents are programmatically + * indexed and serverd to views based on certain conditions, thereby + * elimitating the need to build seqarate listeners that subscribe to db + * documents and perform actions on update. + * + * Views can be named as a string, just like a normal database. They can + * be called by using `db.view(name, params)` method. The response will + * be of type `nano.DocumentViewResponse` where `T` is the shape of the + * documents defined elsewhere. This type has a `rows` property that is + * consistent with many other getter methods in nano. + */ + +// Certain import lines have lintings disabled because they are +// referenced only by documentation comments. +import { + JsDesignDocument, + makeJsDesign, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + viewToStream +} from 'edge-server-tools' + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { ActionEffect } from '../../types/task/ActionEffect' +import { Task } from '../../types/task/Task' +import { dbTasks, logger, packChange, TaskDoc } from '../../utils/dbUtils' + +/** + * A view that indexes to all tasks that contain at least one incomplete + * {@link ActionEffect}. + * + * @remarks + * This view is not intended to be subscribed by any publishers. Think + * of this as a staging area for ongoing tasks. + */ +export const tasksListening: JsDesignDocument = makeJsDesign( + 'tasks_listening', + () => ({ + filter: function (taskDoc: TaskDoc) { + return taskDoc.doc.actionEffects.some(e => e.completed === false) + } + }) +) + +/** + * A view that indexes to all tasks with all {@link ActionEffect} + * completed. + */ +export const tasksPublishing: JsDesignDocument = makeJsDesign( + 'tasks_publishing', + () => ({ + filter: function (taskDoc: TaskDoc) { + return taskDoc.doc.actionEffects.every(Boolean) + } + }) +) + +/** + * Updates the a task document in the `db_tasks` database. The function + * receives a {@link Task} object and updates the relavent document based on + * the content of this task. + * @param {Task} updatedTask - The task that has its `action.inProgress` + * flag updated. + */ +export const updateInProgress = async ( + updatedTask: Task, + id: string +): Promise => { + try { + await dbTasks.insert(packChange(updatedTask, id)) + } catch (e) { + logger(`Failed to make ${updatedTask.taskId}'s action as inprogress: `, e) + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..fdfbf5f --- /dev/null +++ b/src/index.ts @@ -0,0 +1,33 @@ +import nano from 'nano' +import { makeExpressRoute } from 'serverlet/express' + +import { pushNotificationRouterV2 } from './api/router' +import { setupDatabases } from './couchSetup' +import { createServer } from './server' +import { serverConfig } from './serverConfig' + +async function main(): Promise { + // Set up databases: + const connection = nano(serverConfig.couchUri) + await setupDatabases(connection) + + // Create server + const server = createServer( + makeExpressRoute(pushNotificationRouterV2), + serverConfig + ) + + // Start Server + server.listen(server.get('httpPort'), server.get('httpHost'), () => { + console.log( + `Express server listening on port ${JSON.stringify( + server.get('httpPort') + )}` + ) + }) +} + +main().catch(error => { + console.error(error) + process.exit(1) +}) diff --git a/src/models/CurrencyThreshold.ts b/src/models/CurrencyThreshold.ts index 3a3300d..16340e5 100644 --- a/src/models/CurrencyThreshold.ts +++ b/src/models/CurrencyThreshold.ts @@ -60,12 +60,14 @@ export class CurrencyThreshold extends Base implements ICurrencyThreshold { price: number ): Promise { const threshold = this.thresholds[hours] ?? { + custom: undefined, lastUpdated: 0, price: 0 } threshold.lastUpdated = timestamp threshold.price = price this.thresholds[hours] = threshold + return (await this.save()) as CurrencyThreshold } } diff --git a/src/models/User.ts b/src/models/User.ts index 6b9c387..363ebc7 100644 --- a/src/models/User.ts +++ b/src/models/User.ts @@ -40,14 +40,12 @@ export class User extends Base implements ReturnType { public devices: ReturnType public notifications: ReturnType - // @ts-expect-error constructor(...args) { super(...args) - // @ts-expect-error - if (!this.devices) this.devices = {} + if (this.devices == null) this.devices = {} // @ts-expect-error - if (!this.notifications) { + if (this.notifications == null) { this.notifications = { enabled: true, currencyCodes: {} diff --git a/src/models/User/views.ts b/src/models/User/views.ts index 9a8e2ed..c663c0f 100644 --- a/src/models/User/views.ts +++ b/src/models/User/views.ts @@ -2,7 +2,6 @@ declare function emit(...args: any[]): void export const views = { filter: { - // @ts-expect-error byCurrency(doc) { var notifs = doc.notifications if (notifs && notifs.enabled && notifs.currencyCodes) { diff --git a/src/models/base.ts b/src/models/base.ts index f5ec01e..4b5aeb7 100644 --- a/src/models/base.ts +++ b/src/models/base.ts @@ -26,21 +26,19 @@ export class Base implements ReturnType { return new Proxy(this, { set(target: Base, key: PropertyKey, value: any): any { - // @ts-expect-error return key in target ? (target[key] = value) : target.set(key, value) }, get(target: Base, key: PropertyKey): any { - // @ts-expect-error return key in target ? target[key] : target.get(key) } }) } - public validate() { + public validate(): void { ;(this.constructor as typeof Base).asType(this.dataValues) } - public processAPIResponse(response: Nano.DocumentInsertResponse) { + public processAPIResponse(response: Nano.DocumentInsertResponse): void { if (response.ok === true) { this._id = response.id this._rev = response.rev @@ -106,7 +104,6 @@ export class Base implements ReturnType { } public get(key: PropertyKey): any { - // @ts-expect-error return this.dataValues[key] } @@ -115,12 +112,10 @@ export class Base implements ReturnType { for (const prop in key) { // eslint-disable-next-line no-prototype-builtins if (key.hasOwnProperty(prop)) { - // @ts-expect-error this.dataValues[prop] = key[prop] } } } else { - // @ts-expect-error this.dataValues[key] = value } diff --git a/src/publishers/push.ts b/src/publishers/push.ts new file mode 100644 index 0000000..585f8dd --- /dev/null +++ b/src/publishers/push.ts @@ -0,0 +1,169 @@ +/** + * A push publisher subscribes to a view that contains all tasks whose + * arrays of {@link ActionEffect}s are all marked as completed. The + * publisher's job is to push notifications to devices based on the + * completed tasks. + */ + +import { viewToStream } from 'edge-server-tools' + +import { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + tasksPublishing, + updateInProgress +} from '../database/views/couch-tasks' +import { + createNotificationManager, + sendNotification +} from '../NotificationManager' +import { asPushActionData } from '../types/task/ActionData' +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { ActionEffect } from '../types/task/ActionEffect' +import { Task } from '../types/task/Task' +import { + asTaskDoc, + dbTasks, + logger, + TaskDoc, + wrappedDeleteFromDb +} from '../utils/dbUtils' + +/** Used in the retry mechnism for the publisher */ +const RETRY_LIMIT = 5 + +/** + * Begins listening to the 'tasks_publishing' view defined in + * {@link tasksPublishing}. For every new task document received, the + * publisher checks if the action is in progress. If it is, skip the + * processing. If it is not, the publisher will pick up the task by + * executing the push notification action. + * + * If the action is marked as repeatable, the publisher will then mark + * all {@link ActionEffect}s as completed so that 'task_listening' + * view can pick the task up again for processing. + * + * @returns {Promise} 0 if the connection is closed. + */ +export const runPushPublisher = async (): Promise => { + for await (const doc of viewToStream(async params => + Promise.resolve( + dbTasks.view('tasks_publishing', 'tasks_publishing', params) + ) + )) { + const clean: TaskDoc = asTaskDoc(doc) + const currentTask = clean.doc + if (!canExecute(currentTask)) continue + + // Set the action of the task as in progress + // If this process fails, we stop processing the current task + await signalActionStarted(currentTask) + if (currentTask.action.inProgress === false) continue + + // Send notification to the devices + await handlePushNotification(currentTask) + + // Perform chores after the notification has been sent + await handleActionAfterPushingNotification(currentTask) + + // Set the action of the task as not in progress + await finishCurrentTaskAction(currentTask) + } + return 0 +} + +// ----------------------------------------------------------------------------- +// Helper functions +// ----------------------------------------------------------------------------- + +/** + * Determines if the current task from the view is eliglbe for pushing + * notfications to devices. + * @returns Whether the task is eligible for pushing notifications. + */ +const canExecute = (task: Task): boolean => { + return ( + task.action.inProgress != null && + task.action.type === 'push' && + task.action.repeat != null && + task.action.inProgress === false + ) +} + +/** + * By setting the action as in progress, and update that change in the + * database, other publishers will not pick up the task. + * + * If the update fails, we stop processing the current task by setting + * its inProgress flag to false. The {@link execute} function will + * skip this task. + */ +const signalActionStarted = async (task: Task): Promise => { + task.action.inProgress = true + await updateInProgress(task, `${task.userId}:${task.taskId}`).catch(_ => { + task.action.inProgress = false + }) +} + +/** + * Prepares and sends a push notification to the devices identified by tokenIds. + */ +const handlePushNotification = async (task: Task): Promise => { + const { apiKey, title, body, tokenIds } = asPushActionData(task.action.data) + const notificationManager = await createNotificationManager(apiKey) + await sendNotification( + notificationManager, + title, + body, + tokenIds, + task.action.data.additionalData ?? {} + ) +} + +/** + * Some actions are repeatable. If the action is repeatable, we mark all + * {@link ActionEffect}s as completed so that 'task_listening' view + * can pick the task up again for processing. + * + * Otherwise, we delete the task from the database. + */ +const handleActionAfterPushingNotification = async ( + task: Task +): Promise => { + if (task.action.repeat === true) { + // Reset all action effects as incomplete + task.actionEffects.forEach(actionEffect => { + actionEffect.completed = false + }) + } else { + await wrappedDeleteFromDb([task.taskId], task.userId) + } +} + +/** + * Setting the action as not in progress, and update that change in the + * database. A retry mechinism is used to minimize the chance for + * leaving a task whose inProgress flag is always true, which prevents + * it from being ever picked up by publishers. + */ +const finishCurrentTaskAction = async (task: Task): Promise => { + // If not a repeatable action, that means the task has been deleted + // from the db. Do nothing. + if (task.action.repeat === false) return + + var currentRetry = 0 + + // Use a while loop to implement a retry mechanism + while (true) { + try { + task.action.inProgress = false + await updateInProgress(task, `${task.userId}:${task.taskId}`) + break + } catch (e) { + if (currentRetry++ > RETRY_LIMIT) { + logger(`Failed to update inProgress flag after ${RETRY_LIMIT} retries`) + break + } + logger(e) + } + } +} diff --git a/src/api/server.ts b/src/server.ts similarity index 89% rename from src/api/server.ts rename to src/server.ts index 8b48ca3..e52e7fc 100644 --- a/src/api/server.ts +++ b/src/server.ts @@ -1,10 +1,10 @@ import bodyParser from 'body-parser' import compression from 'compression' import cors from 'cors' -import express, { type RequestHandler } from 'express' +import express from 'express' import morgan from 'morgan' -import { asServerConfig } from '../config' +import { asServerConfig } from './serverConfig' const BodyParseError = { message: 'error parsing body data', @@ -33,8 +33,8 @@ export const createServer = ( app.use(compressionHandler) // Create throttled slack poster // Set local app params - app.set('httpPort', config.httpPort) - app.set('httpHost', config.httpHost) + app.set('httpPort', config.listenPort) + app.set('httpHost', config.listenHost) // Morgan Logging app.use(morgan(MorganTemplate)) // configure app to use bodyParser() and return 400 error if body is not json diff --git a/src/serverConfig.ts b/src/serverConfig.ts index 23d5ebd..14aae8b 100644 --- a/src/serverConfig.ts +++ b/src/serverConfig.ts @@ -5,7 +5,7 @@ import { asNumber, asObject, asOptional, asString } from 'cleaners' * Configures the server process as a whole, * such as where to listen and how to talk to the database. */ -const asServerConfig = asObject({ +export const asServerConfig = asObject({ // HTTP server options: listenHost: asOptional(asString, '127.0.0.1'), listenPort: asOptional(asNumber, 8008), diff --git a/src/types/request-types.ts b/src/types/http/request-types.ts similarity index 86% rename from src/types/request-types.ts rename to src/types/http/request-types.ts index c44a33b..0889b88 100644 --- a/src/types/request-types.ts +++ b/src/types/http/request-types.ts @@ -1,6 +1,6 @@ import { ExpressRequest } from 'serverlet/express' -import { ApiKey } from '../models' +import { ApiKey } from '../../models' export interface ExtendedRequest extends ExpressRequest { readonly body: any diff --git a/src/types/response-types.ts b/src/types/http/response-types.ts similarity index 100% rename from src/types/response-types.ts rename to src/types/http/response-types.ts diff --git a/src/types/task/Action.ts b/src/types/task/Action.ts new file mode 100644 index 0000000..8d0241a --- /dev/null +++ b/src/types/task/Action.ts @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------- +// Type definitions +// ------------------------------------------------------------------- + +import { asBoolean, asObject, asOptional, asValue, Cleaner } from 'cleaners' + +import { ActionData, asActionData } from './ActionData' + +/** + * Describes types of action to be done by some service. Some properties + * are optional because certain types of actions do not require the + * optional properties. + */ +export interface Action { + /** + * The type of the action. + * - 'push': An action for pushing a notification to a device. + * - 'broadcast-tx': An action for broadcasting transactions to a + * network provider such as Blockbook. + * - 'client': // TODO: Add description + */ + type: 'push' | 'broadcast-tx' | 'client' + + /** + * If true, the task will be reused, otherwise, the task will be + * deleted after the action is completed. + */ + repeat?: boolean + + /** + * Mutex implementation to prevent race conditions. + */ + inProgress?: boolean + + /** + * Additional payload for consumption. For 'push' action type, data + * must contain apiKey, body, message, and tokenIds to send + * notifications. + * @see {@link ApiKey} + * @see {@link NotificationManager.init} + * @see {@link NotificationManager.send} + */ + data: ActionData +} + +// ------------------------------------------------------------------- +// Cleaners definitions +// ------------------------------------------------------------------- +export const asAction: Cleaner = asObject({ + type: asValue('push', 'broadcast-tx', 'client'), + repeat: asOptional(asBoolean), + inProgress: asOptional(asBoolean), + data: asActionData +}) diff --git a/src/types/task/ActionData.ts b/src/types/task/ActionData.ts new file mode 100644 index 0000000..ea5d4d4 --- /dev/null +++ b/src/types/task/ActionData.ts @@ -0,0 +1,69 @@ +// ------------------------------------------------------------------- +// Type definitions +// ------------------------------------------------------------------- + +import { + asArray, + asEither, + asObject, + asOptional, + asString, + Cleaner +} from 'cleaners' + +import { ApiKey } from '../../models' + +export interface GeneralActionData { + additionalData?: Object +} + +export interface PushActionData extends GeneralActionData { + apiKey: ApiKey | string + title: string + body: string + tokenIds: string[] +} + +export interface BroadcastTxActionData extends GeneralActionData { + SOMETHING: string +} + +export interface ClientActionData extends GeneralActionData { + SOMETHING: string +} + +export type ActionData = + | PushActionData + | BroadcastTxActionData + | ClientActionData + +// ------------------------------------------------------------------- +// Cleaners definitions +// ------------------------------------------------------------------- + +export const asGeneralActionData: Cleaner = asObject({ + additionalData: asOptional(asObject) +}) + +export const asPushActionData: Cleaner = asObject({ + apiKey: asString, + title: asString, + body: asString, + tokenIds: asArray(asString) +}) + +export const asBroadcastTxActionData: Cleaner = asObject( + { + SOMETHING: asString + } +) + +export const asClientActionData: Cleaner = asObject({ + SOMETHING: asString +}) + +export const asActionData: Cleaner = asEither( + asPushActionData, + asBroadcastTxActionData, + asClientActionData +) diff --git a/src/types/task/ActionEffect.ts b/src/types/task/ActionEffect.ts new file mode 100644 index 0000000..e94fc2a --- /dev/null +++ b/src/types/task/ActionEffect.ts @@ -0,0 +1,110 @@ +import { + asArray, + asBoolean, + asEither, + asNumber, + asObject, + asOptional, + asString, + asValue, + Cleaner +} from 'cleaners' + +// ------------------------------------------------------------------- +// Type definitions +// ------------------------------------------------------------------- + +export interface GeneralActionEffect { + completed: boolean +} +export interface SeqActionEffect extends GeneralActionEffect { + type: 'seq' + opIndex: number + childEffect: ActionEffect +} + +export interface ParActionEffect extends GeneralActionEffect { + type: 'par' + childEffects: ActionEffect[] +} + +export interface BalanceActionEffect extends GeneralActionEffect { + type: 'balance' + address: string + aboveAmount?: string + belowAmount?: string + walletId: string + tokenId?: string +} + +export interface TxConfsActionEffect extends GeneralActionEffect { + type: 'tx-confs' + txId: string + walletId: string + confirmations: number +} + +export interface PriceActionEffect extends GeneralActionEffect { + type: 'price' + currencyPair: string + aboveRate?: string + belowRate?: string +} +// TODO: @samholmes to add comments +export type ActionEffect = + | SeqActionEffect + | ParActionEffect + | BalanceActionEffect + | TxConfsActionEffect + | PriceActionEffect + +// ------------------------------------------------------------------- +// Cleaners definitions +// ------------------------------------------------------------------- + +export const asSeqActionEffect: Cleaner = asObject({ + type: asValue('seq'), + opIndex: asNumber, + completed: asBoolean, + childEffect: raw => asActionEffect(raw) +}) + +export const asParActionEffect: Cleaner = asObject({ + type: asValue('par'), + completed: asBoolean, + childEffects: asArray(raw => asActionEffect(raw)) +}) + +export const asBalanceActionEffect: Cleaner = asObject({ + type: asValue('balance'), + address: asString, + completed: asBoolean, + aboveAmount: asOptional(asString), + belowAmount: asOptional(asString), + walletId: asString, + tokenId: asOptional(asString) +}) + +export const asTxConfsActionEffect: Cleaner = asObject({ + type: asValue('tx-confs'), + txId: asString, + completed: asBoolean, + walletId: asString, + confirmations: asNumber +}) + +export const asPriceActionEffect: Cleaner = asObject({ + type: asValue('price'), + currencyPair: asString, + completed: asBoolean, + aboveRate: asOptional(asString), + belowRate: asOptional(asString) +}) + +export const asActionEffect: Cleaner = asEither( + asSeqActionEffect, + asParActionEffect, + asBalanceActionEffect, + asTxConfsActionEffect, + asPriceActionEffect +) diff --git a/src/types/task/Task.ts b/src/types/task/Task.ts new file mode 100644 index 0000000..7f843a5 --- /dev/null +++ b/src/types/task/Task.ts @@ -0,0 +1,33 @@ +import { asArray, asObject, asString, Cleaner } from 'cleaners' + +import { Action, asAction } from './Action' +import { ActionEffect, asActionEffect } from './ActionEffect' + +// ------------------------------------------------------------------- +// Type definitions +// ------------------------------------------------------------------- + +/** + * Describes a task that can be stored in the `db_tasks` database. + * + * `taskId` and `userId` are required to construct the `_id` of the + * couchDB document. The `_id` is used to partition the documents by + * user for performance and security reasons. + */ +export interface Task { + taskId: string + userId: string + actionEffects: ActionEffect[] + action: Action +} + +// ------------------------------------------------------------------- +// Cleaners definitions +// ------------------------------------------------------------------- + +export const asTask: Cleaner = asObject({ + taskId: asString, + userId: asString, + actionEffects: asArray(asActionEffect), + action: asAction +}) diff --git a/src/utils/dbUtils.ts b/src/utils/dbUtils.ts index f995c5e..a5235b1 100644 --- a/src/utils/dbUtils.ts +++ b/src/utils/dbUtils.ts @@ -1,55 +1,37 @@ -import { asArray, asMaybe, asObject, asString, asUnknown } from 'cleaners' +import { Cleaner } from 'cleaners' +import { asCouchDoc, CouchDoc } from 'edge-server-tools' import nano from 'nano' -import { config } from './../config' - -export interface DbDoc - extends nano.IdentifiedDocument, - nano.MaybeRevisionedDocument { - taskId: string - userId: string - triggers: any[] - action: any -} - -export const asDbDoc = (raw: any): DbDoc => { - return { - ...asObject({ - taskId: asString, - userId: asString, - triggers: asArray(asUnknown), - action: asUnknown, - _id: asString - })(raw), - ...asObject(asMaybe(asString))(raw) - } -} - -const { couchUri } = config +import { asTask, Task } from '../types/task/Task' +import { serverConfig } from './../serverConfig' +const { couchUri } = serverConfig const nanoDb = nano(couchUri) -const dbTasks: nano.DocumentScope = nanoDb.db.use('db_tasks') // ------------------------------------------------------------------------------ -// Public API +// Public APIs for the 'db_tasks' database // ------------------------------------------------------------------------------ +export type TaskDoc = CouchDoc +export const asTaskDoc: Cleaner> = asCouchDoc(asTask) +export const dbTasks: nano.DocumentScope = nanoDb.db.use('db_tasks') -export const wrappedSaveToDb = (docs: DbDoc[]): void => saveToDb(dbTasks, docs) +export const wrappedSaveToDb = (docs: TaskDoc[]): void => + saveToDb(dbTasks, docs) export const wrappedGetFromDb = async ( keys: string[], userId: string -): Promise => getFromDb(dbTasks, keys, userId) +): Promise => getFromDb(dbTasks, keys, userId, asTaskDoc) export const wrappedDeleteFromDb = async ( keys: string[], userId: string ): Promise => deleteFromDb(dbTasks, keys, userId) // ------------------------------------------------------------------------------ -// Public Helpers +// Public Helpers - Agnostic of the database // ------------------------------------------------------------------------------ -export const saveToDb = ( - db: nano.DocumentScope, - docs: DbDoc[] +export const saveToDb = ( + db: nano.DocumentScope>, + docs: Array> ): void => { if (docs.length === 0) return db.bulk({ docs }) @@ -59,16 +41,18 @@ export const saveToDb = ( .catch(logger) } -export const deleteFromDb = async ( - db: nano.DocumentScope, +export const deleteFromDb = async ( + db: nano.DocumentScope>, keys: string[], userId: string ): Promise => { - const docs = await getFromDb(db, keys, userId) + // TODO: NOT SURE HOW TO HANDLE THE TYPE ERROR. SOMEONE HELP. + // @ts-ignore + const docs = await getFromDb(db, keys, userId, asTaskDoc) const docsToDelete: any[] = [] docs.forEach(element => { - docsToDelete.push({ _id: element._id, _deleted: true, _rev: element._rev }) + docsToDelete.push({ _id: element.id, _deleted: true, _rev: element.rev }) }) db.bulk({ docs: docsToDelete }) @@ -78,21 +62,22 @@ export const deleteFromDb = async ( .catch(logger) } -export const getFromDb = async ( - db: nano.DocumentScope, +export const getFromDb = async ( + db: nano.DocumentScope>, keys: string[], - userId: string -): Promise => { + userId: string, + cleaner: Cleaner> +): Promise>> => { // Grab existing db data for requested dates const response = await db.partitionedList(userId).catch(logger) - if (response == null) return [] + if (response == null || !(response instanceof Object)) return [] return response.rows .filter(element => !('error' in element) && element.doc != null) .filter( element => keys.length === 0 || keys.includes(element.id.split(':')[1]) ) .map(({ doc }) => doc) - .map(asDbDoc) + .map(cleaner) } export const logger = (...args: any): void => { @@ -106,6 +91,19 @@ export const logger = (...args: any): void => { console.log(result) } +/** + * Convert a {@link Task} object into a {@link TaskDoc} object that + * implements {@link CouchDoc}. + * @param doc - A {@link Task} object. + * @returns {TaskDoc} - A {@link TaskDoc} object wrapping `doc`. + */ +export const packChange = (doc: T, id: string): CouchDoc => { + return { + id: id, + doc: doc + } +} + // ------------------------------------------------------------------------------ // Private Helpers // ------------------------------------------------------------------------------ diff --git a/tsconfig.json b/tsconfig.json index a10b6ac..fa71ccc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,8 +7,7 @@ "moduleResolution": "node", "resolveJsonModule": true, "noImplicitAny": false, - "noEmit": true, "strict": true } -} +} \ No newline at end of file diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..b4a044b --- /dev/null +++ b/typedoc.json @@ -0,0 +1,4 @@ +{ + "entryPoints": ["src/api/", "src/database/views/", "src/types/**/*.ts", "src/utils/**/*.ts", "src/publishers/**"], + "out": "docs/references" +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 45382d8..e2f70f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -600,11 +600,6 @@ any-promise@^1.0.0: resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -695,7 +690,7 @@ axios-cookiejar-support@^1.0.1: is-redirect "^1.0.0" pify "^5.0.0" -axios@^0.21.2: +axios@^0.21.1, axios@^0.21.2: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== @@ -755,6 +750,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -826,7 +828,7 @@ cleaner-config@^0.1.8: minimist "^1.2.5" sucrase "^3.17.1" -cleaners@^0.3.12, cleaners@^0.3.8: +cleaners@^0.3.11, cleaners@^0.3.12, cleaners@^0.3.8: version "0.3.12" resolved "https://registry.yarnpkg.com/cleaners/-/cleaners-0.3.12.tgz#0e99ef2460a59ed87550a60bdfc441b1696ff9cb" integrity sha512-bK7IvvYyhfy30S3VKmWi/YVWp0MUH1pEYfdtbjCpQiIzy8gmP9GCXv6AVZENDHbpcRHqMnZONs3ieyJMh3zvVw== @@ -991,6 +993,14 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +cron-parser@^2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.18.0.tgz#de1bb0ad528c815548371993f81a54e5a089edcf" + integrity sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg== + dependencies: + is-nan "^1.3.0" + moment-timezone "^0.5.31" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -1197,10 +1207,10 @@ ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: dependencies: safe-buffer "^5.0.1" -edge-server-tools@^0.2.11: - version "0.2.11" - resolved "https://registry.yarnpkg.com/edge-server-tools/-/edge-server-tools-0.2.11.tgz#802310ba12d09dc45d359338026dd68861e28ba6" - integrity sha512-dLvyD0TSZM30VsXkAV8nH3Xq7hA3NOUFnhYehCsVLe4BBt0WHjgwyB460xglxrWHx7HzYBKcED4o98rFiQ0ihg== +edge-server-tools@^0.2.13: + version "0.2.13" + resolved "https://registry.yarnpkg.com/edge-server-tools/-/edge-server-tools-0.2.13.tgz#d7686488e5a4915203c0220949758efa110b681a" + integrity sha512-FXLdAWVT/XGEM3PehENVVyXuC0vdS5e4KdchW3fpZFp4Wb8eAr3xmud7VhT4pyXIXsywS+nWiW5MhGQXpl6kdw== dependencies: cleaners "^0.3.11" nano "^9.0.4" @@ -2260,6 +2270,14 @@ is-map@^2.0.1: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1" integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw== +is-nan@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + is-negative-zero@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" @@ -2474,6 +2492,11 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +jsonc-parser@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.1.0.tgz#73b8f0e5c940b83d03476bc2e51a20ef0932615d" + integrity sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg== + jsonwebtoken@8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.1.0.tgz#c6397cd2e5fd583d65c007a83dc7bb78e6982b83" @@ -2691,6 +2714,11 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" +long-timeout@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514" + integrity sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w== + long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" @@ -2710,6 +2738,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lunr@^2.3.9: + version "2.3.9" + resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" + integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== + make-dir@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" @@ -2717,6 +2750,11 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +marked@^4.0.16: + version "4.0.18" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.18.tgz#cd0ac54b2e5610cfb90e8fd46ccaa8292c9ed569" + integrity sha512-wbLDJ7Zh0sqA0Vdg6aqlbT+yPxqLblpAZh1mK2+AO2twQkPywvvqQNfEPVwSSRjZ7dZcdeVBIAgiO7MMp3Dszw== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -2796,6 +2834,13 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" + integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" @@ -2864,6 +2909,17 @@ nano@10.0.0: qs "^6.10.3" tough-cookie "^4.0.0" +nano@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/nano/-/nano-9.0.5.tgz#2b767819f612907a3ac09b21f2929d4097407262" + integrity sha512-fEAhwAdXh4hDDnC8cYJtW6D8ivOmpvFAqT90+zEuQREpRkzA/mJPcI4EKv15JUdajaqiLTXNoKK6PaRF+/06DQ== + dependencies: + "@types/tough-cookie" "^4.0.0" + axios "^0.21.1" + axios-cookiejar-support "^1.0.1" + qs "^6.9.4" + tough-cookie "^4.0.0" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2906,6 +2962,15 @@ node-forge@^0.9.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5" integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ== +node-schedule@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/node-schedule/-/node-schedule-1.3.3.tgz#f8e01c5fb9597f09ecf9c4c25d6938e5e7a06f48" + integrity sha512-uF9Ubn6luOPrcAYKfsXWimcJ1tPFtQ8I85wb4T3NgJQrXazEzojcFZVk46ZlLHby3eEJChgkV/0T689IsXh2Gw== + dependencies: + cron-parser "^2.18.0" + long-timeout "0.1.1" + sorted-array-functions "^1.3.0" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -3332,7 +3397,7 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== -qs@^6.10.3: +qs@^6.10.3, qs@^6.9.4: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== @@ -3602,6 +3667,15 @@ shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== +shiki@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14" + integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng== + dependencies: + jsonc-parser "^3.0.0" + vscode-oniguruma "^1.6.1" + vscode-textmate "5.2.0" + shimmer@^1.1.0, shimmer@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" @@ -3673,6 +3747,11 @@ socks@~2.3.2: ip "1.1.5" smart-buffer "^4.1.0" +sorted-array-functions@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz#8605695563294dffb2c9796d602bd8459f7a0dd5" + integrity sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA== + source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -3861,7 +3940,7 @@ stubs@^3.0.0: resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= -sucrase@^3.17.1: +sucrase@^3.17.1, sucrase@^3.21.0: version "3.23.0" resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.23.0.tgz#2a7fa80a04f055fb2e95d2aead03fec1dba52838" integrity sha512-xgC1xboStzGhCnRywlBf/DLmkC+SkdAKqrNCDsxGrzM0phR5oUxoFKiQNrsc2D8wDdAm03iLbSZqjHDddo3IzQ== @@ -3989,18 +4068,6 @@ ts-interface-checker@^0.1.9: resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== -ts-node@^9.0.0: - version "9.1.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" - integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== - dependencies: - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - source-map-support "^0.5.17" - yn "3.1.1" - tsconfig-paths@^3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" @@ -4087,6 +4154,16 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typedoc@^0.23.8: + version "0.23.8" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.23.8.tgz#6837fb2732f73e7aa61b46a4fbe77a301473998d" + integrity sha512-NLRTY/7XSrhiowR3xnH/nlfTnHk+dkzhHWAMT8guoZ6RHCQZIu3pJREMCqzdkWVCC5+dr9We7TtNeprR3Qy6Ag== + dependencies: + lunr "^2.3.9" + marked "^4.0.16" + minimatch "^5.1.0" + shiki "^0.10.1" + typescript@^4.7.3: version "4.7.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.3.tgz#8364b502d5257b540f9de4c40be84c98e23a129d" @@ -4164,6 +4241,16 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +vscode-oniguruma@^1.6.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz#aeb9771a2f1dbfc9083c8a7fdd9cccaa3f386607" + integrity sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA== + +vscode-textmate@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e" + integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ== + walkdir@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.4.1.tgz#dc119f83f4421df52e3061e514228a2db20afa39"