diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..aa409cd --- /dev/null +++ b/.env.sample @@ -0,0 +1,4 @@ +DB_HOST= +DB_USER= +DB_NAME= +DB_PASS= diff --git a/.gitignore b/.gitignore index 5b3ad33..ddf2bf0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .next/ node_modules/ +.env diff --git a/api/index.js b/api/index.js index aeab217..e7a42b8 100644 --- a/api/index.js +++ b/api/index.js @@ -1,7 +1,8 @@ const router = require('express-promise-router')() +const pg = require('../db/pg') router.get('/', (req, res)=>{ - console.log('api request') + console.log(pg) res.json({test: true}) }) diff --git a/db/pg.js b/db/pg.js new file mode 100644 index 0000000..cbcf8bf --- /dev/null +++ b/db/pg.js @@ -0,0 +1,16 @@ +const { Pool } = require('pg'); +const debug = require('debug')('sos:pg'); + +const pool = new Pool({ + max: 20, + host: process.env.DB_HOST, + user: process.env.DB_USER, + database: process.env.DB_NAME, + password: process.env.DB_PASS +}); + +pool.on('error', err=>debug(err)); + +debug("Database ready"); + +module.exports = pool; diff --git a/db/sql/0-setup.sql b/db/sql/0-setup.sql new file mode 100644 index 0000000..167055c --- /dev/null +++ b/db/sql/0-setup.sql @@ -0,0 +1,6 @@ +CREATE database sos; +create user sos with encrypted password 'password'; +grant all privileges on database sos to sos; + +create extension if not exists "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS citext; diff --git a/db/sql/1-tables.sql b/db/sql/1-tables.sql new file mode 100644 index 0000000..4f15aab --- /dev/null +++ b/db/sql/1-tables.sql @@ -0,0 +1,139 @@ +create type "delivery_type_enum" as enum ('hand_shipped', 'easypost', 'hand_delivered'); +create type "transaction_state_enum" as enum ('started', 'completed', 'cancelled', 'expired'); +create type "payment_state_enum" as enum ('ks_reward', 'stripe', 'paypal', 'account_credit'); + +create table "user" ( + user_uuid uuid primary key default uuid_generate_v4(), + user_email citext unique not null, + user_email_confirmed boolean not null default false, + user_password_hash varchar(60), + user_time_registered timestamptz not null default now(), + user_time_email_confirmed timestamptz +); + +create table "login_link" ( + login_link_uuid uuid primary key default uuid_generate_v4(), + login_link_user_uuid uuid not null references "user" (user_uuid), + login_link_time_created timestamptz not null default now(), + login_link_timeout_length interval not null, + login_link_login_hash varchar(60) not null +); + +create table "cart" ( + cart_uuid uuid primary key default uuid_generate_v4() +); + +create table "session" ( + session_uuid uuid primary key default uuid_generate_v4(), + session_time_created timestamptz not null default now(), + session_time_last_active timestamptz not null default now(), + session_timeout_length interval not null, + session_ip_address varchar(50) not null, + session_user_agent varchar(500) not null, + session_referer varchar(500) not null, + session_user_uuid uuid not null references "user" (user_uuid), + session_originating_link uuid references "login_link" (login_link_uuid), + session_cart uuid references "cart" (cart_uuid) +); + +create table "item" ( + item_uuid uuid primary key default uuid_generate_v4(), + item_name text not null, + item_urlslug citext unique not null, + item_price_cents integer not null +); + +create table "cart_item" ( + cart_item_uuid uuid primary key default uuid_generate_v4(), + cart_item_item_uuid uuid not null references "item" (item_uuid), + cart_item_cart_uuid uuid not null references "cart" (cart_uuid), + cart_item_count integer not null default 1, + cart_item_time_added timestamptz not null default now() +); + +create table "address" ( + address_uuid uuid primary key default uuid_generate_v4(), + address_name text not null, + address_company text, + address_street1 text not null, + address_street2 text, + address_city text not null, + address_state text not null, + address_zip text not null, + address_country text not null, + address_phone text, + address_easypost_id text +); + +create table "delivery" ( + delivery_uuid uuid primary key default uuid_generate_v4(), + delivery_type delivery_type_enum not null, + unique (delivery_uuid, delivery_type) +); + +create table "delivery_hand_shipped" ( + delivery_uuid uuid not null, + delivery_type delivery_type_enum not null, + foreign key (delivery_uuid, delivery_type) references "delivery" (delivery_uuid, delivery_type), + + delivery_tracking_number text not null, + delivery_date_shipped timestamptz not null +); + +create table "delivery_easypost" ( + delivery_uuid uuid not null, + delivery_type delivery_type_enum not null, + foreign key (delivery_uuid, delivery_type) references "delivery" (delivery_uuid, delivery_type), + + delivery_tracking_number text not null, + delivery_date_shipped timestamptz not null, + delivery_easypost_id text not null +); + +create table "delivery_hand_delivered" ( + delivery_uuid uuid not null, + delivery_type delivery_type_enum not null, + foreign key (delivery_uuid, delivery_type) references "delivery" (delivery_uuid, delivery_type), + + delivery_description text not null, + delivery_date_delivered timestamptz not null +); + +create table "order" ( + order_uuid uuid primary key default uuid_generate_v4(), + order_number int not null, + order_start_time timestamptz not null default now(), + order_user_uuid uuid foreign key references "user" (user_uuid), + order_address_uuid uuid foreign key references "address" (address_uuid), + order_delivery_uuid uuid foreign key references "delivery" (delivery_uuid) +); + +create table "coupon" ( + coupon_uuid uuid primary key default uuid_generate_v4(), + coupon_code varchar(50) unique not null, + coupon_valid_until timestamptz not null, + coupon_free_shipping boolean not null default false, + coupon_number_allowed_uses integer not null default 1 check (coupon_number_allowed_uses > 0), + coupon_flat_discount_cents integer not null default 0 check (coupon_flat_discount_cents >= 0), + coupon_percent_discount integer not null default 0 check (coupon_percent_discount >= 0 and coupon_percent_discount <= 100), + coupon_per_sock_discount_cents integer not null default 0 check (coupon_per_sock_discount_cents >= 0), + coupon_number_of_socks_free integer not null default 0 check (coupon_number_of_socks_free >= 0) +); + +create table "transaction" ( + transaction_uuid uuid primary key default uuid_generate_v4(), + transaction_order_uuid uuid foreign key references "order" (order_uuid), + transaction_cart_uuid uuid foreign key references "cart" (cart_uuid), + transaction_coupon_uuid uuid foreign key references "transaction" (transaction_uuid), + transaction_start_time timestamptz not null default now(), + transaction_completion_time timestamptz, + transaction_payment_state transaction_state_enum, not null default 'started', + transaction_item_total_price integer not null, + transaction_coupon_effective_discount integer not null, + transaction_shipping_price integer not null +); + +create table "payment" ( + payment_uuid uuid primary key default uuid_generate_v4(), + payment_type payment_type_enum +) diff --git a/index.js b/index.js index 57b85ae..6ba1702 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ +require('dotenv').config() const express = require('express') const nextjs = require('next') const {promisify} = require('util') diff --git a/package-lock.json b/package-lock.json index 0e0829f..918d03e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1410,6 +1410,14 @@ "postcss-value-parser": "^4.0.2" } }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -1710,6 +1718,16 @@ "qs": "6.7.0", "raw-body": "2.4.0", "type-is": "~1.6.17" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } } }, "brace-expansion": { @@ -1829,6 +1847,11 @@ "resolved": "https://registry.npmjs.org/buffer-json/-/buffer-json-2.0.0.tgz", "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==" }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", @@ -2139,6 +2162,14 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } } } }, @@ -2460,11 +2491,18 @@ } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } } }, "decode-uri-component": { @@ -2585,6 +2623,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -2789,6 +2832,14 @@ "to-regex": "^3.0.1" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -2842,6 +2893,16 @@ "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } } }, "express-promise-router": { @@ -2997,6 +3058,16 @@ "parseurl": "~1.3.3", "statuses": "~1.5.0", "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } } }, "find-cache-dir": { @@ -3062,6 +3133,24 @@ "readable-stream": "^2.3.6" } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -3635,6 +3724,11 @@ } } }, + "join-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/join-js/-/join-js-1.0.2.tgz", + "integrity": "sha512-qhskW9ToRrUpsMhIxcp5aAIiGLqJA8ZGIBYquO6kKbFbp8h8cvlmG9+Q1HTRTt7Qxqm1HCRB3KQyMBwdQot//w==" + }, "js-levenshtein": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", @@ -4512,6 +4606,11 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -4633,6 +4732,68 @@ "sha.js": "^2.4.8" } }, + "pg": { + "version": "7.18.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.18.1.tgz", + "integrity": "sha512-1KtKBKg/zWrjEEv//klBbVOPGucuc7HHeJf6OEMueVcUeyF3yueHf+DvhVwBjIAe9/97RAydO/lWjkcMwssuEw==", + "requires": { + "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-types": "^2.1.0", + "pgpass": "1.x", + "semver": "4.3.2" + }, + "dependencies": { + "semver": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" + } + } + }, + "pg-connection-string": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", + "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-packet-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz", + "integrity": "sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg==" + }, + "pg-pool": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.10.tgz", + "integrity": "sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", + "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", + "requires": { + "split": "^1.0.0" + } + }, "picomatch": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", @@ -5205,6 +5366,29 @@ "uniq": "^1.0.1" } }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.4.tgz", + "integrity": "sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", @@ -5744,6 +5928,21 @@ "statuses": "~1.5.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -5840,6 +6039,14 @@ "use": "^3.1.0" }, "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", @@ -5999,6 +6206,14 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -6301,6 +6516,11 @@ "neo-async": "^2.6.0" } }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", diff --git a/package.json b/package.json index b41aaa2..bfee8ac 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "start": "next start", + "start": "node index.js", "dev": "next dev", "build": "next build" }, @@ -12,10 +12,15 @@ "license": "ISC", "devDependencies": {}, "dependencies": { + "axios": "^0.19.2", + "debug": "^4.1.1", + "dotenv": "^8.2.0", "express": "^4.17.1", "express-promise-router": "^3.0.3", + "join-js": "^1.0.2", "luxon": "^1.22.0", "next": "^9.2.1", + "pg": "^7.18.1", "react": "^16.12.0", "react-dom": "^16.12.0" }