diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..19c7bdb --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +16 \ No newline at end of file diff --git a/README.md b/README.md index bb60bf4..2743b8e 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,46 @@ # Quick Links - * [ZOMBIES! (:zombie: )](https://github.com/beeminder/road/issues?q=is:open+is:issue+label:ZOM "Open gissues labeled ZOM") -   |    -[Undotted i's (:eye: )](https://github.com/beeminder/road/issues?q=is:issue+is:closed+-label:zap+-label:nix+-label:cnr+-label:dup "Gissues that are closed but don't have any of the resolution labels: zap, nix, cnr, or dup") -   |    -[Active (:bug: )](https://github.com/beeminder/road/issues?q=is:issue+is:open+-label:ZzZ "Open gissues NOT labeled ZzZ") -   |    -[Snoozed (:zzz: )](https://github.com/beeminder/road/issues?q=is:issue+is:open+label:ZzZ "Open gissues labeled ZzZ") -   |    -[Closed (:heavy_check_mark: )](https://github.com/beeminder/road/issues?q=is:issue+is:closed "Closed gissues") -* Freshgishing ([blog post](https://blog.beeminder.com/freshen/ "Backlog Freshening")): -   -[Uluc](https://github.com/beeminder/road/issues?q=is:issue+is:open+sort:updated-asc+-label:ZzZ+assignee:saranli "Open non-snoozed gissues, oldest first, assigned to Uluc") -   |    -[Danny/all](https://github.com/beeminder/road/issues?q=is:issue+is:open+sort:updated-asc+-label:ZzZ "Open non-snoozed gissues, oldest first, assigned to anyone (what Danny uses for freshgishing)") -* [Probably-peasy UVIs](https://github.com/beeminder/road/issues?q=is:issue+is:open+label:UVI+label:PEA+label:ABC+-label:SKY "Open gissues that are peasy (PEA), not sky-pie (SKY), user-visible (UVI), and just involve webcopy (ABC)") -   |    -[Potentially-peasy UVIs](https://github.com/beeminder/road/issues?q=is:issue+is:open+label:UVI+label:PEA "Open gissues that are peasy (PEA) and user-visible (UVI)") +- [ZOMBIES! (:zombie: )](https://github.com/beeminder/road/issues?q=is:open+is:issue+label:ZOM "Open gissues labeled ZOM") +    |    + [Undotted i's (:eye: )](https://github.com/beeminder/road/issues?q=is:issue+is:closed+-label:zap+-label:nix+-label:cnr+-label:dup "Gissues that are closed but don't have any of the resolution labels: zap, nix, cnr, or dup") +    |    + [Active (:bug: )](https://github.com/beeminder/road/issues?q=is:issue+is:open+-label:ZzZ "Open gissues NOT labeled ZzZ") +    |    + [Snoozed (:zzz: )](https://github.com/beeminder/road/issues?q=is:issue+is:open+label:ZzZ "Open gissues labeled ZzZ") +    |    + [Closed (:heavy_check_mark: )](https://github.com/beeminder/road/issues?q=is:issue+is:closed "Closed gissues") +- Freshgishing ([blog post](https://blog.beeminder.com/freshen/ "Backlog Freshening")): +    + [Uluc](https://github.com/beeminder/road/issues?q=is:issue+is:open+sort:updated-asc+-label:ZzZ+assignee:saranli "Open non-snoozed gissues, oldest first, assigned to Uluc") +    |    + [Danny/all](https://github.com/beeminder/road/issues?q=is:issue+is:open+sort:updated-asc+-label:ZzZ "Open non-snoozed gissues, oldest first, assigned to anyone (what Danny uses for freshgishing)") +- [Probably-peasy UVIs](https://github.com/beeminder/road/issues?q=is:issue+is:open+label:UVI+label:PEA+label:ABC+-label:SKY "Open gissues that are peasy (PEA), not sky-pie (SKY), user-visible (UVI), and just involve webcopy (ABC)") +    |    + [Potentially-peasy UVIs](https://github.com/beeminder/road/issues?q=is:issue+is:open+label:UVI+label:PEA "Open gissues that are peasy (PEA) and user-visible (UVI)") # Beebrain and the Beeminder Graph Editor This repository includes Javascript packages implementing all Beebrain functionality, as well as an interactive editor for Beeminder's Bright Red Lines. -Description of original Beebrain: +Description of original Beebrain: ## Components and Features -* Javascript modules for processing Beeminder goal BB files -({@link module:butil `butil`}, -{@link module:broad `broad`}, -{@link module:beebrain `beebrain`}) -* A Javascript module for goal graph generation and an interactive graph editor -({@link module:bgraph `bgraph`}) -* A Javascript module implementing a sandbox for experimenting with Beemidner goals -({@link module:bsandbox `bsandbox`}) -* A Javascript module to facilitate automated testing and comparison of beebrain outputs -({@link module:btest `btest`}) -* A Node server that uses the modules above to locally generate graph PNG and SVG, thumbnail PNG, and goal JSON output files upon receiving a GET request -* A Node server that provides a web interface for client-side graphs, graph editor, and sandbox functionality -* A Node server that duplicates the behaviors of sanity.py from pybrain -* Various static HTML pages to test beebrain, graph, editor and sandbox functionality +- Javascript modules for processing Beeminder goal BB files + ({@link module:butil `butil`}, + {@link module:broad `broad`}, + {@link module:beebrain `beebrain`}) +- A Javascript module for goal graph generation and an interactive graph editor + ({@link module:bgraph `bgraph`}) +- A Javascript module implementing a sandbox for experimenting with Beemidner goals + ({@link module:bsandbox `bsandbox`}) +- A Javascript module to facilitate automated testing and comparison of beebrain outputs + ({@link module:btest `btest`}) +- A Node server that uses the modules above to locally generate graph PNG and SVG, thumbnail PNG, and goal JSON output files upon receiving a GET request +- A Node server that provides a web interface for client-side graphs, graph editor, and sandbox functionality +- A Node server that duplicates the behaviors of sanity.py from pybrain +- Various static HTML pages to test beebrain, graph, editor and sandbox functionality ## Getting started @@ -56,9 +56,9 @@ Or just edit in your path wherever it says `$BBPATH` below. The directory `tests` has HTML files illustrating various Beebrain functionality: -* `basic_test.html` : Showcases client-side graphs -* `roadeditor_test.html` : Showcases client-side graphs and the graph editor -* `sandbox.html` : Showcases a Beeminder sandbox to create and experiment with goals +- `basic_test.html` : Showcases client-side graphs +- `roadeditor_test.html` : Showcases client-side graphs and the graph editor +- `sandbox.html` : Showcases a Beeminder sandbox to create and experiment with goals You can load them in Chromium or Chrome with the following command: @@ -68,44 +68,39 @@ You can load them in Chromium or Chrome with the following command: (Chrome on MacOS) `open -na /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --allow-file-access-from-files --disable-web-security --user-data-dir=$BBPATH/chromium-data --remote-debugging-port=9222 --use-gl=osmesa file://$BBPATH/tests/basic_test.html file://$BBPATH/tests/roadeditor_test.html file://$BBPATH/tests/sandbox.html` -The scary-looking arguments allow the browser to open local Beeminder files from within Javascript functions. +The scary-looking arguments allow the browser to open local Beeminder files from within Javascript functions. ### Node server for client-side graphs, graph editor, and sandbox demos -This repository contains a Node server instance for serving various demo pages to browser clients. +This repository contains a Node server instance for serving various demo pages to browser clients. -After you clone this repository, install necessary Node modules in the root directory: +To install dependencies and compile the project, run the following commands: -`npm update` - -Once all module dependencies are installed, generate minified and concatanated files based on sources in `src`. -To do that, you may need to first install the command line interface for Gulp: - -`sudo npm install --global gulp-cli` - -which now enables you to use the gulp command. -Now, you can generate all distribution files with +```bash +nvm use # use the correct Node version +npm ci # install all dependencies +npm run compile # generate distribution files +``` -`gulp compile` +After installing Node modules and using Gulp to compile js modules, you will need to provide a `.env` file with proper server settings to access central Beeminder servers for your login. After copying `template.dev.env` or `template.prod.env` to `.env`, read the comments in `.env` and update the file with proper settings. -After updating Node modules and using Gulp to compile js modules, you will need to provide a `.data` directory with a local sqlite database and a `.env` file with proper server settings to access central Beeminder servers for your login (contact us for details). -Once this is done, you can start the demo server with +Once this is done, you can start the demo server: `npm start` -This starts a web server on `localhost`, with different features available through different paths. -This server should also be embeddable in Glitch. +This starts a web server on `localhost`, with different features available through different paths. +This server should also be embeddable in Glitch. The following paths are available: - * `/editor` : Client-side graph and interactive graph editor for example goals - * `/sandbox` : Client-side sandbox to create and experiment with dummy goals - * `/login` : Authorizes these pages to access your Beeminder goals - * `/logout` : De-authorizes access to your Beeminder goals - * `/road` : Client-side graph and interactive graph editor for your Beeminder goals +- `/editor` : Client-side graph and interactive graph editor for example goals +- `/sandbox` : Client-side sandbox to create and experiment with dummy goals +- `/login` : Authorizes these pages to access your Beeminder goals +- `/logout` : De-authorizes access to your Beeminder goals +- `/road` : Client-side graph and interactive graph editor for your Beeminder goals The last three require setting up oauth redirect uri configuration properly with beeminder servers, so it would require proper settings -in `.env`. The first two should work locally though. Note that getting +in `.env`. Note that getting the last three to work requires the Node server being accessible from beeminder servers for the redirect_uri provided in `.env`, associated with the clientid also configured in `.env`. @@ -120,7 +115,7 @@ the directory `jsbrain_server`. You should first update Node modules with `cd jsbrain_server` `npm update` -At this point, you can start the server in the same directory with +At this point, you can start the server in the same directory with `npm start` @@ -128,46 +123,47 @@ which should start a Node server on port 3000. At this point, every GET request you issue to `localhost:3000` with appropriate parameters will initiate graph generation. valid parameters are: - * `inpath=/path/to/input` : Path to local directory for the BB file - * `outpath=/path/to/output`: (optional) Path to local directory for generated files - * `user=u`: beeminder username (`slug` param must be empty) - * `goal=g`: beeminder goalname (`slug` param must be empty) - * `slug=filebase`: base name for the BB files (`user` and `goal` params must be empty) - * `pyjson=/path/to/pyout/slug.json`: (optional) Local path to pybrain JSON output - +- `inpath=/path/to/input` : Path to local directory for the BB file +- `outpath=/path/to/output`: (optional) Path to local directory for generated files +- `user=u`: beeminder username (`slug` param must be empty) +- `goal=g`: beeminder goalname (`slug` param must be empty) +- `slug=filebase`: base name for the BB files (`user` and `goal` params must be empty) +- `pyjson=/path/to/pyout/slug.json`: (optional) Local path to pybrain JSON output + This reads the file `u+g.bb` (or `slug.bb`) from `/path/to/input`, and generates `u+g.png`, `u+g-thumb.png`, `u+g.svg` and `u+g.json` in -`/path/to/output`. +`/path/to/output`. ### Generating this documentation -Do `gulp gendoc` in the root directory and point your browser to +Do `gulp gendoc` in the root directory and point your browser to `file:///path/to/road/docs/index.html` ## Appendix -### A. Directory structure +### A. Directory structure The directory structure for this repository is organized as follows - * `src` : Javascript and CSS sources - * `lib` : Files generated and copied by gulp, served under `/lib` - * `data`: Example BB files, accessible through `/data` - * `views`: express.js view templates - * `tests`: HTML files for various local tests, loading scripts from `src` - * `jsbrain_server`:Local server to handle graph generation requests - +- `src` : Javascript and CSS sources +- `lib` : Files generated and copied by gulp, served under `/lib` +- `data`: Example BB files, accessible through `/data` +- `views`: express.js view templates +- `tests`: HTML files for various local tests, loading scripts from `src` +- `jsbrain_server`:Local server to handle graph generation requests + Emacs environment: - * indium works well - * sr-speedbar is docked - * imenu requires *rescan* from the top menu - * M-x indium-connect connects to a running chrom instance configured in the .indium file - * Had to rename menu names in js2 and indium el files to shorten their names - * purpose-mode is useful to keep windows with what they are for - * For development, the following fonts seem to be good options: - * Hack: https://github.com/source-foundry/Hack - * OfficeCodePro: https://github.com/nathco/Office-Code-Pro - * Font rendering: https://wiki.manjaro.org/index.php?title=Improve_Font_Rendering + +- indium works well +- sr-speedbar is docked +- imenu requires _rescan_ from the top menu +- M-x indium-connect connects to a running chrom instance configured in the .indium file +- Had to rename menu names in js2 and indium el files to shorten their names +- purpose-mode is useful to keep windows with what they are for +- For development, the following fonts seem to be good options: + - Hack: https://github.com/source-foundry/Hack + - OfficeCodePro: https://github.com/nathco/Office-Code-Pro + - Font rendering: https://wiki.manjaro.org/index.php?title=Improve_Font_Rendering ### B. Deployment to Glitch (or similar) diff --git a/app/server.js b/app/server.js index ec00ad0..6ef9af1 100644 --- a/app/server.js +++ b/app/server.js @@ -1,401 +1,479 @@ "use strict"; // -------------------------------- (80chars) ---------------------------------> -require('dotenv').config() +require("dotenv").config(); - -var express = require('express') -var https = require('https') -var http = require('http') -var bodyParser = require('body-parser') -var session = require('express-session') -var Sequelize = require('sequelize') -var request = require('request') +var express = require("express"); +var https = require("https"); +var http = require("http"); +var bodyParser = require("body-parser"); +var session = require("express-session"); +var Sequelize = require("sequelize"); +var request = require("request"); // Setting session store to Sequelize -var SequelizeStore = require('connect-session-sequelize')(session.Store) +var SequelizeStore = require("connect-session-sequelize")(session.Store); // Initializing the app -var app = express() +var app = express(); -function setsession(req) { -} +function setsession(req) {} // Enabling cookies via HTTPS -app.set('trust proxy', 1) -app.set('view engine', 'ejs'); +app.set("trust proxy", 1); +app.set("view engine", "ejs"); // Enabling JSON request parser -app.use(bodyParser.json()) -app.use(bodyParser.urlencoded({extended: true})) +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); // Initiate global model class for user -var User = null +var User = null; // Setting up a new database using database credentials set in .env -var sequelize = new Sequelize('database', process.env.DB_USER, - process.env.DB_PASS, { - host: '0.0.0.0', - dialect: 'sqlite', - pool: { - max: 5, - min: 0, - idle: 10000 - }, - // Security note: the database is saved to the file `database.sqlite` in - // the local filesystem. It's deliberately placed in the `.data` directory - // which doesn't get copied if someone remixes the project. - storage: '.data/database.sqlite' -}) +var sequelize = new Sequelize( + "database", + process.env.DB_USER, + process.env.DB_PASS, + { + host: "0.0.0.0", + dialect: "sqlite", + pool: { + max: 5, + min: 0, + idle: 10000, + }, + // Security note: the database is saved to the file `database.sqlite` in + // the local filesystem. It's deliberately placed in the `.data` directory + // which doesn't get copied if someone remixes the project. + storage: ".data/database.sqlite", + } +); // Setting up session parameters -app.use(session({ - secret: process.env.SESSION_SECRET, - store: new SequelizeStore({ db: sequelize }), - saveUninitialized: false, - resave: false, - cookie: { secure: true }, - trustProxie: true -})) +app.use( + session({ + secret: process.env.SESSION_SECRET, + store: new SequelizeStore({ db: sequelize }), + saveUninitialized: false, + resave: false, + cookie: { secure: process.env.NODE_ENV !== "development" }, + trustProxie: true, + }) +); // Connecting to the database and defining Models -sequelize.authenticate() +sequelize + .authenticate() .then((err) => { - console.log('Database connection established.') - User = sequelize.define('users', { // Defining table 'users' - username: { type: Sequelize.STRING }, - access_token: { type: Sequelize.STRING } - }) - sequelize.sync() // Creating table User if it does not exist + console.log("Database connection established."); + User = sequelize.define("users", { + // Defining table 'users' + username: { type: Sequelize.STRING }, + access_token: { type: Sequelize.STRING }, + }); + sequelize.sync(); // Creating table User if it does not exist }) .catch((err) => { - console.log('Unable to connect to the database: ', err) - }) - + console.log("Unable to connect to the database: ", err); + }); // Stuff in the pub directory is served statically -app.use('/staticdesign', express.static('tests/newdesign.html')) -app.use('/tutorial', express.static('tests/tutorial.html')) -app.use('/newgoal', express.static('tests/newgoal.html')) +app.use("/staticdesign", express.static("tests/newdesign.html")); +app.use("/tutorial", express.static("tests/tutorial.html")); +app.use("/newgoal", express.static("tests/newgoal.html")); // Serve js files under the src directory through /src -app.use('/src', express.static('src')) +app.use("/src", express.static("src")); // Serve BB files under the data directory through /data -app.use('/data', express.static('data')) +app.use("/data", express.static("data")); // Serve JS, CSS and other files under the list directory in /lib -app.use('/lib', express.static('lib')) +app.use("/lib", express.static("lib")); var listener = app.listen(process.env.PORT, () => { - console.log(`Graph Editor app is running on port ${listener.address().port}`) - console.log(`AUTH_REDIRECT_URI is ${process.env.AUTH_REDIRECT_URI}`) -}) + console.log(`Graph Editor app is running on port ${listener.address().port}`); + console.log(`AUTH_REDIRECT_URI is ${process.env.AUTH_REDIRECT_URI}`); +}); app.get("/login", (req, resp) => { - setsession(req) - //console.log("!!!! GOT LOGIN !!!!") - //console.log(req.session) - if(typeof req.session.access_token === 'undefined' || - req.session.access_token === null) { - - resp.render('login.ejs', { - BEEMINDER_CLIENT_ID: process.env.BEEMINDER_CLIENT_ID, - AUTH_REDIRECT_URI: process.env.AUTH_REDIRECT_URI - }) + setsession(req); + console.log("!!!! GOT LOGIN !!!!"); + console.log(req.session); + if ( + typeof req.session.access_token === "undefined" || + req.session.access_token === null + ) { + resp.render("login.ejs", { + BEEMINDER_CLIENT_ID: process.env.BEEMINDER_CLIENT_ID, + AUTH_REDIRECT_URI: process.env.AUTH_REDIRECT_URI, + }); } else { - resp.redirect('/') + resp.redirect("/"); } -}) +}); app.get("/newdesign", (req, resp) => { - resp.redirect('/') -}) + resp.redirect("/"); +}); app.get("/road", (req, resp) => { - setsession(req) - if (typeof req.session.access_token === 'undefined' || - req.session.access_token === null) { - resp.redirect('/login') + setsession(req); + if ( + typeof req.session.access_token === "undefined" || + req.session.access_token === null + ) { + resp.redirect("/login"); } else { var user = { username: req.session.username, - access_token: req.session.access_token - } - resp.render('newdesign.ejs', {user: user}) + access_token: req.session.access_token, + }; + resp.render("newdesign.ejs", { user: user }); } -}) +}); app.get("/olddesign", (req, resp) => { - setsession(req) - if (typeof req.session.access_token === 'undefined' || - req.session.access_token === null) { - resp.redirect('/login') + setsession(req); + if ( + typeof req.session.access_token === "undefined" || + req.session.access_token === null + ) { + resp.redirect("/login"); } else { var user = { username: req.session.username, - access_token: req.session.access_token - } - resp.render('road.ejs', {user: user}) + access_token: req.session.access_token, + }; + resp.render("road.ejs", { user: user }); } -}) +}); app.get("/editor", (req, resp) => { - resp.render('road.ejs', {user: null}) -}) + resp.render("road.ejs", { user: null }); +}); app.get("/sandbox", (req, resp) => { - resp.render('sandbox.ejs') -}) + resp.render("sandbox.ejs"); +}); app.get("/", (req, resp) => { - setsession(req) - if (typeof req.session.access_token === 'undefined' || - req.session.access_token === null) { - resp.redirect('/login') + setsession(req); + if ( + typeof req.session.access_token === "undefined" || + req.session.access_token === null + ) { + resp.redirect("/login"); } else { var user = { username: req.session.username, - access_token: req.session.access_token - } - resp.render('newdesign.ejs', {user: user}) + access_token: req.session.access_token, + }; + resp.render("newdesign.ejs", { user: user }); } -}) - +}); -// Callback endpoint to receive username and access_token from Beeminder upon +// Callback endpoint to receive username and access_token from Beeminder upon // successful authorization app.get("/connect", (req, resp) => { - if(typeof req.query.access_token === 'undefined' || - typeof req.query.username === 'undefined') { - req.session.access_token = null - req.session.username = null - if(typeof req.query.error != 'undefined') { - req.session.error = req.query.error - req.session.error_description = req.query.error_description + if ( + typeof req.query.access_token === "undefined" || + typeof req.query.username === "undefined" + ) { + req.session.access_token = null; + req.session.username = null; + if (typeof req.query.error != "undefined") { + req.session.error = req.query.error; + req.session.error_description = req.query.error_description; } } else { - req.session.access_token = req.query.access_token - req.session.username = req.query.username + console.log("Setting session", req.query.access_token, req.query.username); + console.log(process.env); + req.session.access_token = req.query.access_token; + req.session.username = req.query.username; } - resp.redirect('/login') -}) + resp.redirect("/login"); +}); app.get("/logout", (req, resp) => { - req.session.access_token = null - req.session.username = null - resp.redirect('/') -}) + req.session.access_token = null; + req.session.username = null; + resp.redirect("/"); +}); app.get("/getusergoals", (req, resp) => { - setsession(req) - if(!req.session.access_token || !req.session.username) { - resp.redirect('/login') + setsession(req); + if (!req.session.access_token || !req.session.username) { + resp.redirect("/login"); } - beemGetUser({ - username: req.session.username, - access_token: req.session.access_token - }, (goals)=> { - resp.send(JSON.stringify( goals )) - }, (error)=> { console.log(error) }) -}) + beemGetUser( + { + username: req.session.username, + access_token: req.session.access_token, + }, + (goals) => { + resp.send(JSON.stringify(goals)); + }, + (error) => { + console.log(error); + } + ); +}); app.get("/getgoaljson/:goal", (req, resp) => { - setsession(req) - if(!req.session.access_token || !req.session.username) { - resp.redirect('/login') + setsession(req); + if (!req.session.access_token || !req.session.username) { + resp.redirect("/login"); } //console.log("user: "+req.session.username+" "+req.session.access_token) - beemGetGraphParams({ - username: req.session.username, - goalslug: req.params.goal, - access_token: req.session.access_token - - }, (goals)=> { - resp.send(JSON.stringify( goals )) - }, (error)=> { console.log(error) }) -}) + beemGetGraphParams( + { + username: req.session.username, + goalslug: req.params.goal, + access_token: req.session.access_token, + }, + (goals) => { + resp.send(JSON.stringify(goals)); + }, + (error) => { + console.log(error); + } + ); +}); -app.post("/submitroad/:goal", (req, resp)=>{ - setsession(req) - if(!req.session.access_token || !req.session.username) { - resp.redirect('/login') +app.post("/submitroad/:goal", (req, resp) => { + setsession(req); + if (!req.session.access_token || !req.session.username) { + resp.redirect("/login"); } - beemSubmitRoad({ - usr: req.session.username, - gol: req.params.goal, - access_token: req.session.access_token, - roadall: JSON.stringify(req.body.road) - }, function(error, response, body) { - if (error) { - return console.error('submit failed:', error); + beemSubmitRoad( + { + usr: req.session.username, + gol: req.params.goal, + access_token: req.session.access_token, + roadall: JSON.stringify(req.body.road), + }, + function (error, response, body) { + if (error) { + return console.error("submit failed:", error); + } + resp.send(body); + //console.log("success? ") + //console.log(body) } - resp.send(body) - //console.log("success? ") - //console.log(body) - }) -}) + ); +}); -app.post("/data/:goal", (req, resp)=>{ - setsession(req) - if(!req.session.access_token || !req.session.username) { - resp.redirect('/login') +app.post("/data/:goal", (req, resp) => { + setsession(req); + if (!req.session.access_token || !req.session.username) { + resp.redirect("/login"); } - beemSubmitPoint({ - usr: req.session.username, - gol: req.params.goal, - access_token: req.session.access_token, - daystamp: req.body.daystamp, - timestamp: req.body.timestamp, - value: req.body.value, - comment: req.body.comment - }, function(error, response, body) { - if (error) { - return console.error('submit point failed:', error); + beemSubmitPoint( + { + usr: req.session.username, + gol: req.params.goal, + access_token: req.session.access_token, + daystamp: req.body.daystamp, + timestamp: req.body.timestamp, + value: req.body.value, + comment: req.body.comment, + }, + function (error, response, body) { + if (error) { + return console.error("submit point failed:", error); + } + resp.send(body); } - resp.send(body) - }) -}) + ); +}); -app.delete("/data/:goal/:id", (req, resp)=>{ - setsession(req) - if(!req.session.access_token || !req.session.username) { - resp.redirect('/login') +app.delete("/data/:goal/:id", (req, resp) => { + setsession(req); + if (!req.session.access_token || !req.session.username) { + resp.redirect("/login"); } - beemDeletePoint({ - usr: req.session.username, - gol: req.params.goal, - access_token: req.session.access_token, - id: req.params.id - }, function(error, response, body) { - if (error) { - return console.error('delete point failed:', error); + beemDeletePoint( + { + usr: req.session.username, + gol: req.params.goal, + access_token: req.session.access_token, + id: req.params.id, + }, + function (error, response, body) { + if (error) { + return console.error("delete point failed:", error); + } + resp.send(body); } - resp.send(body) - }) -}) + ); +}); -app.put("/data/:goal/:id", (req, resp)=>{ - setsession(req) - if(!req.session.access_token || !req.session.username) { - resp.redirect('/login') +app.put("/data/:goal/:id", (req, resp) => { + setsession(req); + if (!req.session.access_token || !req.session.username) { + resp.redirect("/login"); } - beemUpdatePoint({ - usr: req.session.username, - gol: req.params.goal, - access_token: req.session.access_token, - id: req.params.id, - timestamp: req.body.timestamp, - value: req.body.value, - comment: req.body.comment - }, function(error, response, body) { - if (error) { - return console.error('delete point failed:', error); + beemUpdatePoint( + { + usr: req.session.username, + gol: req.params.goal, + access_token: req.session.access_token, + id: req.params.id, + timestamp: req.body.timestamp, + value: req.body.value, + comment: req.body.comment, + }, + function (error, response, body) { + if (error) { + return console.error("delete point failed:", error); + } + resp.send(body); } - resp.send(body) - }) -}) + ); +}); // helper functions function beemSubmitRoad(params, callback) { var options = { - url: 'https://www.beeminder.com/api/v1/users/'+params.usr+'/goals/'+params.gol+'.json', - method: 'PUT', + url: + "https://www.beeminder.com/api/v1/users/" + + params.usr + + "/goals/" + + params.gol + + ".json", + method: "PUT", json: true, body: { access_token: params.access_token, - roadall: params.roadall - } - } - request.put(options, callback) + roadall: params.roadall, + }, + }; + request.put(options, callback); } function beemSubmitPoint(params, callback) { - let r = Math.random().toString(36).substring(7) + let r = Math.random().toString(36).substring(7); var options = { - url: 'https://www.beeminder.com/api/v1/users/'+params.usr+'/goals/'+params.gol+'/datapoints.json', - method: 'POST', + url: + "https://www.beeminder.com/api/v1/users/" + + params.usr + + "/goals/" + + params.gol + + "/datapoints.json", + method: "POST", json: true, form: { access_token: params.access_token, daystamp: params.daystamp, comment: params.comment, value: params.value, - requestid: r - } - } - request.post(options, callback) + requestid: r, + }, + }; + request.post(options, callback); } function beemDeletePoint(params, callback) { var options = { - url: 'https://www.beeminder.com/api/v1/users/'+params.usr+'/goals/'+params.gol+'/datapoints/'+params.id+".json", - method: 'DELETE', + url: + "https://www.beeminder.com/api/v1/users/" + + params.usr + + "/goals/" + + params.gol + + "/datapoints/" + + params.id + + ".json", + method: "DELETE", json: true, form: { - access_token: params.access_token - } - } - request.delete(options, callback) + access_token: params.access_token, + }, + }; + request.delete(options, callback); } function beemUpdatePoint(params, callback) { var options = { - url: 'https://www.beeminder.com/api/v1/users/'+params.usr+'/goals/'+params.gol+'/datapoints/'+params.id+".json", - method: 'PUT', + url: + "https://www.beeminder.com/api/v1/users/" + + params.usr + + "/goals/" + + params.gol + + "/datapoints/" + + params.id + + ".json", + method: "PUT", json: true, form: { access_token: params.access_token, timestamp: params.timestamp, comment: params.comment, - value: params.value - } - } - request.put(options, callback) + value: params.value, + }, + }; + request.put(options, callback); } -function beemGetUser(user, callback, error_callback = ()=>{}) { +function beemGetUser(user, callback, error_callback = () => {}) { var options = { - host: 'www.beeminder.com', + host: "www.beeminder.com", port: 443, - path: '/api/v1/users/' + user.username + '.json?access_token=' + user.access_token, - method: 'GET' - } + path: + "/api/v1/users/" + + user.username + + ".json?access_token=" + + user.access_token, + method: "GET", + }; var req = https.request(options, (res) => { - var data = '' - res.on('data', (chunk) => { - data = data + chunk - }).on('end', () => { - var userd = JSON.parse(data) - if(userd) { //???? what's an error look like here? - callback(userd.goals) - } else { - error_callback(data) - } - }) - }) - req.on('error', (e) => { - console.log('problem with request: ' + e.message) - error_callback(e.message) - }) - req.write('') - req.end() + var data = ""; + res + .on("data", (chunk) => { + data = data + chunk; + }) + .on("end", () => { + var userd = JSON.parse(data); + if (userd) { + //???? what's an error look like here? + callback(userd.goals); + } else { + error_callback(data); + } + }); + }); + req.on("error", (e) => { + console.log("problem with request: " + e.message); + error_callback(e.message); + }); + req.write(""); + req.end(); } -function beemGetGraphParams(usergoal, callback, error_callback = ()=>{}) { +function beemGetGraphParams(usergoal, callback, error_callback = () => {}) { var options = { - host: 'www.beeminder.com', + host: "www.beeminder.com", port: 443, - path: '/api/vx/users/' + usergoal.username + '/goals/' + usergoal.goalslug + '/graph.json?access_token=' + usergoal.access_token, - method: 'GET' - } + path: + "/api/vx/users/" + + usergoal.username + + "/goals/" + + usergoal.goalslug + + "/graph.json?access_token=" + + usergoal.access_token, + method: "GET", + }; var req = https.request(options, (res) => { - var data = '' - res.on('data', (chunk) => { - data = data + chunk - }).on('end', () => { - var goald = JSON.parse(data) - if(goald) { //???? what's an error look like here? - callback(goald) - } else { - error_callback(data) - } - }) - }) - req.on('error', (e) => { - console.log('problem with request: ' + e.message) - error_callback(e.message) - }) - req.write('') - req.end() + var data = ""; + res + .on("data", (chunk) => { + data = data + chunk; + }) + .on("end", () => { + var goald = JSON.parse(data); + if (goald) { + //???? what's an error look like here? + callback(goald); + } else { + error_callback(data); + } + }); + }); + req.on("error", (e) => { + console.log("problem with request: " + e.message); + error_callback(e.message); + }); + req.write(""); + req.end(); } diff --git a/jsdoc.json b/jsdoc.json index ca21f5a..7474565 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -1,15 +1,15 @@ { "opts": { "destination": "./docs", - "tutorials":"./tutorials" + "tutorials": "./tutorials" }, - "templates":{ + "templates": { "includeDate": false, "dateFormat": " ", - "default":{ + "default": { "includeDate": false, - "staticFiles":{ - "include":["./tutorials/static"] + "staticFiles": { + "include": ["./tutorials/static"] } } } diff --git a/package-lock.json b/package-lock.json index c2f0245..0c72ee9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,9 +34,10 @@ "gulp-concat": "^2.6.1", "gulp-jsdoc3": "^2.0.0", "gulp-jshint": "^2.1.0", - "gulp-minify": "^3.0.0", + "gulp-minify": "^3.1.0", "gulp-typescript": "^6.0.0-alpha.1", "jshint": "^2.13.0", + "nodemon": "^2.0.20", "typescript": "^3.9.9" }, "engines": { @@ -44,9 +45,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.1.tgz", - "integrity": "sha512-JzhBFpkuhBNYUY7qs+wTzNmyCWUHEaAFpQQD2YfU1rPL38/L43Wvid0fFkiOCnHvsGncRZgEPyGnltABLcVDTg==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", + "integrity": "sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1971,9 +1972,9 @@ } }, "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", "dev": true, "engines": { "node": ">=0.10" @@ -3487,16 +3488,16 @@ } }, "node_modules/gulp-minify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-minify/-/gulp-minify-3.0.0.tgz", - "integrity": "sha512-G7i4hrVqPRzhXvF0ZXDVb+J82rwZ6s1pr8fjL2TN9tR+rsBZMUQ4HmMTpUExIvMu8y3p6HbhQCWowRFZ9enLjw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gulp-minify/-/gulp-minify-3.1.0.tgz", + "integrity": "sha512-ixF41aYg+NQikI8hpoHdEclYcQkbGdXQu1CBdHaU7Epg8H6e8d2jWXw1+rBPgYwl/XpKgjHj7NI6gkhoSNSSAg==", "dev": true, "dependencies": { "ansi-colors": "^1.0.1", "minimatch": "^3.0.2", "plugin-error": "^0.1.2", + "terser": "^3.7.6", "through2": "^2.0.3", - "uglify-es": "^3.0.3", "vinyl": "^2.1.0" } }, @@ -3780,9 +3781,9 @@ "dev": true }, "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "optional": true }, "node_modules/http-errors": { @@ -3912,6 +3913,12 @@ "node": ">=0.10.0" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -5416,6 +5423,232 @@ "node": ">= 8" } }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/nodemon/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nodemon/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nodemon/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nodemon/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/nodemon/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nodemon/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nodemon/node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nodemon/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -5959,6 +6192,18 @@ "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -6147,6 +6392,12 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "node_modules/pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", @@ -6829,9 +7080,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/sequelize": { - "version": "6.29.0", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.0.tgz", - "integrity": "sha512-m8Wi90rs3NZP9coXE52c7PL4Q078nwYZXqt1IxPvgki7nOFn0p/F0eKsYDBXCPw9G8/BCEa6zZNk0DQUAT4ypA==", + "version": "6.29.1", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.1.tgz", + "integrity": "sha512-EL7HAPtOFyi2h3O4lVdetAzDK0AkLQkK608CRRKB8U9o2swx+4MQKgxAIdcJsB0vud6LqKdVLL7Vfc51glgTYA==", "funding": [ { "type": "opencollective", @@ -7009,6 +7260,27 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -7266,6 +7538,16 @@ "urix": "^0.1.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/source-map-url": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", @@ -7622,6 +7904,29 @@ "node": ">=10" } }, + "node_modules/terser": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", + "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", + "dev": true, + "dependencies": { + "commander": "^2.19.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.10" + }, + "bin": { + "terser": "bin/uglifyjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -7831,29 +8136,6 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, - "node_modules/uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "deprecated": "support for ECMAScript is superseded by `uglify-js` as of v3.13.0", - "dev": true, - "dependencies": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/uglify-es/node_modules/commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - }, "node_modules/uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -7874,6 +8156,12 @@ "node": ">=0.10.0" } }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "node_modules/underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", @@ -8615,9 +8903,9 @@ }, "dependencies": { "@babel/parser": { - "version": "7.21.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.1.tgz", - "integrity": "sha512-JzhBFpkuhBNYUY7qs+wTzNmyCWUHEaAFpQQD2YfU1rPL38/L43Wvid0fFkiOCnHvsGncRZgEPyGnltABLcVDTg==" + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", + "integrity": "sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==" }, "@gar/promisify": { "version": "1.1.3", @@ -10114,9 +10402,9 @@ "dev": true }, "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==", "dev": true }, "deep-equal": { @@ -11371,16 +11659,16 @@ } }, "gulp-minify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-minify/-/gulp-minify-3.0.0.tgz", - "integrity": "sha512-G7i4hrVqPRzhXvF0ZXDVb+J82rwZ6s1pr8fjL2TN9tR+rsBZMUQ4HmMTpUExIvMu8y3p6HbhQCWowRFZ9enLjw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gulp-minify/-/gulp-minify-3.1.0.tgz", + "integrity": "sha512-ixF41aYg+NQikI8hpoHdEclYcQkbGdXQu1CBdHaU7Epg8H6e8d2jWXw1+rBPgYwl/XpKgjHj7NI6gkhoSNSSAg==", "dev": true, "requires": { "ansi-colors": "^1.0.1", "minimatch": "^3.0.2", "plugin-error": "^0.1.2", + "terser": "^3.7.6", "through2": "^2.0.3", - "uglify-es": "^3.0.3", "vinyl": "^2.1.0" } }, @@ -11605,9 +11893,9 @@ } }, "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", "optional": true }, "http-errors": { @@ -11706,6 +11994,12 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -12867,6 +13161,167 @@ } } }, + "nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, "nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -13285,6 +13740,12 @@ "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -13426,6 +13887,12 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", @@ -13953,9 +14420,9 @@ } }, "sequelize": { - "version": "6.29.0", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.0.tgz", - "integrity": "sha512-m8Wi90rs3NZP9coXE52c7PL4Q078nwYZXqt1IxPvgki7nOFn0p/F0eKsYDBXCPw9G8/BCEa6zZNk0DQUAT4ypA==", + "version": "6.29.1", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.29.1.tgz", + "integrity": "sha512-EL7HAPtOFyi2h3O4lVdetAzDK0AkLQkK608CRRKB8U9o2swx+4MQKgxAIdcJsB0vud6LqKdVLL7Vfc51glgTYA==", "requires": { "@types/debug": "^4.1.7", "@types/validator": "^13.7.1", @@ -14070,6 +14537,23 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, "smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -14274,6 +14758,16 @@ "urix": "^0.1.0" } }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "source-map-url": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", @@ -14555,6 +15049,25 @@ "yallist": "^4.0.0" } }, + "terser": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", + "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.10" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + } + } + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -14719,24 +15232,6 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "dev": true, - "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - } - } - }, "uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -14751,6 +15246,12 @@ "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", diff --git a/package.json b/package.json index 827def2..5a643b6 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Beeminder Graph Editor", "main": "server.js", "scripts": { - "start": "node app/server.js" + "start": "nodemon app/server.js", + "compile": "gulp compile" }, "dependencies": { "beeminder": "^1.7.0", @@ -43,9 +44,10 @@ "gulp-concat": "^2.6.1", "gulp-jsdoc3": "^2.0.0", "gulp-jshint": "^2.1.0", - "gulp-minify": "^3.0.0", + "gulp-minify": "^3.1.0", "gulp-typescript": "^6.0.0-alpha.1", "jshint": "^2.13.0", + "nodemon": "^2.0.20", "typescript": "^3.9.9" } -} \ No newline at end of file +} diff --git a/template.dev.env b/template.dev.env new file mode 100644 index 0000000..60880a6 --- /dev/null +++ b/template.dev.env @@ -0,0 +1,44 @@ +# ------------------------------------------------------------------------------ +# CAUTION: +# Ensure you're modifying the .env version of this file, not the +# template.*.env version. The .env version is the one that actually gets used +# by the code. The template.*.env version is the master copy that you copy to +# .env and then modify. +# ------------------------------------------------------------------------------ + +# Environment Config -- for secrets and config variables +# Reference these in the code with process.env.SECRET + +BEEMINDER_CLIENT_ID='REPLACEMEwithActualIDGeneratedByBeeminder' + +# Leave these unmodified unless you know what you're doing +PORT=3000 +AUTH_REDIRECT_URI='http://localhost:3000/connect' +DB_USER='' +DB_PASS='' +SESSION_SECRET='local_dev' + +# NB: .env is a shell file so there can't be spaces around '=' + +# Only the non-secret version of this file -- template.dev.env -- is in version +# control. And on Glitch, for example, only invited collaborators can see the +# secret .env version. + +# SETUP INSTRUCTIONS ----------------------------------------------------------- +# 0. This only has to be done once or when moving where this is hosted +# 1. Copy this file (template.dev.env) to .env and follow the remaining steps there +# 2. Log into your personal Beeminder account +# 3. Go to beeminder.com/apps and click Register A New App +# 4. Put "Beebrain Graph Editor" or similar as the application name +# 5. Put http://localhost:3000/connect as the Redirect URL +# 6. Ensure that AUTH_REDIRECT_URI above matches the Redirect URL in the previous step +# 7. Leave the Callback URLs blank in the Beeminder form +# 8. Click the Register button to register the app +# 9. Beeminder generates and shows you the Client ID and Client Secret +# 10. Copy the Client ID to the BEEMINDER_CLIENT_ID config variable here +# 11. Grep "REPLACEME" to ensure the only instance is the one in this sentence! +# +# To review, you've now copied this template.dev.env file to .env and filled in all +# the values for the config variables and ensured that the template.env version +# remains the master copy. This is confusing to the uninitiated! +# ------------------------------------------------------------------------------ diff --git a/template.env b/template.env deleted file mode 100644 index 3121c4a..0000000 --- a/template.env +++ /dev/null @@ -1,53 +0,0 @@ -# ------------------------------------------------------------------------------ -# REPLACEME with a master-copy-confusion warning -# ------------------------------------------------------------------------------ - -# Environment Config -- for secrets and config variables -# Reference these in the code with process.env.SECRET - -BEEMINDER_CLIENT_ID='REPLACEMEwithActualIDGeneratedByBeeminder' -BEEMINDER_CLIENT_SECRET='REPLACEMEwithActualSecretGeneratedByBeeminder' -AUTH_REDIRECT_URI='https://REPLACEMEwithProjectName.glitch.me/connect' -DB_USER='' -DB_PASS='' -SESSION_SECRET='REPLACEMEwithFreshlyGeneratedUUIDorOtherUniqueUnguessableString' - -# NB: .env is a shell file so there can't be spaces around '=' - -# Only the non-secret version of this file -- template.env -- is in version -# control. And on Glitch, for example, only invited collaborators can see the -# secret .env version. - -# SETUP INSTRUCTIONS ----------------------------------------------------------- -# 0. This only has to be done once or when moving where this is hosted -# 1. Copy this file (template.env) to .env and follow the remaining steps there -# 2. Replace the blurb at the top of this file (again, the .env version) with a -# big, prominent, impossible-to-miss master-copy-confusion warning about not -# editing the .env version of this file except as these instructions specify -# (This ensures that no one accidentally edits the wrong copy of these -# instructions or the names of config variables or anything and then is sad -# and confused when their edits vanish next time we do a fresh deploy. The -# only edits you should make to the .env version of this file are the -# specific replacements specified in these instructions. Making sense?) -# 3. Log in to Beeminder (I do this as user d but can be anyone, I think) -# 4. Go to beeminder.com/apps and click Register A New App -# 5. Put "Beebrain Graph Editor" or similar as the application name -# 6. Put https://graph.beeminder.com/connect as the Redirect URL -# (This used to be road.beeminder.com and could change again. We can also -# make any number of clones like graph-staging42.glitch.me and just add -# /connect to that to make the Redirect URL.) -# 5. Also fill that URL in here as the AUTH_REDIRECT_URI config variable -# 6. Leave the Callback URLs blank in the Beeminder form -# 7. Click the Register button to register the app -# 8. Beeminder generates and shows you the Client ID and Client Secret -# 9. Copy the Client ID to the BEEMINDER_CLIENT_ID config variable here -# 10. Copy the Client Secret to the BEEMINDER_CLIENT_SECRET config variable here -# (Weirdly this seems to be totally unused but I guess might as well do it?) -# 11. Leave the DB_USER and DB_PASS config variables blank (shrug) -# 12. Make up a UUID (long random string) for the SESSION_SECRET config variable -# 13. Grep "REPLACEME" to ensure the only instance is the one in this sentence! -# -# To review, you've now copied this template.env file to .env and filled in all -# the values for the config variables and ensured that the template.env version -# remains the master copy. This is confusing to the uninitiated! -# ------------------------------------------------------------------------------ diff --git a/template.prod.env b/template.prod.env new file mode 100644 index 0000000..485cabd --- /dev/null +++ b/template.prod.env @@ -0,0 +1,47 @@ +# ------------------------------------------------------------------------------ +# CAUTION: +# Ensure you're modifying the .env version of this file, not the +# template.*.env version. The .env version is the one that actually gets used +# by the code. The template.*.env version is the master copy that you copy to +# .env and then modify. +# ------------------------------------------------------------------------------ + +# Environment Config -- for secrets and config variables +# Reference these in the code with process.env.SECRET + +BEEMINDER_CLIENT_ID='REPLACEMEwithActualIDGeneratedByBeeminder' +AUTH_REDIRECT_URI='https://REPLACEMEwithProjectName.glitch.me/connect' +SESSION_SECRET='REPLACEMEwithFreshlyGeneratedUUIDorOtherUniqueUnguessableString' + +# Leave these unmodified unless you know what you're doing +DB_USER='' +DB_PASS='' + +# NB: .env is a shell file so there can't be spaces around '=' + +# Only the non-secret version of this file -- template.prod.env -- is in version +# control. And on Glitch, for example, only invited collaborators can see the +# secret .env version. + +# SETUP INSTRUCTIONS ----------------------------------------------------------- +# 0. This only has to be done once or when moving where this is hosted +# 1. Copy this file (template.prod.env) to .env and follow the remaining steps there +# 2. Log into your personal Beeminder account +# 3. Go to beeminder.com/apps and click Register A New App +# 4. Put "Beebrain Graph Editor" or similar as the application name +# 5. Put https://graph.beeminder.com/connect as the Redirect URL +# (This used to be road.beeminder.com and could change again. We can also +# make any number of clones like graph-staging42.glitch.me and just add +# /connect to that to make the Redirect URL.) +# 6. Also fill that URL in here as the AUTH_REDIRECT_URI config variable +# 7. Leave the Callback URLs blank in the Beeminder form +# 8. Click the Register button to register the app +# 9. Beeminder generates and shows you the Client ID and Client Secret +# 10. Copy the Client ID to the BEEMINDER_CLIENT_ID config variable here +# 11. Make up a UUID (long random string) for the SESSION_SECRET config variable +# 12. Grep "REPLACEME" to ensure the only instance is the one in this sentence! +# +# To review, you've now copied this template.prod.env file to .env and filled in all +# the values for the config variables and ensured that the template.env version +# remains the master copy. This is confusing to the uninitiated! +# ------------------------------------------------------------------------------