+
+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;iGenerated using TypeDoc
Construct an HttpResponse object with a JSON body.
+Optional headers?: HttpHeadersOptional status?: numberGenerated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Reads & checks an untrusted value. Throws an exception if it's wrong.
+Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
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.
The object of query parameters.
+An array of query parameter names.
+The URL path.
+Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
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.
+ + +This server requires a working copies of Node.js, Yarn, PM2, and CouchDB. We also recommend using Caddy to terminate SSL connections.
+ + +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
+
+
+
+ pm2First, 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
+
+
+
+ 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
Readonly apiReadonly bodyReadonly headersReadonly methodReadonly pathReadonly payloadReadonly reqReadonly versionGenerated using TypeDoc
Readonly bodyReadonly headersReadonly methodReadonly pathReadonly reqReadonly versionGenerated using TypeDoc
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.
+Additional payload for consumption. For 'push' action type, data +must contain apiKey, body, message, and tokenIds to send +notifications.
+ +Optional inMutex implementation to prevent race conditions.
+Optional repeatIf true, the task will be reused, otherwise, the task will be +deleted after the action is completed.
+The type of the action.
+Generated using TypeDoc
Optional additionalGenerated using TypeDoc
Optional additionalGenerated using TypeDoc
Generated using TypeDoc
Optional additionalGenerated using TypeDoc
Optional aboveOptional belowOptional tokenGenerated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Optional aboveOptional belowGenerated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
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.
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Generated using TypeDoc
Const Generated using TypeDoc
Const Generated using TypeDoc
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.
+