diff --git a/package.json b/package.json index 4e7830d..3503435 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "lerna": "^3.14.1" }, "scripts": { - "db:setup": "lerna run db:setup --scope '*/*-server' --stream", + "db:setup": "lerna run db:setup --scope '*/*-shared' --stream", "build": "lerna run --stream build", "build:shared": "yarn run --scope '*/*-shared' build", "start:app": "lerna run --scope '*/*-app' --stream start", diff --git a/packages/server/package.json b/packages/server/package.json index e218e25..09ff487 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -14,7 +14,7 @@ "start:dev": "yarn db:setup && nodemon --ignore ./build --exec babel-node ./src/index.js", "knex": "npx babel-node ./node_modules/.bin/knex", "test": "npx mocha test --recursive --exit --require @babel/register", - "db:setup": "./scripts/db-setup.sh" + "db:setup": "lerna run db:setup --scope '*/*-shared' --stream" }, "dependencies": { "@aragon/protocol-backend-shared": "^0.2.21", @@ -31,12 +31,7 @@ "express-session": "^1.17.0", "helmet": "^3.21.2", "http-status-codes": "^1.4.0", - "jsonwebtoken": "^8.5.1", - "knex": "^0.21.0", "morgan": "^1.9.1", - "objection": "^2.1.3", - "pg": "^7.18.2", - "pg-hstore": "^2.3.3", "postmark": "^2.5.3", "prom-client": "^11.5.3", "regenerator-runtime": "^0.13.3", diff --git a/packages/server/scripts/db-setup.sh b/packages/server/scripts/db-setup.sh deleted file mode 100755 index 8623538..0000000 --- a/packages/server/scripts/db-setup.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -# Wait for connection before Knex migrations -db_result=0 -while [ "${db_result}" -ne "1" ]; do - npm run knex -- migrate:currentVersion 2>&1 | grep 'connect ECONNREFUSED' > /dev/null - db_result=$? - if [ "${db_result}" -eq "0" ]; then - echo "Waiting for DB..." - sleep 5 - fi -done - -echo "Running knex database migrations..." -npm run knex -- migrate:latest -if [ "$?" -ne "0" ]; then - exit 1 -fi - -echo "Running knex seeds..." -npm run knex -- seed:run -if [ "$?" -ne "0" ]; then - exit 1 -fi - -echo "Database is ready!" diff --git a/packages/server/scripts/notify-appeals-confirm.js b/packages/server/scripts/notify-appeals-confirm.js deleted file mode 100755 index 67e175d..0000000 --- a/packages/server/scripts/notify-appeals-confirm.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Usage: npx babel-node scripts/notify-appeals-confirm - * requires .env file / env vars with - * DB_NAME= - * DB_USER= - * DB_PASS= - * DB_PORT= - * DB_HOST= - * POSTMARK_SERVER_API_TOKEN= - */ -import { User } from '../src/models/objection' -import emailClient from '@aragon/protocol-backend-shared/helpers/email-client' -import dotenv from 'dotenv' -import { accountData } from '../../../emails/helpers' -dotenv.config() - -async function main() { - const users = await User.findWithoutDisabledNotifications() - const emails = new Set() - for (const user of users) { - const { email: { email }, address } = user - if (emails.has(email.toLowerCase())) continue - emails.add(email.toLowerCase()) - try { - await emailClient.sendEmailWithTemplate({ - To: email, - From: 'notifications@protocol.aragon.org', - TemplateAlias: 'appeals-confirm', - TemplateModel: { - subject: 'Aragon Court Dispute #20 and Dispute #21 have been APPEALED.', - ...accountData(address), - date: 'Tuesday, 8 Sep. 2020' - }, - }) - } catch (err) { - console.log(err.message) - } - console.log(`sent email to ${email} for address ${address}`) - } - console.log(`Total emails: ${emails.size}`) - process.exit(0) -} - -main().catch((error) => { - console.error(error) - process.exit(1) -}) diff --git a/packages/server/scripts/notify-fee-mechanism-upgrade.js b/packages/server/scripts/notify-fee-mechanism-upgrade.js deleted file mode 100755 index 13ead1e..0000000 --- a/packages/server/scripts/notify-fee-mechanism-upgrade.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Usage: npx babel-node scripts/notify-fee-mechanism-upgrade - * requires .env file / env vars with - * DB_NAME= - * DB_USER= - * DB_PASS= - * DB_PORT= - * DB_HOST= - * POSTMARK_SERVER_API_TOKEN= - */ -import { User } from '../src/models/objection' -import emailClient from '@aragon/protocol-backend-shared/helpers/email-client' -import dotenv from 'dotenv' -import { trimMultiline } from '../../../emails/template-utils' -dotenv.config() - -async function main() { - const users = await User.findWithoutDisabledNotifications() - const emails = new Set() - for (const user of users) { - const { email: { email }, address } = user - if (emails.has(email.toLowerCase())) continue - emails.add(email.toLowerCase()) - try { - await emailClient.sendEmailWithTemplate({ - To: email, - From: 'notifications@protocol.aragon.org', - TemplateAlias: 'generic', - TemplateModel: { - actionLabel: 'Go to the Aragon Forum Post', - actionUrl: 'https://forum.aragon.org/t/request-for-comment-proposal-to-adjust-the-court-subscription-fee-mechanism/2163', - title: 'Proposal to adjust the Court Subscription Fee Mechanism', - bannerHtml: '', - contentHtml: ` -

- A proposal has been made to adjust the Court Subscription Fee Mechanism. - The author is requesting comments for their proposal from Aragon community. - You can read the proposal and leave comments on the forum post here: -

- `, - content: trimMultiline(` - A proposal has been made to adjust the Court Subscription Fee Mechanism. - The author is requesting comments for their proposal from Aragon community. - You can read the proposal and leave comments on the forum post here: - `), - }, - }) - } catch (err) { - console.log(err.message) - } - console.log(`sent email to ${email} for address ${address}`) - } - console.log(`Total emails: ${emails.size}`) - process.exit(0) -} - -main().catch((error) => { - console.error(error) - process.exit(1) -}) diff --git a/packages/server/scripts/notify-unverified-anj-registrations.js b/packages/server/scripts/notify-unverified-anj-registrations.js deleted file mode 100755 index d643b8b..0000000 --- a/packages/server/scripts/notify-unverified-anj-registrations.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Usage: npx babel-node scripts/notify-unverified-anj-registrations - * requires .env file / env vars with - * DB_NAME= - * DB_USER= - * DB_PASS= - * DB_PORT= - * DB_HOST= - * POSTMARK_SERVER_API_TOKEN= - */ -import { User } from '../src/models/objection' -import emailClient from '@aragon/protocol-backend-shared/helpers/email-client' -import dotenv from 'dotenv' -dotenv.config() - -async function main() { - const users = await User.findUnverifiedAnjRegistrations() - const emails = new Set() - for (const user of users) { - const { email: { email }, address } = user - if (emails.has(email.toLowerCase())) continue - emails.add(email.toLowerCase()) - try { - await emailClient.sendEmailWithTemplate({ - To: email, - From: 'notifications@protocol.aragon.org', - TemplateAlias: 'notification-settings-announcement', - TemplateModel: { - dashboardUrl: 'https://protocol.aragon.org/dashboard', - }, - }) - } catch (err) { - console.log(err.message) - } - console.log(`sent email to ${email} for address ${address}`) - } - console.log(`Total emails: ${emails.size}`) - process.exit(0) -} - -main().catch((error) => { - console.error(error) - process.exit(1) -}) diff --git a/packages/server/src/controllers/AdminsController.js b/packages/server/src/controllers/AdminsController.js index a0bd547..7ab5010 100644 --- a/packages/server/src/controllers/AdminsController.js +++ b/packages/server/src/controllers/AdminsController.js @@ -1,4 +1,4 @@ -import { Admin } from '../models/objection' +import { Admin } from '@aragon/protocol-backend-shared/build/models/objection' import HttpError from '../errors/http-error' import AdminValidator from '../validators/AdminValidator' diff --git a/packages/server/src/controllers/EmailsController.js b/packages/server/src/controllers/EmailsController.js index 0bd4811..cef2525 100644 --- a/packages/server/src/controllers/EmailsController.js +++ b/packages/server/src/controllers/EmailsController.js @@ -1,6 +1,6 @@ -import { User } from '../models/objection' -import emailClient from '@aragon/protocol-backend-shared/helpers/email-client' -import sleep from '@aragon/protocol-backend-shared/helpers/sleep' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' +import emailClient from '@aragon/protocol-backend-shared/build/helpers/email-client' +import sleep from '@aragon/protocol-backend-shared/build/helpers/sleep' export default { async send(req, res) { @@ -40,7 +40,7 @@ async function sendEmails(users, TemplateModel, res) { } } console.log(`Total emails: ${emails.size}`) - await sleep(0.1) // sleep to make sure Total emails is in the next chunk + await sleep(100) // sleep to make sure Total emails is in the next chunk res.write(`Total emails: ${emails.size}`) res.end() } diff --git a/packages/server/src/controllers/RevealsController.js b/packages/server/src/controllers/RevealsController.js index abec252..4c439d7 100644 --- a/packages/server/src/controllers/RevealsController.js +++ b/packages/server/src/controllers/RevealsController.js @@ -1,4 +1,4 @@ -import { Reveal } from '../models/objection' +import { Reveal } from '@aragon/protocol-backend-shared/build/models/objection' import HttpError from '../errors/http-error' import RevealsValidator from '../validators/RevealsValidator' import { decodeVoteId } from '@aragon/protocol-backend-shared/helpers/voting' diff --git a/packages/server/src/controllers/UserEmailController.js b/packages/server/src/controllers/UserEmailController.js index fe66975..5e7682b 100644 --- a/packages/server/src/controllers/UserEmailController.js +++ b/packages/server/src/controllers/UserEmailController.js @@ -1,7 +1,7 @@ import HttpError from '../errors/http-error' import UsersValidator from '../validators/UsersValidator' import UserEmailVerificationTokenValidator from '../validators/UserEmailVerificationTokenValidator' -import { User } from '../models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' export default { async get(req, res) { diff --git a/packages/server/src/controllers/UserNotificationsController.js b/packages/server/src/controllers/UserNotificationsController.js index 10c1c9d..c012b2e 100644 --- a/packages/server/src/controllers/UserNotificationsController.js +++ b/packages/server/src/controllers/UserNotificationsController.js @@ -1,5 +1,5 @@ import HttpError from '../errors/http-error' -import { User } from '../models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' export default { async set(req, res) { diff --git a/packages/server/src/controllers/UserSessionsController.js b/packages/server/src/controllers/UserSessionsController.js index ff8a59b..94c7be8 100644 --- a/packages/server/src/controllers/UserSessionsController.js +++ b/packages/server/src/controllers/UserSessionsController.js @@ -1,6 +1,6 @@ import HttpError from '../errors/http-error' import UserSessionsValidator from '../validators/UserSessionsValidator' -import { User } from '../models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' export default { async create(req, res) { diff --git a/packages/server/src/controllers/UsersController.js b/packages/server/src/controllers/UsersController.js index 59a1c3d..7a6df0d 100644 --- a/packages/server/src/controllers/UsersController.js +++ b/packages/server/src/controllers/UsersController.js @@ -1,6 +1,6 @@ import HttpError from '../errors/http-error' import UsersValidator from '../validators/UsersValidator' -import { User, UserEmail } from '../models/objection' +import { User, UserEmail } from '@aragon/protocol-backend-shared/build/models/objection' export default { async details(req, res) { diff --git a/packages/server/src/database/migrations/20200425004131_create-emails.js b/packages/server/src/database/migrations/20200425004131_create-emails.js deleted file mode 100644 index 5161a85..0000000 --- a/packages/server/src/database/migrations/20200425004131_create-emails.js +++ /dev/null @@ -1,21 +0,0 @@ -export function up(knex) { - return knex.schema.hasTable('Users').then(function(sequelizeExists) { - if (sequelizeExists) { - return knex.schema.renameTable('Users', 'UserEmails').alterTable('UserEmails', function (table) { - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable().alter() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable().alter() - }) - } else { - return knex.schema.createTable('UserEmails', function (table) { - table.increments('id') - table.string('email').unique().notNullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() - }) - } - }) -} - -export function down(knex) { - return knex.schema.dropTable('UserEmails') -} diff --git a/packages/server/src/database/migrations/20200425004137_create-users.js b/packages/server/src/database/migrations/20200425004137_create-users.js deleted file mode 100644 index 11f3b9b..0000000 --- a/packages/server/src/database/migrations/20200425004137_create-users.js +++ /dev/null @@ -1,31 +0,0 @@ -export function up(knex) { - return knex.schema.hasTable('UserAddresses').then(function(sequelizeExists) { - if (sequelizeExists) { - return knex.schema.renameTable('UserAddresses', 'Users').alterTable('Users', function (table) { - table.boolean('addressVerified').defaultTo(false).notNullable() - table.renameColumn('userId', 'userEmailId') - table.index('userEmailId') - table.dropForeign('userEmailId', 'UserAddresses_userId_fkey') // need to recreate constraint with set null on delete - table.foreign('userEmailId').references('UserEmails.id').onDelete('SET NULL') - table.boolean('emailVerified').defaultTo(false).notNullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable().alter() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable().alter() - }) - } else { - return knex.schema.createTable('Users', function (table) { - table.increments('id') - table.string('address').unique().notNullable() - table.boolean('addressVerified').defaultTo(false).notNullable() - table.integer('userEmailId').index() - table.foreign('userEmailId').references('UserEmails.id').onDelete('SET NULL') - table.boolean('emailVerified').defaultTo(false).notNullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() - }) - } - }) -} - -export function down(knex) { - return knex.schema.dropTable('Users') -} diff --git a/packages/server/src/database/migrations/20200425004140_create-admins.js b/packages/server/src/database/migrations/20200425004140_create-admins.js deleted file mode 100644 index 295dc08..0000000 --- a/packages/server/src/database/migrations/20200425004140_create-admins.js +++ /dev/null @@ -1,22 +0,0 @@ -export function up(knex) { - return knex.schema.hasTable('Admins').then(function(sequelizeExists) { - if (sequelizeExists) { - return knex.schema.alterTable('Admins', function (table) { - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable().alter() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable().alter() - }) - } else { - return knex.schema.createTable('Admins', function (table) { - table.increments('id') - table.string('email').unique().notNullable() - table.string('password').notNullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() - }) - } - }) -} - -export function down(knex) { - return knex.schema.dropTable('Admins') -} diff --git a/packages/server/src/database/migrations/20200428185153_create-reveals.js b/packages/server/src/database/migrations/20200428185153_create-reveals.js deleted file mode 100644 index 8f6a800..0000000 --- a/packages/server/src/database/migrations/20200428185153_create-reveals.js +++ /dev/null @@ -1,29 +0,0 @@ -export function up(knex) { - return knex.schema.hasTable('Reveals').then(function(sequelizeExists) { - if (sequelizeExists) { - return knex.schema.alterTable('Reveals', function (table) { - table.boolean('revealed').defaultTo(false).notNullable().alter() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable().alter() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable().alter() - }) - } else { - return knex.schema.createTable('Reveals', function (table) { - table.increments('id') - table.string('voteId').notNullable() - table.string('guardian').notNullable() - table.unique(['guardian', 'voteId']) - table.string('disputeId').notNullable() - table.integer('roundNumber').notNullable() - table.integer('outcome').notNullable() - table.string('salt').notNullable() - table.boolean('revealed').defaultTo(false).notNullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() - }) - } - }) -} - -export function down(knex) { - return knex.schema.dropTable('Reveals') -} diff --git a/packages/server/src/database/migrations/20200504162940_create-keeper-suspicious-transactions.js b/packages/server/src/database/migrations/20200504162940_create-keeper-suspicious-transactions.js deleted file mode 100644 index 77e1e2b..0000000 --- a/packages/server/src/database/migrations/20200504162940_create-keeper-suspicious-transactions.js +++ /dev/null @@ -1,22 +0,0 @@ -export function up(knex) { - return knex.schema.hasTable('KeeperSuspiciousTransactions').then(function(sequelizeExists) { - if (sequelizeExists) { - return knex.schema.alterTable('KeeperSuspiciousTransactions', function (table) { - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable().alter() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable().alter() - }) - } else { - return knex.schema.createTable('KeeperSuspiciousTransactions', function (table) { - table.increments('id') - table.string('blockNumber').unique().notNullable() - table.string('txHash').unique().nullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() - }) - } - }) -} - -export function down(knex) { - return knex.schema.dropTable('KeeperSuspiciousTransactions') -} diff --git a/packages/server/src/database/migrations/20200509004243_create-notification-types.js b/packages/server/src/database/migrations/20200509004243_create-notification-types.js deleted file mode 100644 index de82292..0000000 --- a/packages/server/src/database/migrations/20200509004243_create-notification-types.js +++ /dev/null @@ -1,13 +0,0 @@ -export function up(knex) { - return knex.schema.createTable('UserNotificationTypes', function (table) { - table.increments('id') - table.string('model').unique().notNullable() - table.datetime('scannedAt').index() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() - }) -} - -export function down(knex) { - return knex.schema.dropTable('UserNotificationTypes') -} diff --git a/packages/server/src/database/migrations/20200605140156_add-reveals-tries.js b/packages/server/src/database/migrations/20200605140156_add-reveals-tries.js deleted file mode 100644 index 8cf9cb9..0000000 --- a/packages/server/src/database/migrations/20200605140156_add-reveals-tries.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(knex) { - return knex.schema.alterTable('Reveals', function (table) { - table.integer('failedAttempts').notNullable().defaultTo(0) - }) -} - -export function down(knex) { - return knex.schema.alterTable('Reveals', function (table) { - table.dropColumn('failedAttempts') - }) -} diff --git a/packages/server/src/database/migrations/20200903114032_add-reveals-expired.js b/packages/server/src/database/migrations/20200903114032_add-reveals-expired.js deleted file mode 100644 index 16d4c0e..0000000 --- a/packages/server/src/database/migrations/20200903114032_add-reveals-expired.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(knex) { - return knex.schema.alterTable('Reveals', function (table) { - table.boolean('expired').notNullable().defaultTo(false) - }) -} - -export function down(knex) { - return knex.schema.alterTable('Reveals', function (table) { - table.dropColumn('expired') - }) -} diff --git a/packages/server/src/helpers/session-middleware.js b/packages/server/src/helpers/session-middleware.js index 294e578..150d2a1 100644 --- a/packages/server/src/helpers/session-middleware.js +++ b/packages/server/src/helpers/session-middleware.js @@ -1,5 +1,5 @@ import expressSession from 'express-session' -import { Session } from '../models/objection' +import { Session } from '@aragon/protocol-backend-shared/build/models/objection' import { HOURS, DAYS } from '@aragon/protocol-backend-shared/build/helpers/times' const SESSION_MAXAGE = 30 * DAYS diff --git a/packages/server/src/helpers/token-manager.js b/packages/server/src/helpers/token-manager.js deleted file mode 100644 index 7f6319b..0000000 --- a/packages/server/src/helpers/token-manager.js +++ /dev/null @@ -1,21 +0,0 @@ -import jwt from 'jsonwebtoken' - -const { env: { - EMAIL_JWT_PRIVATE_KEY, -}} = process - -function generateToken(expiresIn = '24h') { - const payload = { timestamp: Date.now() } - return jwt.sign(payload, EMAIL_JWT_PRIVATE_KEY, { expiresIn }) -} - -function isTokenValid(token) { - try { - jwt.verify(token, EMAIL_JWT_PRIVATE_KEY) - return true - } catch { - return false - } -} - -export { generateToken, isTokenValid } diff --git a/packages/server/src/models/objection/Admin.js b/packages/server/src/models/objection/Admin.js deleted file mode 100644 index e5551a7..0000000 --- a/packages/server/src/models/objection/Admin.js +++ /dev/null @@ -1,52 +0,0 @@ -import bcrypt from 'bcryptjs' -import BaseModel from './BaseModel' - -export default class Admin extends BaseModel { - static get tableName() { - return 'Admins' - } - - static get relationMappings() { - return { - sessions: { - relation: BaseModel.HasManyRelation, - modelClass: 'Session', - join: { - from: 'Admins.id', - to: 'Sessions.adminId' - } - } - } - } - - static async countByEmail(email) { - return this.query().where({ email }).count() - } - - static async findByEmail(email) { - return this.findOne({ email }) - } - - static async findAllEmails() { - const admins = await this.query().select('email') - return admins.map(admin => admin.email) - } - - hasPassword(password) { - return bcrypt.compareSync(password, this.password) - } - - hashPassword() { - this.password = bcrypt.hashSync(this.password) - } - - async $beforeInsert(queryContext) { - await super.$beforeInsert(queryContext) - this.hashPassword() - } - - async $beforeUpdate(opt, queryContext) { - await super.$beforeUpdate(opt, queryContext) - this.hashPassword() - } -} diff --git a/packages/server/src/models/objection/BaseModel.js b/packages/server/src/models/objection/BaseModel.js deleted file mode 100644 index 06ea81d..0000000 --- a/packages/server/src/models/objection/BaseModel.js +++ /dev/null @@ -1,62 +0,0 @@ -import { Model } from 'objection' -import Knex from 'knex' - -import config from '../../database/config' -Model.knex(Knex(config)) - -export default class BaseModel extends Model { - // modelPaths is used to allow modelClass relations be defined as a string to avoid require loops - // https://vincit.github.io/objection.js/guide/relations.html#require-loops - static get modelPaths() { - return [__dirname]; - } - // every child model should have updatedAt datetime field - $beforeUpdate() { - this.updatedAt = new Date().toISOString() - } - - - // static query methods (table level) - - static async exists(args) { - return !!(await this.findOne(args)) - } - - static count(args) { - return this.query().where(args).resultSize() - } - - static findById(id) { - return this.query().findById(id) - } - - static findOne(args) { - return this.query().findOne(args) - } - - static async findOrInsert(args) { - let row = await this.findOne(args) - if (!row) row = await this.create(args) - return row - } - - static create(args = {}) { - return this.query().insert(args) - } - - - // instance query methods (row level) - - async relatedUpdateOrInsert(relation, args) { - const row = await this.$relatedQuery(relation) - if (row) { - await this.$relatedQuery(relation).update(args) - } else { - await this.$relatedQuery(relation).insert(args) - } - } - - get createdAtDateString() { - return this.createdAt.toLocaleDateString('en-US', {dateStyle: 'full'}) // format: Tuesday, May 19, 2020 - } -} diff --git a/packages/server/src/models/objection/Reveal.js b/packages/server/src/models/objection/Reveal.js deleted file mode 100644 index e10426e..0000000 --- a/packages/server/src/models/objection/Reveal.js +++ /dev/null @@ -1,11 +0,0 @@ -import BaseModel from './BaseModel' - -export default class Reveal extends BaseModel { - static get tableName() { - return 'Reveals' - } - - static async create(params = {}) { - return this.query().insert(params) - } -} diff --git a/packages/server/src/models/objection/index.js b/packages/server/src/models/objection/index.js deleted file mode 100644 index 902f22a..0000000 --- a/packages/server/src/models/objection/index.js +++ /dev/null @@ -1,23 +0,0 @@ -import Admin from './Admin' -import KeeperSuspiciousTransaction from './KeeperSuspiciousTransaction' -import Reveal from './Reveal' -import Session from './Session' -import UserEmail from './UserEmail' -import UserEmailVerificationToken from './UserEmailVerificationToken' -import UserNotificationSetting from './UserNotificationSetting' -import UserNotification from './UserNotification' -import UserNotificationType from './UserNotificationType' -import User from './User' - -export { - Admin, - KeeperSuspiciousTransaction, - Reveal, - Session, - UserEmail, - UserEmailVerificationToken, - UserNotificationSetting, - UserNotification, - UserNotificationType, - User, -} diff --git a/packages/server/src/routes/authenticate-admin.js b/packages/server/src/routes/authenticate-admin.js index de9e7a7..a668f58 100644 --- a/packages/server/src/routes/authenticate-admin.js +++ b/packages/server/src/routes/authenticate-admin.js @@ -1,4 +1,4 @@ -import { Admin } from '../models/objection' +import { Admin } from '@aragon/protocol-backend-shared/build/models/objection' import HttpError from '../errors/http-error' import asyncMiddleware from '../helpers/async-middleware' diff --git a/packages/server/src/routes/authenticate-user.js b/packages/server/src/routes/authenticate-user.js index f5a7139..3187037 100644 --- a/packages/server/src/routes/authenticate-user.js +++ b/packages/server/src/routes/authenticate-user.js @@ -1,6 +1,6 @@ import HttpError from '../errors/http-error' import asyncMiddleware from '../helpers/async-middleware' -import { User } from '../models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' const authenticate = (route) => async (req, res, next) => { const { session: { userId }, params: { address } } = req diff --git a/packages/server/src/validators/AdminValidator.js b/packages/server/src/validators/AdminValidator.js index 6f35a0c..3905030 100644 --- a/packages/server/src/validators/AdminValidator.js +++ b/packages/server/src/validators/AdminValidator.js @@ -1,4 +1,4 @@ -import { Admin } from '../models/objection' +import { Admin } from '@aragon/protocol-backend-shared/build/models/objection' import BaseValidator from './BaseValidator' class AdminValidator extends BaseValidator { diff --git a/packages/server/src/validators/RevealsValidator.js b/packages/server/src/validators/RevealsValidator.js index fa169c7..837739a 100644 --- a/packages/server/src/validators/RevealsValidator.js +++ b/packages/server/src/validators/RevealsValidator.js @@ -1,4 +1,4 @@ -import { Reveal } from '../models/objection' +import { Reveal } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '../web3/Network' import BaseValidator from './BaseValidator' const { hashVote } = require('@aragon/protocol-backend-shared/helpers/voting') diff --git a/packages/server/src/validators/UserEmailVerificationTokenValidator.js b/packages/server/src/validators/UserEmailVerificationTokenValidator.js index 4ca1e6e..61a9352 100644 --- a/packages/server/src/validators/UserEmailVerificationTokenValidator.js +++ b/packages/server/src/validators/UserEmailVerificationTokenValidator.js @@ -1,6 +1,6 @@ import BaseValidator from './BaseValidator' -import { User } from '../models/objection' -import { isTokenValid } from '../helpers/token-manager' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' +import { isTokenValid } from '@aragon/protocol-backend-shared/build/helpers/jwt-manager' class UserEmailVerificationTokenValidator extends BaseValidator { async validateForVerify({ address, token }) { diff --git a/packages/server/src/validators/UsersValidator.js b/packages/server/src/validators/UsersValidator.js index 0f16f52..90f0826 100644 --- a/packages/server/src/validators/UsersValidator.js +++ b/packages/server/src/validators/UsersValidator.js @@ -1,7 +1,7 @@ import validator from 'validator' import BaseValidator from './BaseValidator' -import { User } from '../models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' class UsersValidator extends BaseValidator { async validateForCreate({ address, email }) { diff --git a/packages/server/test/helpers/dbCleanup.js b/packages/server/test/helpers/dbCleanup.js index eabe8d2..f40dd76 100644 --- a/packages/server/test/helpers/dbCleanup.js +++ b/packages/server/test/helpers/dbCleanup.js @@ -1,4 +1,4 @@ -import { User } from '../../src/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' export default async function dbCleanup(address) { const user = await User.findOne({address}) diff --git a/packages/server/test/integration/user-client-interaction.js b/packages/server/test/integration/user-client-interaction.js index 714864d..f0fef92 100644 --- a/packages/server/test/integration/user-client-interaction.js +++ b/packages/server/test/integration/user-client-interaction.js @@ -4,7 +4,7 @@ import HttpStatus from 'http-status-codes' import { ethers } from 'ethers' import app from '../../src/app' -import { User } from '../../src/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' import dbCleanup from '../helpers/dbCleanup' const serverPort = process.env.SERVER_PORT || 8000 const { expect } = chai diff --git a/packages/services/bin/worker.js b/packages/services/bin/worker.js index c3c2f10..fbe5481 100644 --- a/packages/services/bin/worker.js +++ b/packages/services/bin/worker.js @@ -4,7 +4,7 @@ import path from 'path' import Logger from '../src/helpers/worker-logger' import MetricsReporter from '../src/helpers/metrics-reporter' import errorHandler from '../src/helpers/error-handler' -import sleep from '@aragon/protocol-backend-shared/helpers/sleep' +import sleep from '@aragon/protocol-backend-shared/build/helpers/sleep' let [workerPath, name, times, repeat, color, metricsPort] = process.argv.slice(2) if (!workerPath) throw Error('Cannot start worker with missing path') @@ -36,7 +36,7 @@ async function run() { metrics.workerError() logger.error(`Job #${job} exited with an error`, error) } - await sleep(repeat) + await sleep(repeat * 1000) } logger.success(`Worker finished`) } diff --git a/packages/services/package.json b/packages/services/package.json index acf78b8..d699296 100644 --- a/packages/services/package.json +++ b/packages/services/package.json @@ -10,7 +10,8 @@ "build:server": "yarn workspace @aragon/protocol-backend-server build", "start": "npm run build:server && babel-node ./bin/main.js", "start:dev": "npm run build:server && nodemon --ignore ./build --exec babel-node ./bin/main.js", - "test": "npx mocha test --recursive --exit --require @babel/register" + "test": "npx mocha test --recursive --exit --require @babel/register", + "db:setup": "lerna run db:setup --scope '*/*-shared' --stream" }, "dependencies": { "@aragon/protocol-backend-server": "^0.2.21", diff --git a/packages/services/src/models/notification-scanners/SubscriptionReminder.js b/packages/services/src/models/notification-scanners/SubscriptionReminder.js index dd25122..5489f2e 100644 --- a/packages/services/src/models/notification-scanners/SubscriptionReminder.js +++ b/packages/services/src/models/notification-scanners/SubscriptionReminder.js @@ -1,5 +1,5 @@ import NotificationScannerBaseModel from './NotificationScannerBaseModel' -import { User } from '@aragon/protocol-backend-server/build/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' class SubscriptionReminder extends NotificationScannerBaseModel { async scan() { diff --git a/packages/services/src/workers/heartbeat.js b/packages/services/src/workers/heartbeat.js index 87c8f0e..383927a 100644 --- a/packages/services/src/workers/heartbeat.js +++ b/packages/services/src/workers/heartbeat.js @@ -1,4 +1,4 @@ -import sleep from '@aragon/protocol-backend-shared/helpers/sleep' +import sleep from '@aragon/protocol-backend-shared/build/helpers/sleep' import Network from '@aragon/protocol-backend-server/build/web3/Network' const HEARTBEAT_TRIES_PER_JOB = 3 @@ -19,7 +19,7 @@ async function heartbeat(logger, protocol, attempt = 1) { } catch (error) { logger.error('Failed to transition terms with error', error) if (attempt >= HEARTBEAT_TRIES_PER_JOB) return - await sleep(SECONDS_BETWEEN_INTENTS) + await sleep(SECONDS_BETWEEN_INTENTS * 1000) await heartbeat(logger, protocol, attempt + 1) } } diff --git a/packages/services/src/workers/monitor-keeper.js b/packages/services/src/workers/monitor-keeper.js index a7bd7fb..ecb5364 100644 --- a/packages/services/src/workers/monitor-keeper.js +++ b/packages/services/src/workers/monitor-keeper.js @@ -1,7 +1,7 @@ -import emailClient from '@aragon/protocol-backend-shared/helpers/email-client' +import emailClient from '@aragon/protocol-backend-shared/build/helpers/email-client' import Etherscan from '../models/Etherscan' import Network from '@aragon/protocol-backend-server/build/web3/Network' -import { Admin, KeeperSuspiciousTransaction } from '@aragon/protocol-backend-server/build/models/objection' +import { Admin, KeeperSuspiciousTransaction } from '@aragon/protocol-backend-shared/build/models/objection' import { fromWei } from 'web3-utils' import { bigExp } from '@aragon/protocol-backend-shared/helpers/numbers' diff --git a/packages/services/src/workers/notification-scanner.js b/packages/services/src/workers/notification-scanner.js index 68d5ba9..6bd441c 100644 --- a/packages/services/src/workers/notification-scanner.js +++ b/packages/services/src/workers/notification-scanner.js @@ -1,4 +1,4 @@ -import { User, UserNotification, UserNotificationType } from '@aragon/protocol-backend-server/build/models/objection' +import { User, UserNotification, UserNotificationType } from '@aragon/protocol-backend-shared/build/models/objection' import * as notificationScanners from '../models/notification-scanners' /** diff --git a/packages/services/src/workers/notification-sender.js b/packages/services/src/workers/notification-sender.js index 7d87637..f39789c 100644 --- a/packages/services/src/workers/notification-sender.js +++ b/packages/services/src/workers/notification-sender.js @@ -1,5 +1,5 @@ -import emailClient from '@aragon/protocol-backend-shared/helpers/email-client' -import { UserNotification } from '@aragon/protocol-backend-server/build/models/objection' +import emailClient from '@aragon/protocol-backend-shared/build/helpers/email-client' +import { UserNotification } from '@aragon/protocol-backend-shared/build/models/objection' import * as notificationScanners from '../models/notification-scanners' import { accountData } from '../../../../emails/helpers' diff --git a/packages/services/src/workers/reveal.js b/packages/services/src/workers/reveal.js index 6564c36..5ad7921 100644 --- a/packages/services/src/workers/reveal.js +++ b/packages/services/src/workers/reveal.js @@ -1,4 +1,4 @@ -import { Reveal } from '@aragon/protocol-backend-server/build/models/objection' +import { Reveal } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '@aragon/protocol-backend-server/build/web3/Network' const REVEAL_TRIES = 3 diff --git a/packages/services/test/helpers/dbCleanup.js b/packages/services/test/helpers/dbCleanup.js index 9ce9976..3745395 100644 --- a/packages/services/test/helpers/dbCleanup.js +++ b/packages/services/test/helpers/dbCleanup.js @@ -1,4 +1,4 @@ -import { User, UserEmail, UserNotificationType } from '@aragon/protocol-backend-server/build/models/objection' +import { User, UserEmail, UserNotificationType } from '@aragon/protocol-backend-shared/build/models/objection' export async function userDbCleanup(address, email) { await UserEmail.findOne({email}).del() diff --git a/packages/services/test/helpers/userNotificationTypeByModel.js b/packages/services/test/helpers/userNotificationTypeByModel.js index 34aac37..b83d0e6 100644 --- a/packages/services/test/helpers/userNotificationTypeByModel.js +++ b/packages/services/test/helpers/userNotificationTypeByModel.js @@ -1,4 +1,4 @@ -import { UserNotificationType } from '@aragon/protocol-backend-server/build/models/objection' +import { UserNotificationType } from '@aragon/protocol-backend-shared/build/models/objection' export default function userNotificationTypeByModel(model) { return UserNotificationType.findOne({model}).withGraphFetched('notifications') diff --git a/packages/services/test/integration/notification-scanners/AppealsOpened.js b/packages/services/test/integration/notification-scanners/AppealsOpened.js index a0e0407..03c2398 100644 --- a/packages/services/test/integration/notification-scanners/AppealsOpened.js +++ b/packages/services/test/integration/notification-scanners/AppealsOpened.js @@ -7,7 +7,7 @@ chai.use(sinonChai) import { userDbCleanup, userNotificationTypeDbCleanup } from '../../helpers/dbCleanup' import userNotificationTypeByModel from '../../helpers/userNotificationTypeByModel' import { tryRunScanner } from '../../../src/workers/notification-scanner' -import { User } from '@aragon/protocol-backend-server/build/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '@aragon/protocol-backend-server/build/web3/Network' import * as termIdGetter from '../../../src/helpers/term-id-getter' diff --git a/packages/services/test/integration/notification-scanners/DisputeRuled.js b/packages/services/test/integration/notification-scanners/DisputeRuled.js index 73ecb4e..dda8cae 100644 --- a/packages/services/test/integration/notification-scanners/DisputeRuled.js +++ b/packages/services/test/integration/notification-scanners/DisputeRuled.js @@ -7,7 +7,7 @@ chai.use(sinonChai) import { userDbCleanup, userNotificationTypeDbCleanup } from '../../helpers/dbCleanup' import userNotificationTypeByModel from '../../helpers/userNotificationTypeByModel' import { tryRunScanner } from '../../../src/workers/notification-scanner' -import { User } from '@aragon/protocol-backend-server/build/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '@aragon/protocol-backend-server/build/web3/Network' const { env: { CLIENT_URL } } = process diff --git a/packages/services/test/integration/notification-scanners/DueTasks.js b/packages/services/test/integration/notification-scanners/DueTasks.js index d58cf8a..bd656fd 100644 --- a/packages/services/test/integration/notification-scanners/DueTasks.js +++ b/packages/services/test/integration/notification-scanners/DueTasks.js @@ -7,7 +7,7 @@ chai.use(sinonChai) import { userDbCleanup, userNotificationTypeDbCleanup } from '../../helpers/dbCleanup' import userNotificationTypeByModel from '../../helpers/userNotificationTypeByModel' import { tryRunScanner } from '../../../src/workers/notification-scanner' -import { User } from '@aragon/protocol-backend-server/build/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '@aragon/protocol-backend-server/build/web3/Network' import * as termIdGetter from '../../../src/helpers/term-id-getter' diff --git a/packages/services/test/integration/notification-scanners/JurorDrafted.js b/packages/services/test/integration/notification-scanners/JurorDrafted.js index fcf9b1c..492e9fb 100644 --- a/packages/services/test/integration/notification-scanners/JurorDrafted.js +++ b/packages/services/test/integration/notification-scanners/JurorDrafted.js @@ -7,7 +7,7 @@ chai.use(sinonChai) import { userDbCleanup, userNotificationTypeDbCleanup } from '../../helpers/dbCleanup' import userNotificationTypeByModel from '../../helpers/userNotificationTypeByModel' import { tryRunScanner } from '../../../src/workers/notification-scanner' -import { User } from '@aragon/protocol-backend-server/build/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '@aragon/protocol-backend-server/build/web3/Network' const { env: { CLIENT_URL } } = process diff --git a/packages/services/test/integration/notification-scanners/MissedReveal.js b/packages/services/test/integration/notification-scanners/MissedReveal.js index 20700f5..c233692 100644 --- a/packages/services/test/integration/notification-scanners/MissedReveal.js +++ b/packages/services/test/integration/notification-scanners/MissedReveal.js @@ -7,7 +7,7 @@ chai.use(sinonChai) import { userDbCleanup, userNotificationTypeDbCleanup } from '../../helpers/dbCleanup' import userNotificationTypeByModel from '../../helpers/userNotificationTypeByModel' import { tryRunScanner } from '../../../src/workers/notification-scanner' -import { User } from '@aragon/protocol-backend-server/build/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '@aragon/protocol-backend-server/build/web3/Network' import * as termIdGetter from '../../../src/helpers/term-id-getter' diff --git a/packages/services/test/integration/notification-scanners/MissedVote.js b/packages/services/test/integration/notification-scanners/MissedVote.js index 3b7f7b5..29b847e 100644 --- a/packages/services/test/integration/notification-scanners/MissedVote.js +++ b/packages/services/test/integration/notification-scanners/MissedVote.js @@ -7,7 +7,7 @@ chai.use(sinonChai) import { userDbCleanup, userNotificationTypeDbCleanup } from '../../helpers/dbCleanup' import userNotificationTypeByModel from '../../helpers/userNotificationTypeByModel' import { tryRunScanner } from '../../../src/workers/notification-scanner' -import { User } from '@aragon/protocol-backend-server/build/models/objection' +import { User } from '@aragon/protocol-backend-shared/build/models/objection' import Network from '@aragon/protocol-backend-server/build/web3/Network' import * as termIdGetter from '../../../src/helpers/term-id-getter' diff --git a/packages/services/test/integration/notification-scanners/SubscriptionReminder.js b/packages/services/test/integration/notification-scanners/SubscriptionReminder.js index 4836aae..338dbc9 100644 --- a/packages/services/test/integration/notification-scanners/SubscriptionReminder.js +++ b/packages/services/test/integration/notification-scanners/SubscriptionReminder.js @@ -8,7 +8,7 @@ import { userDbCleanup, userNotificationTypeDbCleanup } from '../../helpers/dbCl import userNotificationTypeByModel from '../../helpers/userNotificationTypeByModel' import { tryRunScanner } from '../../../src/workers/notification-scanner' import { trySendNotification } from '../../../src/workers/notification-sender' -import { User, UserEmail, UserNotification } from '@aragon/protocol-backend-server/build/models/objection' +import { User, UserEmail, UserNotification } from '@aragon/protocol-backend-shared/build/models/objection' const { env: { CLIENT_URL } } = process const notificationTypeModel = 'SubscriptionReminder' @@ -117,7 +117,7 @@ describe('SubscriptionReminder notifications', () => { await type.$query().update({scannedAt: null}) await tryRunScanner(ctx, notificationTypeModel) const newType = await userNotificationTypeByModel(notificationTypeModel) - expect(type.notifications).to.deep.equal(newType.notifications) + expect(type.notifications[0].updatedAt).to.deep.equal(newType.notifications[0].updatedAt) }) it('should send single notification', async () => { diff --git a/packages/services/test/src/workers/reveal.js b/packages/services/test/src/workers/reveal.js index d4651cc..3061a97 100644 --- a/packages/services/test/src/workers/reveal.js +++ b/packages/services/test/src/workers/reveal.js @@ -3,7 +3,7 @@ import sinon from 'sinon' import sinonChai from 'sinon-chai' import revealWorker from '../../../src/workers/reveal' import Network from '@aragon/protocol-backend-server/build/web3/Network' -import { Reveal } from '@aragon/protocol-backend-server/build/models/objection' +import { Reveal } from '@aragon/protocol-backend-shared/build/models/objection' const { expect } = chai chai.use(sinonChai) diff --git a/packages/shared/README.md b/packages/shared/README.md index 19a07a8..89f8566 100644 --- a/packages/shared/README.md +++ b/packages/shared/README.md @@ -26,12 +26,13 @@ The first one is only used by the back-office frontend app where all the compone ### Helpers It provides the following helper functions: -- [`email-client`](./helpers/email-client.js): Handles sending emails through Postmark +- [`email-client`](./src/helpers/email-client.ts): Handles sending emails through Postmark +- [`jwt-manager`](./src/helpers/jwt-manager.ts): For creating and validating JWTs in email verification - [`gas-price-oracle`](./helpers/gas-price-oracle.js): Get gas price oracle object used to know the current gas prices being paid on each network - [`get-wallet-from-pk`](./helpers/get-wallet-from-pk.js): Decode Ethereum address based on a private key - [`logger`](./helpers/logger.js): Logger object that provides a friendly interface for fancy logging - [`numbers`](./helpers/numbers.js): BigNumber-related helper functions -- [`sleep`](./helpers/sleep.js): Sleep function to wait a number of seconds +- [`sleep`](./src/helpers/sleep.ts): Sleep function to wait a number of seconds - [`times`](./helpers/times.ts): Time constants for using with `Date()` - [`voting`](./helpers/voting.js): Utils related to the CR Voting module of Aragon Protocol @@ -45,3 +46,8 @@ yarn build # from another package: yarn build:shared ``` + +Shared Typescript packages need to be imported from the `build` directory, e.g.: +```js +import sleep from '@aragon/protocol-backend-shared/build/helpers/sleep' +``` diff --git a/packages/shared/helpers/email-client.js b/packages/shared/helpers/email-client.js deleted file mode 100644 index 8709362..0000000 --- a/packages/shared/helpers/email-client.js +++ /dev/null @@ -1,56 +0,0 @@ -const { ServerClient } = require('postmark') - -const { env: { - CLIENT_URL, - EMAIL_FROM_DEFAULT, - POSTMARK_SERVER_API_TOKEN, - POSTMARK_TEMPLATE_ALIAS_VERIFY, -}} = process -const postmarkClient = new ServerClient(POSTMARK_SERVER_API_TOKEN) - -class EmailClient { - async sendMagicLink({ email, address, token }) { - const verifyEmailUrl = `${CLIENT_URL}?preferences=notifications&address=${address}&token=${token}` - const message = { - To: email, - TemplateAlias: POSTMARK_TEMPLATE_ALIAS_VERIFY, - TemplateModel: { verifyEmailUrl }, - } - await this.sendEmailWithTemplate(message) - } - - async sendEmail(message) { - message = this._sanitizeMessage(message) - await postmarkClient.sendEmail(message) - } - - async sendEmailWithTemplate(message) { - message = this._sanitizeMessage(message) - // simply check postmark endpoint when testing. - // there is no way to run template test as of 2020-05-04: - // https://github.com/wildbit/postmark.js/issues/56 - if (POSTMARK_SERVER_API_TOKEN == 'POSTMARK_API_TEST') { - message.TextBody = 'test' - delete message.TemplateAlias - delete message.TemplateModel - return await this.sendEmail(message) - } - await postmarkClient.sendEmailWithTemplate(message) - } - - _sanitizeMessage(message) { - message.From = this._sanitizeFrom(message.From) - message.To = this._sanitizeTo(message.To) - return message - } - - _sanitizeFrom(From) { - return From || EMAIL_FROM_DEFAULT - } - - _sanitizeTo(To) { - return Array.isArray(To) ? To.join(', ') : To - } -} - -module.exports = new EmailClient() diff --git a/packages/shared/helpers/sleep.js b/packages/shared/helpers/sleep.js deleted file mode 100644 index d2c2443..0000000 --- a/packages/shared/helpers/sleep.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = async function (seconds) { - return new Promise(resolve => setTimeout(resolve, seconds * 1000)) -} diff --git a/packages/server/knexfile.js b/packages/shared/knexfile.ts similarity index 100% rename from packages/server/knexfile.js rename to packages/shared/knexfile.ts diff --git a/packages/shared/models/environments/BrowserEnvironment.js b/packages/shared/models/environments/BrowserEnvironment.js index 2da84ad..8f2e55c 100644 --- a/packages/shared/models/environments/BrowserEnvironment.js +++ b/packages/shared/models/environments/BrowserEnvironment.js @@ -1,5 +1,5 @@ const { ethers } = require('ethers') -const sleep = require('../../helpers/sleep') +const sleep = require('../../build/helpers/sleep') const Environment = require('./Environment') const JsonRpcSigner = require('../providers/JsonRpcSigner') const StaticArtifacts = require('../artifacts/StaticArtifacts') @@ -10,7 +10,7 @@ class BrowserEnvironment extends Environment { } async isEnabled() { - await sleep(2) + await sleep(2000) const { web3 } = window return !!(web3 && web3.currentProvider && web3.currentProvider.selectedAddress) } diff --git a/packages/shared/package.json b/packages/shared/package.json index 58a9f28..b2a696a 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -10,7 +10,8 @@ "build:types": "tsc", "build:js": "babel ./src --out-dir ./build --extensions .ts", "build:clean": "yarn clean && yarn build", - "clean": "rm -rf ./build" + "clean": "rm -rf ./build", + "db:setup": "babel-node --extensions .ts src/scripts/db-setup" }, "dependencies": { "@aragon/contract-helpers-test": "^0.1.0", @@ -23,6 +24,10 @@ "dotenv": "^8.2.0", "ethers": "^4.0.46", "graphql-request": "^1.8.2", + "jsonwebtoken": "^8.5.1", + "knex": "^0.21.12", + "objection": "^2.2.3", + "pg": "^8.4.2", "postmark": "^2.5.3", "web3-utils": "^1.2.4" }, @@ -31,6 +36,8 @@ "@babel/core": "^7.12.3", "@babel/preset-env": "^7.12.1", "@babel/preset-typescript": "^7.12.1", + "@types/bcryptjs": "^2.4.2", + "@types/jsonwebtoken": "^8.5.0", "@typescript-eslint/eslint-plugin": "^4.6.1", "@typescript-eslint/parser": "^4.6.1", "eslint": "^7.12.1", diff --git a/packages/server/src/database/config.js b/packages/shared/src/database/config.ts similarity index 83% rename from packages/server/src/database/config.js rename to packages/shared/src/database/config.ts index 499eae6..9ac62c3 100644 --- a/packages/server/src/database/config.js +++ b/packages/shared/src/database/config.ts @@ -1,13 +1,14 @@ import path from 'path' import dotenv from 'dotenv' +import { Config } from 'knex' dotenv.config() -const config = { +const config: Config = { client: 'pg', connection: { host: process.env.DB_HOST, - port: process.env.DB_PORT, + port: Number(process.env.DB_PORT), user: process.env.DB_USER, password: process.env.DB_PASS, database: process.env.DB_NAME, diff --git a/packages/shared/src/database/migrations/20200425004131_create-emails.ts b/packages/shared/src/database/migrations/20200425004131_create-emails.ts new file mode 100644 index 0000000..8391a41 --- /dev/null +++ b/packages/shared/src/database/migrations/20200425004131_create-emails.ts @@ -0,0 +1,14 @@ +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { + return knex.schema.createTable('UserEmails', function (table) { + table.increments('id') + table.string('email').unique().notNullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() + }) +} + +export function down(knex: Knex): Promise { + return knex.schema.dropTable('UserEmails') +} diff --git a/packages/shared/src/database/migrations/20200425004137_create-users.ts b/packages/shared/src/database/migrations/20200425004137_create-users.ts new file mode 100644 index 0000000..1628536 --- /dev/null +++ b/packages/shared/src/database/migrations/20200425004137_create-users.ts @@ -0,0 +1,18 @@ +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { + return knex.schema.createTable('Users', function (table) { + table.increments('id') + table.string('address').unique().notNullable() + table.boolean('addressVerified').defaultTo(false).notNullable() + table.integer('userEmailId').index() + table.foreign('userEmailId').references('UserEmails.id').onDelete('SET NULL') + table.boolean('emailVerified').defaultTo(false).notNullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() + }) +} + +export function down(knex: Knex): Promise { + return knex.schema.dropTable('Users') +} diff --git a/packages/shared/src/database/migrations/20200425004140_create-admins.ts b/packages/shared/src/database/migrations/20200425004140_create-admins.ts new file mode 100644 index 0000000..cb050cf --- /dev/null +++ b/packages/shared/src/database/migrations/20200425004140_create-admins.ts @@ -0,0 +1,15 @@ +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { + return knex.schema.createTable('Admins', function (table) { + table.increments('id') + table.string('email').unique().notNullable() + table.string('password').notNullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() + }) +} + +export function down(knex: Knex): Promise { + return knex.schema.dropTable('Admins') +} diff --git a/packages/server/src/database/migrations/20200425004150_create-sessions.js b/packages/shared/src/database/migrations/20200425004150_create-sessions.ts similarity index 59% rename from packages/server/src/database/migrations/20200425004150_create-sessions.js rename to packages/shared/src/database/migrations/20200425004150_create-sessions.ts index e11c858..f89241f 100644 --- a/packages/server/src/database/migrations/20200425004150_create-sessions.js +++ b/packages/shared/src/database/migrations/20200425004150_create-sessions.ts @@ -1,5 +1,7 @@ -export function up(knex) { - return knex.schema.dropTableIfExists('Sessions').createTable('Sessions', function (table) { +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { + return knex.schema.createTable('Sessions', function (table) { table.increments('id') table.string('sid').unique().notNullable() table.jsonb('data').notNullable() @@ -7,12 +9,12 @@ export function up(knex) { table.foreign('adminId').references('Admins.id').onDelete('CASCADE') table.integer('userId').index() table.foreign('userId').references('Users.id').onDelete('CASCADE') - table.datetime('expiresAt').index().notNullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('expiresAt').index().notNullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() }).raw('ALTER TABLE "Sessions" ADD CONSTRAINT "admin_or_user" CHECK (("adminId" IS NOT NULL AND "userId" IS NULL) OR ("userId" IS NOT NULL AND "adminId" IS NULL));') } -export function down(knex) { +export function down(knex: Knex): Promise { return knex.schema.dropTable('Sessions') } diff --git a/packages/server/src/database/migrations/20200425004217_create-settings.js b/packages/shared/src/database/migrations/20200425004217_create-settings.ts similarity index 60% rename from packages/server/src/database/migrations/20200425004217_create-settings.js rename to packages/shared/src/database/migrations/20200425004217_create-settings.ts index 7868feb..b585226 100644 --- a/packages/server/src/database/migrations/20200425004217_create-settings.js +++ b/packages/shared/src/database/migrations/20200425004217_create-settings.ts @@ -1,14 +1,16 @@ -export function up(knex) { +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { return knex.schema.createTable('UserNotificationSettings', function (table) { table.increments('id') table.boolean('notificationsDisabled').defaultTo(false).notNullable() table.integer('userId').index().notNullable() table.foreign('userId').references('Users.id').onDelete('CASCADE') - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() }) } -export function down(knex) { +export function down(knex: Knex): Promise { return knex.schema.dropTable('UserNotificationSettings') } diff --git a/packages/server/src/database/migrations/20200425005745_create-tokens.js b/packages/shared/src/database/migrations/20200425005745_create-tokens.ts similarity index 56% rename from packages/server/src/database/migrations/20200425005745_create-tokens.js rename to packages/shared/src/database/migrations/20200425005745_create-tokens.ts index 42354a1..755017c 100644 --- a/packages/server/src/database/migrations/20200425005745_create-tokens.js +++ b/packages/shared/src/database/migrations/20200425005745_create-tokens.ts @@ -1,16 +1,18 @@ -export function up(knex) { +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { return knex.schema.createTable('UserEmailVerificationTokens', function (table) { table.increments('id') table.string('email').notNullable() table.string('token').notNullable() table.integer('userId').index().notNullable() table.foreign('userId').references('Users.id').onDelete('CASCADE') - table.datetime('expiresAt').index().notNullable() - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('expiresAt').index().notNullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() }) } -export function down(knex) { +export function down(knex: Knex): Promise { return knex.schema.dropTable('UserEmailVerificationTokens') } diff --git a/packages/shared/src/database/migrations/20200428185153_create-reveals.ts b/packages/shared/src/database/migrations/20200428185153_create-reveals.ts new file mode 100644 index 0000000..32fba45 --- /dev/null +++ b/packages/shared/src/database/migrations/20200428185153_create-reveals.ts @@ -0,0 +1,23 @@ +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { + return knex.schema.createTable('Reveals', function (table) { + table.increments('id') + table.string('voteId').notNullable() + table.string('guardian').notNullable() + table.unique(['guardian', 'voteId']) + table.string('disputeId').notNullable() + table.integer('roundNumber').notNullable() + table.integer('outcome').notNullable() + table.string('salt').notNullable() + table.boolean('revealed').defaultTo(false).notNullable() + table.integer('failedAttempts').notNullable().defaultTo(0) + table.boolean('expired').notNullable().defaultTo(false) + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() + }) +} + +export function down(knex: Knex): Promise { + return knex.schema.dropTable('Reveals') +} diff --git a/packages/shared/src/database/migrations/20200504162940_create-keeper-suspicious-transactions.ts b/packages/shared/src/database/migrations/20200504162940_create-keeper-suspicious-transactions.ts new file mode 100644 index 0000000..aaaa4c5 --- /dev/null +++ b/packages/shared/src/database/migrations/20200504162940_create-keeper-suspicious-transactions.ts @@ -0,0 +1,15 @@ +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { + return knex.schema.createTable('KeeperSuspiciousTransactions', function (table) { + table.increments('id') + table.string('blockNumber').unique().notNullable() + table.string('txHash').unique().nullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() + }) +} + +export function down(knex: Knex): Promise { + return knex.schema.dropTable('KeeperSuspiciousTransactions') +} diff --git a/packages/shared/src/database/migrations/20200509004243_create-notification-types.ts b/packages/shared/src/database/migrations/20200509004243_create-notification-types.ts new file mode 100644 index 0000000..393ba1f --- /dev/null +++ b/packages/shared/src/database/migrations/20200509004243_create-notification-types.ts @@ -0,0 +1,15 @@ +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { + return knex.schema.createTable('UserNotificationTypes', function (table) { + table.increments('id') + table.string('model').unique().notNullable() + table.dateTime('scannedAt').index() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() + }) +} + +export function down(knex: Knex): Promise { + return knex.schema.dropTable('UserNotificationTypes') +} diff --git a/packages/server/src/database/migrations/20200509004247_create-notifications.js b/packages/shared/src/database/migrations/20200509004247_create-notifications.ts similarity index 63% rename from packages/server/src/database/migrations/20200509004247_create-notifications.js rename to packages/shared/src/database/migrations/20200509004247_create-notifications.ts index 64b74c6..91be437 100644 --- a/packages/server/src/database/migrations/20200509004247_create-notifications.js +++ b/packages/shared/src/database/migrations/20200509004247_create-notifications.ts @@ -1,17 +1,19 @@ -export function up(knex) { +import * as Knex from 'knex' + +export function up(knex: Knex): Promise { return knex.schema.createTable('UserNotifications', function (table) { table.increments('id') table.jsonb('details').index() - table.datetime('sentAt').index() + table.dateTime('sentAt').index() table.integer('userNotificationTypeId').index().notNullable() table.foreign('userNotificationTypeId').references('UserNotificationTypes.id').onDelete('CASCADE') table.integer('userId').index().notNullable() table.foreign('userId').references('Users.id').onDelete('CASCADE') - table.datetime('createdAt').defaultTo(knex.fn.now()).notNullable() - table.datetime('updatedAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('createdAt').defaultTo(knex.fn.now()).notNullable() + table.dateTime('updatedAt').defaultTo(knex.fn.now()).notNullable() }) } -export function down(knex) { +export function down(knex: Knex): Promise { return knex.schema.dropTable('UserNotifications') } diff --git a/packages/server/src/database/seeds/insert-admin.js b/packages/shared/src/database/seeds/insert-admin.ts similarity index 83% rename from packages/server/src/database/seeds/insert-admin.js rename to packages/shared/src/database/seeds/insert-admin.ts index e861cab..3040518 100644 --- a/packages/server/src/database/seeds/insert-admin.js +++ b/packages/shared/src/database/seeds/insert-admin.ts @@ -5,6 +5,6 @@ dotenv.config() const { env: { ADMIN_EMAIL, ADMIN_PASSWORD } } = process export async function seed() { - const admin = await Admin.findByEmail(ADMIN_EMAIL) + const admin = await Admin.findByEmail(ADMIN_EMAIL!) if (!admin) await Admin.create({ email: ADMIN_EMAIL, password: ADMIN_PASSWORD }) } diff --git a/packages/shared/src/helpers/email-client.ts b/packages/shared/src/helpers/email-client.ts new file mode 100644 index 0000000..7b350ef --- /dev/null +++ b/packages/shared/src/helpers/email-client.ts @@ -0,0 +1,63 @@ +import { ServerClient, Message, TemplatedMessage } from 'postmark' + +const { env: { + CLIENT_URL, + EMAIL_FROM_DEFAULT, + POSTMARK_SERVER_API_TOKEN, + POSTMARK_TEMPLATE_ALIAS_VERIFY, +}} = process +const postmarkClient = new ServerClient(POSTMARK_SERVER_API_TOKEN!) + +type MagicLinkPayload = { email: string, address: string, token: string } +type ToMaybeArray = { To?: string | string[] } +type EmailMessage = Message & ToMaybeArray +type EmailTemplatedMessage = Partial & ToMaybeArray +type SanitizedMessage = M extends EmailMessage ? Message : TemplatedMessage + +class EmailClient { + async sendMagicLink({ email, address, token }: MagicLinkPayload): Promise { + const verifyEmailUrl = `${CLIENT_URL}?preferences=notifications&address=${address}&token=${token}` + const message = { + To: email, + TemplateAlias: POSTMARK_TEMPLATE_ALIAS_VERIFY, + TemplateModel: { verifyEmailUrl }, + } + await this.sendEmailWithTemplate(message) + } + + async sendEmail(message: EmailMessage): Promise { + const sanitizedMessage = this._sanitizeMessage(message) + await postmarkClient.sendEmail(sanitizedMessage) + } + + async sendEmailWithTemplate(message: EmailTemplatedMessage): Promise { + const sanitizedMessage = this._sanitizeMessage(message) + // simply check postmark endpoint when testing. + // there is no way to run template test as of 2020-05-04: + // https://github.com/wildbit/postmark.js/issues/56 + if (POSTMARK_SERVER_API_TOKEN == 'POSTMARK_API_TEST') { + delete sanitizedMessage.TemplateAlias + delete sanitizedMessage.TemplateModel + const nonTemplateMessage = message as Message + nonTemplateMessage.TextBody = 'test' + return await this.sendEmail(nonTemplateMessage) + } + await postmarkClient.sendEmailWithTemplate(sanitizedMessage) + } + + private _sanitizeMessage(message: M): SanitizedMessage { + message.From = this._sanitizeFrom(message?.From) + if (message.To) message.To = this._sanitizeTo(message.To) + return message as any as SanitizedMessage + } + + private _sanitizeFrom(From: string | undefined): string { + return From || EMAIL_FROM_DEFAULT! + } + + private _sanitizeTo(To: string | string[]): string { + return Array.isArray(To) ? To.join(', ') : To + } +} + +export default new EmailClient() diff --git a/packages/shared/src/helpers/jwt-manager.ts b/packages/shared/src/helpers/jwt-manager.ts new file mode 100644 index 0000000..5ad13ab --- /dev/null +++ b/packages/shared/src/helpers/jwt-manager.ts @@ -0,0 +1,23 @@ +import jwt from 'jsonwebtoken' + +const { env: { + EMAIL_JWT_PRIVATE_KEY, +}} = process + +function generateToken(expiresIn: string | number = '24h'): string { + if (!EMAIL_JWT_PRIVATE_KEY) throw new Error('EMAIL_JWT_PRIVATE_KEY env variable missing.') + const payload = { timestamp: Date.now() } + return jwt.sign(payload, EMAIL_JWT_PRIVATE_KEY, { expiresIn }) +} + +function isTokenValid(token: string): boolean { + if (!EMAIL_JWT_PRIVATE_KEY) throw new Error('EMAIL_JWT_PRIVATE_KEY env variable missing.') + try { + jwt.verify(token, EMAIL_JWT_PRIVATE_KEY) + return true + } catch { + return false + } +} + +export { generateToken, isTokenValid } diff --git a/packages/shared/src/helpers/sleep.ts b/packages/shared/src/helpers/sleep.ts new file mode 100644 index 0000000..a49de62 --- /dev/null +++ b/packages/shared/src/helpers/sleep.ts @@ -0,0 +1,3 @@ +export default async function (ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)) +} diff --git a/packages/shared/src/models/objection/Admin.ts b/packages/shared/src/models/objection/Admin.ts new file mode 100644 index 0000000..19900a2 --- /dev/null +++ b/packages/shared/src/models/objection/Admin.ts @@ -0,0 +1,57 @@ +import BaseModel from './BaseModel' +import { Session } from './' +import bcrypt from 'bcryptjs' + +export default class Admin extends BaseModel { + static get tableName() { + return 'Admins' + } + + email?: string + password?: string + sessions?: Session[] + + static get relationMappings() { + return { + sessions: { + relation: BaseModel.HasManyRelation, + modelClass: 'Session', + join: { + from: 'Admins.id', + to: 'Sessions.adminId' + } + } + } + } + + static async countByEmail(email: string): Promise { + return this.query().where({ email }).resultSize() + } + + static async findByEmail(email: string): Promise { + return this.findOne({ email }) + } + + static async findAllEmails(): Promise { + const admins = await this.query().select('email') + return admins.map(admin => admin.email!) + } + + hasPassword(password: string): boolean { + return bcrypt.compareSync(password, this.password!) + } + + hashPassword(): void { + if (this.password) this.password = bcrypt.hashSync(this.password) + } + + $beforeInsert: BaseModel['$beforeInsert'] = async (queryContext) => { + await super.$beforeInsert(queryContext) + this.hashPassword() + } + + $beforeUpdate: BaseModel['$beforeUpdate'] = async (opt, queryContext) => { + await super.$beforeUpdate(opt, queryContext) + this.hashPassword() + } +} diff --git a/packages/shared/src/models/objection/BaseModel.ts b/packages/shared/src/models/objection/BaseModel.ts new file mode 100644 index 0000000..1881f79 --- /dev/null +++ b/packages/shared/src/models/objection/BaseModel.ts @@ -0,0 +1,87 @@ +import Knex from 'knex' +import { Model, MaybeCompositeId, QueryBuilder } from 'objection' + +import config from '../../database/config' +Model.knex(Knex(config)) + +// "this" is not polymorphic for static methods, need to cast return values +// Ongoing issue as of Nov 7, 2020: https://github.com/microsoft/TypeScript/issues/5863 +type SingleResult = QueryBuilder, InstanceType> +export { SingleResult } + +export default class BaseModel extends Model { + // modelPaths is used to allow modelClass relations be defined as a string to avoid require loops + // https://vincit.github.io/objection.js/guide/relations.html#require-loops + static get modelPaths(): [string] { + return [__dirname]; + } + + id!: MaybeCompositeId + updatedAt?: Date + createdAt?: Date + + $beforeUpdate: Model['$beforeUpdate'] = async (opt, queryContext) => { + await super.$beforeUpdate(opt, queryContext) + this.updatedAt = new Date() + } + + + // static query methods (table level) + + static async exists(args: any): Promise { + return !!(await this.findOne(args)) + } + + static count(args: any): Promise { + return this.query().where(args).resultSize() + } + + static findById( + this: T, + id: BaseModel['id'] + ): SingleResult { + return this.query().findById(id) as SingleResult + } + + static findOne( + this: T, + args: any + ): SingleResult { + return this.query().findOne(args) as SingleResult + } + + static async findOrInsert( + this: T, + args: any + ): Promise> { + let row = await this.findOne(args) + if (!row) row = await this.create(args) + return row as SingleResult + } + + static create( + this: T, + args: any = {} + ): SingleResult { + return this.query().insert(args) as SingleResult + } + + + // instance query methods (row level) + + async relatedUpdateOrInsert(relation: string, args: any): Promise { + const row = await this.$relatedQuery(relation) + if (row) { + await this.$relatedQuery(relation).update(args) + } else { + await this.$relatedQuery(relation).insert(args) + } + } + + get createdAtDateString(): string { + if (!this.createdAt) { + throw Error('createdAt field missing') + } + return this.createdAt.toLocaleDateString('en-US', ({dateStyle: 'full'} as Intl.DateTimeFormatOptions)) // format: Tuesday, May 19, 2020 + } +} diff --git a/packages/server/src/models/objection/KeeperSuspiciousTransaction.js b/packages/shared/src/models/objection/KeeperSuspiciousTransaction.ts similarity index 60% rename from packages/server/src/models/objection/KeeperSuspiciousTransaction.js rename to packages/shared/src/models/objection/KeeperSuspiciousTransaction.ts index 398510c..70ee8a6 100644 --- a/packages/server/src/models/objection/KeeperSuspiciousTransaction.js +++ b/packages/shared/src/models/objection/KeeperSuspiciousTransaction.ts @@ -5,17 +5,16 @@ export default class KeeperSuspiciousTransactions extends BaseModel { return 'KeeperSuspiciousTransactions' } - static async last() { + blockNumber?: string + txHash?: string + + static async last(): Promise { const txs = await this.query().limit(1).orderBy('createdAt', 'DESC') return txs[0] } - static async lastInspectedBlockNumber() { + static async lastInspectedBlockNumber(): Promise { const tx = await this.last() - return tx ? tx.blockNumber : 0 - } - - static async create(params = {}) { - return this.query().insert(params) + return tx ? Number(tx.blockNumber!) : 0 } } diff --git a/packages/shared/src/models/objection/Reveal.ts b/packages/shared/src/models/objection/Reveal.ts new file mode 100644 index 0000000..d378282 --- /dev/null +++ b/packages/shared/src/models/objection/Reveal.ts @@ -0,0 +1,18 @@ +import BaseModel from './BaseModel' + +export default class Reveal extends BaseModel { + static get tableName() { + return 'Reveals' + } + + voteId?: string + guardian?: string + blockNumber?: string + disputeId?: string + roundNumber?: number + outcome?: number + salt?: string + revealed?: boolean + failedAttempts?: number + expired?: boolean +} diff --git a/packages/server/src/models/objection/Session.js b/packages/shared/src/models/objection/Session.ts similarity index 70% rename from packages/server/src/models/objection/Session.js rename to packages/shared/src/models/objection/Session.ts index 5243e99..1b1cd4f 100644 --- a/packages/server/src/models/objection/Session.js +++ b/packages/shared/src/models/objection/Session.ts @@ -1,10 +1,18 @@ -import BaseModel from './BaseModel' +import { BaseModel, User, Admin } from './' export default class Session extends BaseModel { static get tableName() { return 'Sessions' } + sid?: string + data?: any + adminId?: number + userId?: number + expiresAt?: Date + user?: User + admin?: Admin + static get relationMappings() { return { user: { @@ -26,14 +34,14 @@ export default class Session extends BaseModel { } } - static async getData(sid) { + static async getData(sid: Session['sid']) { const session = await this.findOne({sid}) return session?.data } - static async setData(sid, newData) { - for (let prop of ['userId', 'adminId']) { - if (newData.hasOwnProperty(prop)) { + static async setData(sid: Session['sid'], newData: Session['data']): Promise { + for (const prop of ['userId', 'adminId']) { + if (Object.prototype.hasOwnProperty.call(newData, prop)) { const row = { sid, data: newData, diff --git a/packages/server/src/models/objection/User.js b/packages/shared/src/models/objection/User.ts similarity index 65% rename from packages/server/src/models/objection/User.js rename to packages/shared/src/models/objection/User.ts index d4b8048..af595b9 100644 --- a/packages/server/src/models/objection/User.js +++ b/packages/shared/src/models/objection/User.ts @@ -1,17 +1,28 @@ -import BaseModel from './BaseModel' -import UserEmail from './UserEmail' -import emailClient from '@aragon/protocol-backend-shared/helpers/email-client' -import { generateToken } from '../../helpers/token-manager' +import { BaseModel, Session, UserNotificationSetting, UserNotification, UserEmailVerificationToken, UserEmail } from './' +import { SingleResult } from './BaseModel' +import emailClient from '../../helpers/email-client' +import { generateToken } from '../../helpers/jwt-manager' -import { DAYS } from '@aragon/protocol-backend-shared/build/helpers/times' +import { DAYS } from '../../helpers/times' const EMAIL_TOKEN_EXPIRES = DAYS const EMAIL_TOKEN_OLD = DAYS export default class User extends BaseModel { + static get tableName() { return 'Users' } + address?: string + addressVerified?: boolean + userEmailId?: number + emailVerified?: boolean + sessions?: Session[] + notificationSetting?: UserNotificationSetting + notifications?: UserNotification[] + emailVerificationToken?: UserEmailVerificationToken + email?: UserEmail + static get relationMappings() { return { sessions: { @@ -57,42 +68,45 @@ export default class User extends BaseModel { } } - static findOne(args) { + static findOne( + this: T, + args: any + ): SingleResult { if (args.address) args.address = args.address.toLowerCase() - return super.findOne(args) + return super.findOne(args) as SingleResult } - async $beforeInsert(queryContext) { + $beforeInsert: BaseModel['$beforeInsert'] = async (queryContext) => { await super.$beforeInsert(queryContext) if (this.address) this.address = this.address.toLowerCase() } - async $beforeUpdate(opt, queryContext) { + $beforeUpdate: BaseModel['$beforeUpdate'] = async (opt, queryContext) => { await super.$beforeUpdate(opt, queryContext) if (this.address) this.address = this.address.toLowerCase() } - static async findWithUnverifiedEmail() { + static async findWithUnverifiedEmail(): Promise { const users = await this.query().where({emailVerified: false}).withGraphFetched('[email, emailVerificationToken]') return users.filter(user => !!user.email) } - static async findWithoutDisabledNotifications() { + static async findWithoutDisabledNotifications(): Promise { const users = await this.query().withGraphFetched('[email, notificationSetting]') return users.filter(user => !!user.email && !user.notificationSetting?.notificationsDisabled) } - static async findWithOldVerificationToken() { + static async findWithOldVerificationToken(): Promise { const users = await this.findWithUnverifiedEmail() - return users.filter(user => user.emailVerificationToken && user.emailVerificationToken.expiresAt <= new Date(Date.now()-EMAIL_TOKEN_OLD)) + return users.filter(user => user.emailVerificationToken && user.emailVerificationToken.expiresAt! <= new Date(Date.now()-EMAIL_TOKEN_OLD)) } - static async findUnverifiedAnjRegistrations() { + static async findUnverifiedAnjRegistrations(): Promise { const users = await this.findWithUnverifiedEmail() return users.filter(user => !user.addressVerified) } - async relateEmail(email) { + async relateEmail(email: string): Promise { await this.unrelateEmail() const emailInstance = await UserEmail.findOne({email}) if (emailInstance) { @@ -102,32 +116,34 @@ export default class User extends BaseModel { } } - async unrelateEmail() { + async unrelateEmail(): Promise { const user = await this.$fetchGraph('email') let emailInstance = user.email await user.$relatedQuery('email').unrelate() // clean emails with no users if (emailInstance) { emailInstance = await emailInstance.$fetchGraph('users') - if (emailInstance.users.length == 0) { + if (emailInstance.users?.length == 0) { await emailInstance.$query().del() } } } - async sendVerificationEmail() { + async sendVerificationEmail(): Promise { const user = await this.$fetchGraph('email') - const { email: { email }, address } = user + const { email: userEmail, address } = user + if (!userEmail) throw new Error(`No associated email found for user ${user.address}`) + const { email } = userEmail const tokenExpiresSeconds = EMAIL_TOKEN_EXPIRES/1000 const token = generateToken(tokenExpiresSeconds) await user.relatedUpdateOrInsert('emailVerificationToken', { - email, + email: email!, token, expiresAt: new Date(Date.now()+EMAIL_TOKEN_EXPIRES) }) await emailClient.sendMagicLink({ - email, - address, + email: email!, + address: address!, token }) } diff --git a/packages/server/src/models/objection/UserEmail.js b/packages/shared/src/models/objection/UserEmail.ts similarity index 83% rename from packages/server/src/models/objection/UserEmail.js rename to packages/shared/src/models/objection/UserEmail.ts index cbf9fc2..9e046cb 100644 --- a/packages/server/src/models/objection/UserEmail.js +++ b/packages/shared/src/models/objection/UserEmail.ts @@ -1,10 +1,13 @@ -import BaseModel from './BaseModel' +import { BaseModel, User } from './' export default class UserEmail extends BaseModel { static get tableName() { return 'UserEmails' } + email?: string + users?: User[] + static get relationMappings() { return { users: { diff --git a/packages/server/src/models/objection/UserEmailVerificationToken.js b/packages/shared/src/models/objection/UserEmailVerificationToken.ts similarity index 76% rename from packages/server/src/models/objection/UserEmailVerificationToken.js rename to packages/shared/src/models/objection/UserEmailVerificationToken.ts index b68792f..5852963 100644 --- a/packages/server/src/models/objection/UserEmailVerificationToken.js +++ b/packages/shared/src/models/objection/UserEmailVerificationToken.ts @@ -1,10 +1,16 @@ -import BaseModel from './BaseModel' +import { BaseModel, User } from './' export default class UserEmailVerificationToken extends BaseModel { static get tableName() { return 'UserEmailVerificationTokens' } + email?: string + token?: string + userId?: number + expiresAt?: Date + user?: User + static get relationMappings() { return { user: { diff --git a/packages/server/src/models/objection/UserNotification.js b/packages/shared/src/models/objection/UserNotification.ts similarity index 76% rename from packages/server/src/models/objection/UserNotification.js rename to packages/shared/src/models/objection/UserNotification.ts index dfdc708..2f5bf1d 100644 --- a/packages/server/src/models/objection/UserNotification.js +++ b/packages/shared/src/models/objection/UserNotification.ts @@ -1,11 +1,18 @@ -import BaseModel from './BaseModel' -import { HOURS } from '@aragon/protocol-backend-shared/build/helpers/times' +import { BaseModel, User, UserNotificationType } from './' +import { HOURS } from '../../helpers/times' export default class UserNotification extends BaseModel { static get tableName() { return 'UserNotifications' } + details?: any + sentAt?: Date + userNotificationTypeId?: number + userId?: number + user?: User + type?: UserNotificationType + static get relationMappings() { return { user: { diff --git a/packages/server/src/models/objection/UserNotificationSetting.js b/packages/shared/src/models/objection/UserNotificationSetting.ts similarity index 79% rename from packages/server/src/models/objection/UserNotificationSetting.js rename to packages/shared/src/models/objection/UserNotificationSetting.ts index c1136cd..052fa65 100644 --- a/packages/server/src/models/objection/UserNotificationSetting.js +++ b/packages/shared/src/models/objection/UserNotificationSetting.ts @@ -1,10 +1,14 @@ -import BaseModel from './BaseModel' +import { BaseModel, User } from './' export default class UserNotificationSetting extends BaseModel { static get tableName() { return 'UserNotificationSettings' } + notificationsDisabled?: boolean + userId?: number + user?: User + static get relationMappings() { return { user: { diff --git a/packages/server/src/models/objection/UserNotificationType.js b/packages/shared/src/models/objection/UserNotificationType.ts similarity index 77% rename from packages/server/src/models/objection/UserNotificationType.js rename to packages/shared/src/models/objection/UserNotificationType.ts index ae0b0a2..2ccbb86 100644 --- a/packages/server/src/models/objection/UserNotificationType.js +++ b/packages/shared/src/models/objection/UserNotificationType.ts @@ -1,10 +1,14 @@ -import BaseModel from './BaseModel' +import { BaseModel, UserNotification } from './' export default class UserNotificationType extends BaseModel { static get tableName() { return 'UserNotificationTypes' } + model?: string + scannedAt?: Date + notifications?: UserNotification[] + static get relationMappings() { return { notifications: { diff --git a/packages/shared/src/models/objection/index.ts b/packages/shared/src/models/objection/index.ts new file mode 100644 index 0000000..381aed7 --- /dev/null +++ b/packages/shared/src/models/objection/index.ts @@ -0,0 +1,11 @@ +export { default as Admin } from './Admin' +export { default as BaseModel } from './BaseModel' +export { default as KeeperSuspiciousTransaction } from './KeeperSuspiciousTransaction' +export { default as Reveal } from './Reveal' +export { default as Session } from './Session' +export { default as User } from './User' +export { default as UserEmail } from './UserEmail' +export { default as UserEmailVerificationToken } from './UserEmailVerificationToken' +export { default as UserNotification } from './UserNotification' +export { default as UserNotificationSetting } from './UserNotificationSetting' +export { default as UserNotificationType } from './UserNotificationType' diff --git a/packages/shared/src/scripts/db-setup.ts b/packages/shared/src/scripts/db-setup.ts new file mode 100755 index 0000000..ad27c5a --- /dev/null +++ b/packages/shared/src/scripts/db-setup.ts @@ -0,0 +1,35 @@ +import Knex from 'knex' +import sleep from '../helpers/sleep' +import { SECONDS } from '../helpers/times' + +import config from '../database/config' +const knex = Knex(config) + +async function waitConnection() { + for (;;) { + try { + return await knex.migrate.currentVersion() + } + catch (error) { + if (error.code == 'ECONNREFUSED') { + console.log('Database connection timed out, retrying in 5 seconds...') + await sleep(5 * SECONDS) + } + else { + throw error + } + } + } +} + +async function main() { + console.log('Running knex database migrations...') + await waitConnection() + await knex.migrate.latest() + knex.destroy() +} + +main().catch((error) => { + console.error(error) + process.exit(1) +}) diff --git a/yarn.lock b/yarn.lock index 03c60a7..7336d34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,24 +27,7 @@ resolved "https://registry.yarnpkg.com/@aragonone/erc20-faucet/-/erc20-faucet-1.0.0.tgz#ce671a03c25e3dd3930e1a0395830fe500fc8b22" integrity sha512-0e7+5dH5xFfyj8LF7t1k6JEla0lFupwUezEekQTEGqz45CtVHiIjLjEbkQ9n29MITNvNtUFMZVruK7jprZRHBg== -"@babel/cli@^7.12.1": - version "7.12.1" - resolved "https://testnet.thegraph.com/npm-registry/@babel%2fcli/-/cli-7.12.1.tgz#e08a0b1cb6fcd4b9eb6a606ba5602c5c0fe24a0c" - integrity sha512-eRJREyrfAJ2r42Iaxe8h3v6yyj1wu9OyosaUHW6UImjGf9ahGL9nsFNh7OCopvtcPL8WnEo7tp78wrZaZ6vG9g== - dependencies: - commander "^4.0.1" - convert-source-map "^1.1.0" - fs-readdir-recursive "^1.1.0" - glob "^7.0.0" - lodash "^4.17.19" - make-dir "^2.1.0" - slash "^2.0.0" - source-map "^0.5.0" - optionalDependencies: - "@nicolo-ribaudo/chokidar-2" "^2.1.8" - chokidar "^3.4.0" - -"@babel/cli@^7.7.7": +"@babel/cli@^7.12.1", "@babel/cli@^7.7.7": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.12.1.tgz#e08a0b1cb6fcd4b9eb6a606ba5602c5c0fe24a0c" integrity sha512-eRJREyrfAJ2r42Iaxe8h3v6yyj1wu9OyosaUHW6UImjGf9ahGL9nsFNh7OCopvtcPL8WnEo7tp78wrZaZ6vG9g== @@ -123,7 +106,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.4.5", "@babel/core@^7.7.7": +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.4.5", "@babel/core@^7.7.7": version "7.12.3" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8" integrity sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g== @@ -145,28 +128,6 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.12.3": - version "7.12.3" - resolved "https://testnet.thegraph.com/npm-registry/@babel%2fcore/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8" - integrity sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.1" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.1" - "@babel/parser" "^7.12.3" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.12.1" - "@babel/types" "^7.12.1" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - "@babel/generator@^7.12.1", "@babel/generator@^7.4.0", "@babel/generator@^7.8.4", "@babel/generator@^7.9.0": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.1.tgz#0d70be32bdaa03d7c51c8597dda76e0df1f15468" @@ -1097,79 +1058,7 @@ levenary "^1.1.1" semver "^5.5.0" -"@babel/preset-env@^7.12.1": - version "7.12.1" - resolved "https://testnet.thegraph.com/npm-registry/@babel%2fpreset-env/-/preset-env-7.12.1.tgz#9c7e5ca82a19efc865384bb4989148d2ee5d7ac2" - integrity sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg== - dependencies: - "@babel/compat-data" "^7.12.1" - "@babel/helper-compilation-targets" "^7.12.1" - "@babel/helper-module-imports" "^7.12.1" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-validator-option" "^7.12.1" - "@babel/plugin-proposal-async-generator-functions" "^7.12.1" - "@babel/plugin-proposal-class-properties" "^7.12.1" - "@babel/plugin-proposal-dynamic-import" "^7.12.1" - "@babel/plugin-proposal-export-namespace-from" "^7.12.1" - "@babel/plugin-proposal-json-strings" "^7.12.1" - "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" - "@babel/plugin-proposal-numeric-separator" "^7.12.1" - "@babel/plugin-proposal-object-rest-spread" "^7.12.1" - "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" - "@babel/plugin-proposal-optional-chaining" "^7.12.1" - "@babel/plugin-proposal-private-methods" "^7.12.1" - "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.12.1" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.12.1" - "@babel/plugin-transform-arrow-functions" "^7.12.1" - "@babel/plugin-transform-async-to-generator" "^7.12.1" - "@babel/plugin-transform-block-scoped-functions" "^7.12.1" - "@babel/plugin-transform-block-scoping" "^7.12.1" - "@babel/plugin-transform-classes" "^7.12.1" - "@babel/plugin-transform-computed-properties" "^7.12.1" - "@babel/plugin-transform-destructuring" "^7.12.1" - "@babel/plugin-transform-dotall-regex" "^7.12.1" - "@babel/plugin-transform-duplicate-keys" "^7.12.1" - "@babel/plugin-transform-exponentiation-operator" "^7.12.1" - "@babel/plugin-transform-for-of" "^7.12.1" - "@babel/plugin-transform-function-name" "^7.12.1" - "@babel/plugin-transform-literals" "^7.12.1" - "@babel/plugin-transform-member-expression-literals" "^7.12.1" - "@babel/plugin-transform-modules-amd" "^7.12.1" - "@babel/plugin-transform-modules-commonjs" "^7.12.1" - "@babel/plugin-transform-modules-systemjs" "^7.12.1" - "@babel/plugin-transform-modules-umd" "^7.12.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" - "@babel/plugin-transform-new-target" "^7.12.1" - "@babel/plugin-transform-object-super" "^7.12.1" - "@babel/plugin-transform-parameters" "^7.12.1" - "@babel/plugin-transform-property-literals" "^7.12.1" - "@babel/plugin-transform-regenerator" "^7.12.1" - "@babel/plugin-transform-reserved-words" "^7.12.1" - "@babel/plugin-transform-shorthand-properties" "^7.12.1" - "@babel/plugin-transform-spread" "^7.12.1" - "@babel/plugin-transform-sticky-regex" "^7.12.1" - "@babel/plugin-transform-template-literals" "^7.12.1" - "@babel/plugin-transform-typeof-symbol" "^7.12.1" - "@babel/plugin-transform-unicode-escapes" "^7.12.1" - "@babel/plugin-transform-unicode-regex" "^7.12.1" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.12.1" - core-js-compat "^3.6.2" - semver "^5.5.0" - -"@babel/preset-env@^7.4.5", "@babel/preset-env@^7.7.7": +"@babel/preset-env@^7.12.1", "@babel/preset-env@^7.4.5", "@babel/preset-env@^7.7.7": version "7.12.1" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.1.tgz#9c7e5ca82a19efc865384bb4989148d2ee5d7ac2" integrity sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg== @@ -3029,6 +2918,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/bcryptjs@^2.4.2": + version "2.4.2" + resolved "https://testnet.thegraph.com/npm-registry/@types%2fbcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae" + integrity sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ== + "@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": version "4.11.6" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" @@ -3084,6 +2978,13 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== +"@types/jsonwebtoken@^8.5.0": + version "8.5.0" + resolved "https://testnet.thegraph.com/npm-registry/@types%2fjsonwebtoken/-/jsonwebtoken-8.5.0.tgz#2531d5e300803aa63279b232c014acf780c981c5" + integrity sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg== + dependencies: + "@types/node" "*" + "@types/lodash@^4.14.149": version "4.14.162" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.162.tgz#65d78c397e0d883f44afbf1f7ba9867022411470" @@ -3900,7 +3801,7 @@ array-differ@^2.0.3: array-each@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" + resolved "https://testnet.thegraph.com/npm-registry/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8= array-equal@^1.0.0: @@ -3939,7 +3840,7 @@ array-includes@^3.0.3, array-includes@^3.1.1: array-slice@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" + resolved "https://testnet.thegraph.com/npm-registry/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== array-union@^1.0.1, array-union@^1.0.2: @@ -4676,7 +4577,7 @@ buffer-crc32@~0.2.3: buffer-equal-constant-time@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + resolved "https://testnet.thegraph.com/npm-registry/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= buffer-fill@^1.0.0: @@ -5348,7 +5249,7 @@ commander@^4.0.1, commander@^4.1.1: commander@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + resolved "https://testnet.thegraph.com/npm-registry/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== common-tags@^1.8.0: @@ -6103,7 +6004,7 @@ dateformat@^3.0.0, dateformat@^3.0.3: db-errors@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/db-errors/-/db-errors-0.2.3.tgz#a6a38952e00b20e790f2695a6446b3c65497ffa2" + resolved "https://testnet.thegraph.com/npm-registry/db-errors/-/db-errors-0.2.3.tgz#a6a38952e00b20e790f2695a6446b3c65497ffa2" integrity sha512-OOgqgDuCavHXjYSJoV2yGhv6SeG8nk42aoCSoyXLZUH7VwFG27rxbavU1z+VrZbZjphw5UkDQwUlD21MwZpUng== debug-fabulous@0.0.X: @@ -6138,7 +6039,7 @@ debug@3.2.6, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: debug@4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + resolved "https://testnet.thegraph.com/npm-registry/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" @@ -6376,7 +6277,7 @@ destroy@~1.0.4: detect-file@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + resolved "https://testnet.thegraph.com/npm-registry/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= detect-indent@^5.0.0: @@ -6635,7 +6536,7 @@ ecc-jsbn@~0.1.1: ecdsa-sig-formatter@1.0.11: version "1.0.11" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + resolved "https://testnet.thegraph.com/npm-registry/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== dependencies: safe-buffer "^5.0.1" @@ -7108,7 +7009,7 @@ eslint@^7.12.1: esm@^3.2.25: version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" + resolved "https://testnet.thegraph.com/npm-registry/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== espree@^6.1.2: @@ -7542,7 +7443,7 @@ expand-range@^1.8.1: expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + resolved "https://testnet.thegraph.com/npm-registry/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= dependencies: homedir-polyfill "^1.0.1" @@ -7938,7 +7839,7 @@ find-up@^2.0.0, find-up@^2.1.0: findup-sync@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + resolved "https://testnet.thegraph.com/npm-registry/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== dependencies: detect-file "^1.0.0" @@ -7948,7 +7849,7 @@ findup-sync@^3.0.0: fined@^1.0.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b" + resolved "https://testnet.thegraph.com/npm-registry/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b" integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng== dependencies: expand-tilde "^2.0.2" @@ -7964,7 +7865,7 @@ first-chunk-stream@^1.0.0: flagged-respawn@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" + resolved "https://testnet.thegraph.com/npm-registry/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== flat-cache@^2.0.1: @@ -8032,7 +7933,7 @@ for-own@^0.1.3, for-own@^0.1.4: for-own@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + resolved "https://testnet.thegraph.com/npm-registry/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= dependencies: for-in "^1.0.1" @@ -8305,7 +8206,7 @@ get-value@^2.0.3, get-value@^2.0.6: getopts@2.2.5: version "2.2.5" - resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" + resolved "https://testnet.thegraph.com/npm-registry/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA== getpass@^0.1.1: @@ -8464,7 +8365,7 @@ global-modules@2.0.0: global-modules@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + resolved "https://testnet.thegraph.com/npm-registry/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== dependencies: global-prefix "^1.0.1" @@ -8473,7 +8374,7 @@ global-modules@^1.0.0: global-prefix@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + resolved "https://testnet.thegraph.com/npm-registry/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= dependencies: expand-tilde "^2.0.2" @@ -9282,7 +9183,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -9383,7 +9284,7 @@ internal-ip@^4.3.0: interpret@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" + resolved "https://testnet.thegraph.com/npm-registry/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== invariant@^2.2.2, invariant@^2.2.4: @@ -9430,7 +9331,7 @@ is-absolute-url@^3.0.3: is-absolute@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + resolved "https://testnet.thegraph.com/npm-registry/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== dependencies: is-relative "^1.0.0" @@ -9803,7 +9704,7 @@ is-regexp@^1.0.0: is-relative@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + resolved "https://testnet.thegraph.com/npm-registry/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== dependencies: is-unc-path "^1.0.0" @@ -9868,7 +9769,7 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: is-unc-path@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + resolved "https://testnet.thegraph.com/npm-registry/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== dependencies: unc-path-regex "^0.1.2" @@ -10595,7 +10496,7 @@ jsonparse@^1.2.0: jsonwebtoken@^8.5.1: version "8.5.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + resolved "https://testnet.thegraph.com/npm-registry/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== dependencies: jws "^3.2.2" @@ -10634,7 +10535,7 @@ just-extend@^4.0.2: jwa@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + resolved "https://testnet.thegraph.com/npm-registry/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== dependencies: buffer-equal-constant-time "1.0.1" @@ -10643,7 +10544,7 @@ jwa@^1.4.1: jws@^3.2.2: version "3.2.2" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + resolved "https://testnet.thegraph.com/npm-registry/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== dependencies: jwa "^1.4.1" @@ -10705,25 +10606,22 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -knex@^0.21.0: - version "0.21.6" - resolved "https://registry.yarnpkg.com/knex/-/knex-0.21.6.tgz#3e80ae38199c41e2dfe7d1d1a38470b1de1c93e7" - integrity sha512-gFB2q4MamYCEqzCPNgK7DMcyyAxoHhhSDnPsNDJo50Gor5ibI2n5bNRW768IG5S06k6nE3Gik5/kcoTmbsYbZw== +knex@^0.21.12: + version "0.21.12" + resolved "https://testnet.thegraph.com/npm-registry/knex/-/knex-0.21.12.tgz#961bdb484311eb853030f6f49bd5bf9eca89dc51" + integrity sha512-AEyyiTM9p/x/Pb38TPZkvphKPmn8UWxP7MdIphzjAOielOfFFeU6pjP6y3M7UJ7rxrQsCrAYHwdonLQ3l1JCDw== dependencies: colorette "1.2.1" commander "^5.1.0" debug "4.1.1" esm "^3.2.25" getopts "2.2.5" - inherits "~2.0.4" interpret "^2.2.0" liftoff "3.1.0" lodash "^4.17.20" - mkdirp "^1.0.4" pg-connection-string "2.3.0" - tarn "^3.0.0" + tarn "^3.0.1" tildify "2.0.0" - uuid "^7.0.3" v8flags "^3.2.0" last-call-webpack-plugin@^3.0.0: @@ -10886,7 +10784,7 @@ levn@^0.4.1: liftoff@3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" + resolved "https://testnet.thegraph.com/npm-registry/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" integrity sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog== dependencies: extend "^3.0.0" @@ -11036,12 +10934,12 @@ lodash.get@^4.4.2: lodash.includes@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + resolved "https://testnet.thegraph.com/npm-registry/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= lodash.isboolean@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + resolved "https://testnet.thegraph.com/npm-registry/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: @@ -11051,7 +10949,7 @@ lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: lodash.isinteger@^4.0.4: version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + resolved "https://testnet.thegraph.com/npm-registry/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= lodash.ismatch@^4.4.0: @@ -11061,17 +10959,17 @@ lodash.ismatch@^4.4.0: lodash.isnumber@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + resolved "https://testnet.thegraph.com/npm-registry/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= lodash.isplainobject@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + resolved "https://testnet.thegraph.com/npm-registry/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= lodash.isstring@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + resolved "https://testnet.thegraph.com/npm-registry/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= lodash.keys@^4.0.0: @@ -11248,7 +11146,7 @@ make-fetch-happen@^5.0.0: make-iterator@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" + resolved "https://testnet.thegraph.com/npm-registry/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw== dependencies: kind-of "^6.0.2" @@ -11739,7 +11637,7 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*, mkdirp@^1.0.4: +mkdirp@*: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -12417,7 +12315,7 @@ object.assign@^4.1.0, object.assign@^4.1.1: object.defaults@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" + resolved "https://testnet.thegraph.com/npm-registry/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8= dependencies: array-each "^1.0.1" @@ -12454,7 +12352,7 @@ object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0 object.map@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37" + resolved "https://testnet.thegraph.com/npm-registry/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37" integrity sha1-z4Plncj8wK1fQlDh94s7gb2AHTc= dependencies: for-own "^1.0.0" @@ -12485,9 +12383,9 @@ object.values@^1.1.0, object.values@^1.1.1: function-bind "^1.1.1" has "^1.0.3" -objection@^2.1.3: +objection@^2.2.3: version "2.2.3" - resolved "https://registry.yarnpkg.com/objection/-/objection-2.2.3.tgz#7509620b75a6907227cfb6a3fc4135222bb2e749" + resolved "https://testnet.thegraph.com/npm-registry/objection/-/objection-2.2.3.tgz#7509620b75a6907227cfb6a3fc4135222bb2e749" integrity sha512-uNya9GuHlNeix7H0URthVE3+CmAlXmxkU69LAcRnncLjujJ8l1YX8JCB2GVSErTYS3Oc2xneF1ZWaR/MS8r63g== dependencies: ajv "^6.12.0" @@ -12867,7 +12765,7 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: parse-filepath@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" + resolved "https://testnet.thegraph.com/npm-registry/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE= dependencies: is-absolute "^1.0.0" @@ -13024,12 +12922,12 @@ path-parse@^1.0.6: path-root-regex@^0.1.0: version "0.1.2" - resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + resolved "https://testnet.thegraph.com/npm-registry/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0= path-root@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + resolved "https://testnet.thegraph.com/npm-registry/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc= dependencies: path-root-regex "^0.1.0" @@ -13100,37 +12998,30 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pg-connection-string@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" - integrity sha1-2hhHsglA5C7hSSvq9l1J2RskXfc= - pg-connection-string@2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.3.0.tgz#c13fcb84c298d0bfa9ba12b40dd6c23d946f55d6" + resolved "https://testnet.thegraph.com/npm-registry/pg-connection-string/-/pg-connection-string-2.3.0.tgz#c13fcb84c298d0bfa9ba12b40dd6c23d946f55d6" integrity sha512-ukMTJXLI7/hZIwTW7hGMZJ0Lj0S2XQBCJ4Shv4y1zgQ/vqVea+FLhzywvPj0ujSuofu+yA4MYHGZPTsgjBgJ+w== -pg-hstore@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/pg-hstore/-/pg-hstore-2.3.3.tgz#d1978c12a85359830b1388d3b0ff233b88928e96" - integrity sha512-qpeTpdkguFgfdoidtfeTho1Q1zPVPbtMHgs8eQ+Aan05iLmIs3Z3oo5DOZRclPGoQ4i68I1kCtQSJSa7i0ZVYg== - dependencies: - underscore "^1.7.0" +pg-connection-string@^2.4.0: + version "2.4.0" + resolved "https://testnet.thegraph.com/npm-registry/pg-connection-string/-/pg-connection-string-2.4.0.tgz#c979922eb47832999a204da5dbe1ebf2341b6a10" + integrity sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ== pg-int8@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== -pg-packet-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz#e45c3ae678b901a2873af1e17b92d787962ef914" - integrity sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg== +pg-pool@^3.2.2: + version "3.2.2" + resolved "https://testnet.thegraph.com/npm-registry/pg-pool/-/pg-pool-3.2.2.tgz#a560e433443ed4ad946b84d774b3f22452694dff" + integrity sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA== -pg-pool@^2.0.10: - version "2.0.10" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-2.0.10.tgz#842ee23b04e86824ce9d786430f8365082d81c4a" - integrity sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg== +pg-protocol@^1.3.0: + version "1.3.0" + resolved "https://testnet.thegraph.com/npm-registry/pg-protocol/-/pg-protocol-1.3.0.tgz#3c8fb7ca34dbbfcc42776ce34ac5f537d6e34770" + integrity sha512-64/bYByMrhWULUaCd+6/72c9PMWhiVFs3EVxl9Ct6a3v/U8+rKgqP2w+kKg/BIGgMJyB+Bk/eNivT32Al+Jghw== pg-types@^2.1.0: version "2.2.0" @@ -13143,19 +13034,18 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" -pg@^7.18.2: - version "7.18.2" - resolved "https://registry.yarnpkg.com/pg/-/pg-7.18.2.tgz#4e219f05a00aff4db6aab1ba02f28ffa4513b0bb" - integrity sha512-Mvt0dGYMwvEADNKy5PMQGlzPudKcKKzJds/VbOeZJpb6f/pI3mmoXX0JksPgI3l3JPP/2Apq7F36O63J7mgveA== +pg@^8.4.2: + version "8.4.2" + resolved "https://testnet.thegraph.com/npm-registry/pg/-/pg-8.4.2.tgz#2aa58166a23391e91d56a7ea57c6d99931c0642a" + integrity sha512-E9FlUrrc7w3+sbRmL1CSw99vifACzB2TjhMM9J5w9D1LIg+6un0jKkpHS1EQf2CWhKhec2bhrBLVMmUBDbjPRQ== dependencies: buffer-writer "2.0.0" packet-reader "1.0.0" - pg-connection-string "0.1.3" - pg-packet-stream "^1.1.0" - pg-pool "^2.0.10" + pg-connection-string "^2.4.0" + pg-pool "^3.2.2" + pg-protocol "^1.3.0" pg-types "^2.1.0" pgpass "1.x" - semver "4.3.2" pgpass@1.x: version "1.0.4" @@ -14739,7 +14629,7 @@ realpath-native@^1.1.0: rechoir@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + resolved "https://testnet.thegraph.com/npm-registry/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= dependencies: resolve "^1.1.6" @@ -15014,7 +14904,7 @@ resolve-cwd@^2.0.0: resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + resolved "https://testnet.thegraph.com/npm-registry/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= dependencies: expand-tilde "^2.0.0" @@ -15380,11 +15270,6 @@ semver-diff@^3.1.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" - integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= - semver@6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" @@ -16371,10 +16256,10 @@ tar@^4, tar@^4.0.2, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: safe-buffer "^5.1.2" yallist "^3.0.3" -tarn@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.0.tgz#a4082405216c0cce182b8b4cb2639c52c1e870d4" - integrity sha512-PKUnlDFODZueoA8owLehl8vLcgtA8u4dRuVbZc92tspDYZixjJL6TqYOmryf/PfP/EBX+2rgNcrj96NO+RPkdQ== +tarn@^3.0.1: + version "3.0.1" + resolved "https://testnet.thegraph.com/npm-registry/tarn/-/tarn-3.0.1.tgz#ebac2c6dbc6977d34d4526e0a7814200386a8aec" + integrity sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw== tdigest@^0.1.1: version "0.1.1" @@ -16542,7 +16427,7 @@ tildify@1.2.0: tildify@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a" + resolved "https://testnet.thegraph.com/npm-registry/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a" integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw== timed-out@^4.0.0, timed-out@^4.0.1: @@ -16869,7 +16754,7 @@ unbzip2-stream@^1.0.9: unc-path-regex@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + resolved "https://testnet.thegraph.com/npm-registry/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= undefsafe@^2.0.3: @@ -16884,11 +16769,6 @@ underscore@1.9.1: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== -underscore@^1.7.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.11.0.tgz#dd7c23a195db34267186044649870ff1bab5929e" - integrity sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw== - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -17179,11 +17059,6 @@ uuid@^3.0.1, uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - v8-compile-cache@^2.0.3: version "2.1.1" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"