Compare commits

...

3 Commits

@ -5,6 +5,7 @@ go 1.15
require (
github.com/go-chi/chi v1.5.4
github.com/go-chi/chi/v5 v5.0.2
github.com/go-chi/cors v1.2.0
github.com/go-chi/jwtauth/v5 v5.0.1
github.com/kelseyhightower/envconfig v1.4.0
github.com/lib/pq v1.10.0

@ -8,6 +8,8 @@ github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIu
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
github.com/go-chi/chi/v5 v5.0.2 h1:4xKeALZdMEsuI5s05PU2Bm89Uc5iM04qFubUCl5LfAQ=
github.com/go-chi/chi/v5 v5.0.2/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/jwtauth v1.2.0 h1:Z116SPpevIABBYsv8ih/AHYBHmd4EufKSKsLUnWdrTM=
github.com/go-chi/jwtauth/v5 v5.0.1 h1:eyJ6Yx5VphEfjkqpZ7+LJEWThzyIcF5aN2QVpgqSIu0=
github.com/go-chi/jwtauth/v5 v5.0.1/go.mod h1:+JtcRYGZsnA4+ur1LFlb4Bei3O9WeUzoMfDZWfUJuoY=

@ -97,12 +97,30 @@ func (s Stats) putLog(res http.ResponseWriter, req *http.Request) {
return
}
if in.Value == 0 {
fail.Payload = "Must specify non zero value"
fail.Status = http.StatusExpectationFailed
fail.Write(res)
return
}
if in.Type == "" {
fail.Payload = "Must specify 'Weight', 'Calories', or 'Height' for type"
fail.Status = http.StatusExpectationFailed
fail.Write(res)
return
}
if in.RecordedTS.Equal(time.Time{}) {
in.RecordedTS = time.Now().UTC()
}
if err := s.Conn.AddLog(userId, in.StatLog); err != nil {
log.Println(err)
fail.Write(res)
return
}
APIResp{Success: true}.Write(res)
APIResp{Success: true, Payload: in.StatLog}.Write(res)
}

@ -139,10 +139,12 @@ func (u UserHandler) login(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Authorization", fmt.Sprintf("Bearer %s", token))
http.SetCookie(res, &http.Cookie{
Name: "jwt",
Value: token,
Path: "/v1/api/",
Expires: time.Now().Add(duration),
Name: "jwt",
Value: token,
Domain: "localhost",
Path: "/",
SameSite: http.SameSiteLaxMode,
Expires: time.Now().Add(duration),
})
APIResp{

@ -3,6 +3,7 @@ package services
import (
"encoding/base64"
"errors"
"fmt"
"net/http"
"github.com/go-chi/jwtauth/v5"
@ -36,9 +37,13 @@ func NewJWTVerifier() func(http.Handler) http.Handler {
func GenerateJWT(u User) string {
_, tokenString, _ := tokenEncoder.Encode(map[string]interface{}{
"id": u.ID,
"x-Hasura-Role": "user",
"x-Hasura-User-Id": u.ID,
"id": u.ID,
"https://hasura.io/jwt/claims": map[string]interface{}{
"x-hasura-allowed-roles": []string{"user"},
"X-hasura-role": "user",
"x-hasura-default-role": "user",
"x-hasura-user-id": fmt.Sprintf("%d", u.ID),
},
})
return tokenString
}

@ -9,6 +9,7 @@ import (
"git.vdhsn.com/adam/bodytrack/internal/services"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
"github.com/kelseyhightower/envconfig"
)
@ -42,6 +43,16 @@ func main() {
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Timeout(60 * time.Second))
r.Use(cors.Handler(cors.Options{
// AllowedOrigins: []string{"https://foo.com"}, // Use this to allow specific origin hosts
AllowedOrigins: []string{"https://*", "http://*", "http://localhost:5000"},
// AllowOriginFunc: func(r *http.Request, origin string) bool { return true },
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: true,
MaxAge: 300,
}))
r.Use(func(h http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
r.Header.Set("Content-Type", "application/json; utf-8")

@ -1,8 +1,8 @@
BIN := .bin
start: $(BIN)/api
start: clean $(BIN)/api
BODYTRACK_API_HOST="localhost" \
BODYTRACK_API_JWT_SECRET="ducks123" \
BODYTRACK_API_JWT_SECRET="D*zvWkiDHi#j&Rx7c#NaPbd*pk%ayjsX" \
BODYTRACK_API_PG_HOST="localhost" \
BODYTRACK_API_PG_USERNAME="api" \
BODYTRACK_API_PG_PASSWORD="api-user" \

@ -19,6 +19,7 @@ services:
- HASURA_GRAPHQL_ENABLE_CONSOLE=true
- HASURA_GRAPHQL_ADMIN_SECRET=bodytrack-graphql
- HASURA_GRAPHQL_UNAUTHORIZED_ROLE=anonymous
- "HASURA_GRAPHQL_JWT_SECRET={\"header\": { \"type\": \"cookie\", \"name\":\"jwt\"}, \"type\": \"HS256\", \"key\":\"D*zvWkiDHi#j&Rx7c#NaPbd*pk%ayjsX\"}"
ports:
- 8080:8080
depends_on:

@ -0,0 +1,21 @@
export const doFetch = async function({ url, method = "GET", body = null, headers = {} }) {
try {
const response = await fetch(url, {
method,
body: !!body ? JSON.stringify(body) : undefined,
mode: 'cors',
credentials: 'include',
headers: {
...headers,
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('jwt')}`
}
})
return await response.json();
} catch (error) {
return { success: false, payload: error }
}
}

@ -21,12 +21,15 @@
"postcss-preset-env": "^6.7.0",
"prettier": "^2.1.2",
"prettier-plugin-svelte": "^1.4.0",
"svelte": "^3.29.0",
"svelte": "^3.20.x",
"tailwindcss": "^1.8.10",
"tailwindcss-font-inter": "^1.0.8"
},
"dependencies": {
"@urql/svelte": "^1.2.1",
"graphql": "^15.5.0"
"d3": "^6.7.0",
"graphql": "^15.5.0",
"js-cookie": "^2.2.1",
"svelte-routing": "^1.6.0"
}
}

@ -1,40 +1,36 @@
<script>
import { initClient, query, operationStore } from '@urql/svelte';
import ExerciseCard from './components/ExerciseCard.svelte';
import Button from './components/Button.svelte';
import { initClient } from '@urql/svelte';
import { Router, Route } from 'svelte-routing';
import user from './stores/user.js';
import Nav from './components/Nav.svelte';
import Authenticate from './pages/Authenticate.svelte';
import Exercises from './pages/Exercises.svelte';
import Stats from './pages/Stats.svelte';
initClient({
url: 'http://localhost:8080/v1/graphql',
});
const exdata = operationStore(`
query {
workouts_exercises {
name
instructions
muscletarget
tutoriallink
}
}`, {}, {requestPolicy: 'cache-first'});
query(exdata);
user.load();
export let url = "";
</script>
<style>
#root {
@apply flex flex-col flex-grow justify-center items-center px-4 w-full pt-5;
}
</style>
<div class="flex flex-col font-inter flex flex-grow justify-center items-center">
<h1 class="text-xl bold">Cool asf</h1>
<Button on:button-click={load}>Click me</Button>
{#if $exdata.fetching}
<p>Loading...</p>
{:else if $exdata.error}
<p>{$exdata.error.message}</p>
{:else}
<ul>
{#each $exdata.data.workouts_exercises as ex}
<li>
<ExerciseCard exercise="{ex}" />
</li>
{/each}
</ul>
{/if}
</div>
<Router url="{url}">
<div id="root" class="font-inter">
<Nav>
<h1 class="text-bold text-gray-800">BodyTrack</h1>
</Nav>
<section class="w-full h-full">
<Route path="/" component={Exercises} />
<Route path="/login" component={Authenticate} />
<Route path="/stats" component={Stats} />
</section>
</div>
</Router>

@ -9,7 +9,15 @@
</script>
<style>
button {
@apply bg-gray-800 py-2 px-4 rounded-md text-gray-200 text-xs;
}
button:hover {
@apply bg-gray-700;
}
</style>
<button class="bg-gray-800 py-2 px-4 rounded-md text-gray-200 hover:bg-gray-700" on:click={onClick}>
<button on:click={onClick}>
<slot/>
</button>

@ -2,7 +2,6 @@
export let exercise;
let instructions = exercise.instructions.replaceAll('\\n', '<br>');
console.log(instructions);
</script>
<article id="{exercise.name}" class="bg-gray-100 rounded-l p-8 animate-">
<header class="text-lg my-1">

@ -0,0 +1,9 @@
<script>
import { Link } from 'svelte-routing';
export let href = "";
export let target = "";
</script>
<Link to="{href}" class="underline hover:text-gray-600 visited:text-gray-700" href="{href}" target="{target}" >
<slot/>
</Link>

@ -1,2 +1,39 @@
<script>
import Link from './Link.svelte';
import Button from './Button.svelte';
import user from '../stores/user.js';
import { onDestroy } from 'svelte';
let isLoggedIn = false;
const unsubscribe = user.subscribe(u => { isLoggedIn = u.loggedIn });
onDestroy(unsubscribe);
</script>
<style>
nav {
@apply flex w-full justify-between ;
}
ul {
@apply flex flex-row px-5;
}
li {
@apply px-1;
}
</style>
<nav>
<header class="flex-grow"> <Link href="/"><slot /></Link> </header>
<section class="flex">
<ul>
<li><Link href="stats">Stats</Link></li>
<li><Link href="workouts">Workouts</Link></li>
<li><Link href="/">Exercise Index</Link></li>
</ul>
<section>
{#if isLoggedIn}
<Button on:button-click={user.logout}><Link href="/">Log out</Link></Button>
{:else}
<Button><Link href="login">Log in/Sign up</Link></Button>
{/if}
</section>
</section>
</nav>

@ -1,6 +1,5 @@
if (module.hot) {
module.hot.accept()
}
import App from './App.svelte';

@ -0,0 +1,71 @@
<script>
import { onMount } from 'svelte';
import { fade } from 'svelte/transition';
import Button from '../components/Button.svelte';
import user from '../stores/user.js';
export let showLogin = true;
let email= "";
let password= "";
let confirmPassword= "";
let actionLabel = showLogin ? "Login" : "Sign up"
let inverseLabel = !showLogin ? "Login" : "Sign up"
let error = null;
const toggle = () => showLogin = !showLogin;
async function authenticate(){
error = null;
await user.login({ email, password });
console.log(user);
location.replace("/stats");
}
</script>
<style>
section {
min-width: 500px;
}
input {
@apply border-solid border-2 border-gray-700 flex-grow;
}
form label {
@apply flex flex-col py-2;
}
form label span {
@apply w-full;
}
</style>
<div class="w-full h-full flex justify-center flex-col content-center items-center" >
<h2>{actionLabel}</h2>
<form on:submit|preventDefault={authenticate} transition:fade class="flex flex-col p-5">
<label>
<span>Email:</span>
<input id="email" bind:value={email}>
</label>
<label>
<span>Password:</span>
<input id="password" bind:value={password} type="password">
</label>
{#if !showLogin}
<label>
<span>Confirm Password:</span>
<input id="confirm-password" bind:value={confirmPassword} type="password">
</label>
{/if}
<section class="flex justify-end">
<span class="pr-2"><Button>{actionLabel}</Button></span>
<span ><Button on:button-click={toggle}>{inverseLabel}</Button></span>
</section>
{#if error}
<section class="text-red-700">
{error}
</section>
{/if}
</form>
</div>

@ -0,0 +1,40 @@
<script>
import { query, operationStore } from '@urql/svelte';
import { fade } from 'svelte/transition';
import ExerciseCard from '../components/ExerciseCard.svelte';
const exdata = operationStore(
`
query {
workouts_exercises {
id
name
instructions
muscletarget
tutoriallink
}
}`,
{},
{ requestPolicy: 'cache-first' }
);
query(exdata);
</script>
<div id="Exercises" class="font-inter">
<h2>Exercises</h2>
{#if $exdata.fetching}
<p>Loading...</p>
{:else if $exdata.error}
<p>{$exdata.error.message}</p>
{:else}
<ul >
{#each $exdata.data.workouts_exercises as ex}
<li transition:fade>
<ExerciseCard exercise="{ex}" />
</li>
{/each}
</ul>
{/if}
</div>

@ -0,0 +1,53 @@
<script>
import { onMount } from 'svelte';
import stats from '../stores/stats.js';
import * as d3 from 'd3';
import { query } from '@urql/svelte';
const statsQ = stats.getStat({ start: '2020-01-01T00:00:00', types: ['Weight'] });
let el;
query(statsQ);
let mounted = false;
function render(data, isLoading){
if (isLoading || !mounted)
return;
d3.select(el)
.selectAll("div")
.data(data.stats_log)
.enter()
.append("div")
.style("width", function(d) {
return d.value + "px";
})
.text(function(d) {
return d.recordedts;
});
}
$: render($statsQ.data, $statsQ.fetching);
onMount(async () => {
mounted = true;
})
</script>
<style>
.chart :global(div) {
font: 10px sans-serif;
background-color: steelblue;
text-align: right;
padding: 3px;
margin: 1px;
color: white;
}
</style>
<h2>Statistics</h2>
<section>
<div bind:this={el} class="chart"></div>
</section>

@ -0,0 +1,49 @@
import { query, operationStore, subscription } from '@urql/svelte';
import { writable } from 'svelte/store';
import { doFetch } from '../../helpers';
const defaultState = {loggedIn:false, loading:false, profile: null, error: null}
const { subscribe, set, update } = writable(defaultState);
async function logStat({ type = "Weight", recordedTs, value }) {
return await doFetch({
url: 'http://localhost/v1/api/stats',
method: 'PUT',
body: {
type,
recordedTs,
value
}
});
}
const getStat = ({ start = '2020-01-01T00:00:00',types = ['Weight', 'Calories', 'Height'] }) =>
operationStore(`
query GetStats($types: [logtype!] = ["Weight"], $start: timestamp! = "2020-01-01T00:00:00") {
stats_log(where: {
logtype: {_in: $types },
recordedts: {_gte: $start}
},
order_by: { recordedts: desc }) {
value
logtype
recordedts
id
}
}`,
{ start, types },
{
requestPolicy: "cache-and-network",
fetchOptions: {
headers: {
'Authorization': `Bearer ${localStorage.getItem('jwt')}`
}
}
});
export default { subscribe, logStat, getStat };

@ -0,0 +1,63 @@
import Cookies from 'js-cookie';
import { writable } from 'svelte/store';
import { doFetch } from '../../helpers';
const defaultState = { loggedIn: false, loading: false, profile: null, error: null, token: null };
const { subscribe, set, update } = writable(defaultState);
const logout = () => {
localStorage.removeItem('jwt');
Cookies.remove('jwt', { path: '/', domain: 'localhost' });
set(defaultState);
location.pathname !== "/" && location.replace("/");
}
const load = async () => {
try {
update(p => ({ ...p, loading: true}));
const {success, payload} = await doFetch({ url:"http://localhost:3000/v1/api/user" });
if (!success) {
set({ ...defaultState, error: payload });
logout();
return
}
update(() => ({ ...defaultState, loggedIn:true, profile: payload, token: localStorage.getItem('jwt') }));
} catch (e) {
set({ ...defaultState, error: e.message });
logout();
}
}
const login = async ({ email, password }) => {
try {
update(p => ({ ...p, loading: true}));
const { success, payload } = await doFetch({
url: "http://localhost:3000/v1/api/user/auth",
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: { email, password }
});
if (!success) {
set({ ...defaultState, error: payload });
logout();
return
}
set({ ...defaultState, loggedIn:true, profile: payload.profile, token: payload.token });
localStorage.setItem('jwt', payload.token)
} catch (e) {
set({ ...defaultState, error: e.message });
console.trace(e);
}
}
export default { subscribe, login, logout, load };

@ -1632,7 +1632,7 @@ command-exists@^1.2.6:
resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.8.tgz#715acefdd1223b9c9b37110a149c6392c2852291"
integrity sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0:
commander@2, commander@^2.11.0, commander@^2.19.0, commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -1981,6 +1981,250 @@ cssstyle@^1.1.1:
dependencies:
cssom "0.3.x"
d3-array@2, d3-array@>=2.5, d3-array@^2.3.0:
version "2.12.1"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81"
integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==
dependencies:
internmap "^1.0.0"
d3-axis@2:
version "2.1.0"
resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-2.1.0.tgz#978db534092711117d032fad5d733d206307f6a0"
integrity sha512-z/G2TQMyuf0X3qP+Mh+2PimoJD41VOCjViJzT0BHeL/+JQAofkiWZbWxlwFGb1N8EN+Cl/CW+MUKbVzr1689Cw==
d3-brush@2:
version "2.1.0"
resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-2.1.0.tgz#adadfbb104e8937af142e9a6e2028326f0471065"
integrity sha512-cHLLAFatBATyIKqZOkk/mDHUbzne2B3ZwxkzMHvFTCZCmLaXDpZRihQSn8UNXTkGD/3lb/W2sQz0etAftmHMJQ==
dependencies:
d3-dispatch "1 - 2"
d3-drag "2"
d3-interpolate "1 - 2"
d3-selection "2"
d3-transition "2"
d3-chord@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-2.0.0.tgz#32491b5665391180560f738e5c1ccd1e3c47ebae"
integrity sha512-D5PZb7EDsRNdGU4SsjQyKhja8Zgu+SHZfUSO5Ls8Wsn+jsAKUUGkcshLxMg9HDFxG3KqavGWaWkJ8EpU8ojuig==
dependencies:
d3-path "1 - 2"
"d3-color@1 - 2", d3-color@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e"
integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==
d3-contour@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-2.0.0.tgz#80ee834988563e3bea9d99ddde72c0f8c089ea40"
integrity sha512-9unAtvIaNk06UwqBmvsdHX7CZ+NPDZnn8TtNH1myW93pWJkhsV25JcgnYAu0Ck5Veb1DHiCv++Ic5uvJ+h50JA==
dependencies:
d3-array "2"
d3-delaunay@5:
version "5.3.0"
resolved "https://registry.yarnpkg.com/d3-delaunay/-/d3-delaunay-5.3.0.tgz#b47f05c38f854a4e7b3cea80e0bb12e57398772d"
integrity sha512-amALSrOllWVLaHTnDLHwMIiz0d1bBu9gZXd1FiLfXf8sHcX9jrcj81TVZOqD4UX7MgBZZ07c8GxzEgBpJqc74w==
dependencies:
delaunator "4"
"d3-dispatch@1 - 2", d3-dispatch@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-2.0.0.tgz#8a18e16f76dd3fcaef42163c97b926aa9b55e7cf"
integrity sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==
d3-drag@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-2.0.0.tgz#9eaf046ce9ed1c25c88661911c1d5a4d8eb7ea6d"
integrity sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==
dependencies:
d3-dispatch "1 - 2"
d3-selection "2"
"d3-dsv@1 - 2", d3-dsv@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-2.0.0.tgz#b37b194b6df42da513a120d913ad1be22b5fe7c5"
integrity sha512-E+Pn8UJYx9mViuIUkoc93gJGGYut6mSDKy2+XaPwccwkRGlR+LO97L2VCCRjQivTwLHkSnAJG7yo00BWY6QM+w==
dependencies:
commander "2"
iconv-lite "0.4"
rw "1"
"d3-ease@1 - 2", d3-ease@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-2.0.0.tgz#fd1762bfca00dae4bacea504b1d628ff290ac563"
integrity sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==
d3-fetch@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-2.0.0.tgz#ecd7ef2128d9847a3b41b548fec80918d645c064"
integrity sha512-TkYv/hjXgCryBeNKiclrwqZH7Nb+GaOwo3Neg24ZVWA3MKB+Rd+BY84Nh6tmNEMcjUik1CSUWjXYndmeO6F7sw==
dependencies:
d3-dsv "1 - 2"
d3-force@2:
version "2.1.1"
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-2.1.1.tgz#f20ccbf1e6c9e80add1926f09b51f686a8bc0937"
integrity sha512-nAuHEzBqMvpFVMf9OX75d00OxvOXdxY+xECIXjW6Gv8BRrXu6gAWbv/9XKrvfJ5i5DCokDW7RYE50LRoK092ew==
dependencies:
d3-dispatch "1 - 2"
d3-quadtree "1 - 2"
d3-timer "1 - 2"
"d3-format@1 - 2", d3-format@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767"
integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==
d3-geo@2:
version "2.0.1"
resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-2.0.1.tgz#2437fdfed3fe3aba2812bd8f30609cac83a7ee39"
integrity sha512-M6yzGbFRfxzNrVhxDJXzJqSLQ90q1cCyb3EWFZ1LF4eWOBYxFypw7I/NFVBNXKNqxv1bqLathhYvdJ6DC+th3A==
dependencies:
d3-array ">=2.5"
d3-hierarchy@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz#dab88a58ca3e7a1bc6cab390e89667fcc6d20218"
integrity sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw==
"d3-interpolate@1 - 2", "d3-interpolate@1.2.0 - 2", d3-interpolate@2:
version "2.0.1"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163"
integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==
dependencies:
d3-color "1 - 2"
"d3-path@1 - 2", d3-path@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-2.0.0.tgz#55d86ac131a0548adae241eebfb56b4582dd09d8"
integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==
d3-polygon@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-2.0.0.tgz#13608ef042fbec625ba1598327564f03c0396d8e"
integrity sha512-MsexrCK38cTGermELs0cO1d79DcTsQRN7IWMJKczD/2kBjzNXxLUWP33qRF6VDpiLV/4EI4r6Gs0DAWQkE8pSQ==
"d3-quadtree@1 - 2", d3-quadtree@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-2.0.0.tgz#edbad045cef88701f6fee3aee8e93fb332d30f9d"
integrity sha512-b0Ed2t1UUalJpc3qXzKi+cPGxeXRr4KU9YSlocN74aTzp6R/Ud43t79yLLqxHRWZfsvWXmbDWPpoENK1K539xw==
d3-random@2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-2.2.2.tgz#5eebd209ef4e45a2b362b019c1fb21c2c98cbb6e"
integrity sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw==
d3-scale-chromatic@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-2.0.0.tgz#c13f3af86685ff91323dc2f0ebd2dabbd72d8bab"
integrity sha512-LLqy7dJSL8yDy7NRmf6xSlsFZ6zYvJ4BcWFE4zBrOPnQERv9zj24ohnXKRbyi9YHnYV+HN1oEO3iFK971/gkzA==
dependencies:
d3-color "1 - 2"
d3-interpolate "1 - 2"
d3-scale@3:
version "3.3.0"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3"
integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ==
dependencies:
d3-array "^2.3.0"
d3-format "1 - 2"
d3-interpolate "1.2.0 - 2"
d3-time "^2.1.1"
d3-time-format "2 - 3"
d3-selection@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-2.0.0.tgz#94a11638ea2141b7565f883780dabc7ef6a61066"
integrity sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==
d3-shape@2:
version "2.1.0"
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-2.1.0.tgz#3b6a82ccafbc45de55b57fcf956c584ded3b666f"
integrity sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA==
dependencies:
d3-path "1 - 2"
"d3-time-format@2 - 3", d3-time-format@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6"
integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==
dependencies:
d3-time "1 - 2"
"d3-time@1 - 2", d3-time@2, d3-time@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682"
integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==
dependencies:
d3-array "2"
"d3-timer@1 - 2", d3-timer@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-2.0.0.tgz#055edb1d170cfe31ab2da8968deee940b56623e6"
integrity sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==
d3-transition@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-2.0.0.tgz#366ef70c22ef88d1e34105f507516991a291c94c"
integrity sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==
dependencies:
d3-color "1 - 2"
d3-dispatch "1 - 2"
d3-ease "1 - 2"
d3-interpolate "1 - 2"
d3-timer "1 - 2"
d3-zoom@2:
version "2.0.0"
resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-2.0.0.tgz#f04d0afd05518becce879d04709c47ecd93fba54"
integrity sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==
dependencies:
d3-dispatch "1 - 2"
d3-drag "2"
d3-interpolate "1 - 2"
d3-selection "2"
d3-transition "2"
d3@^6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/d3/-/d3-6.7.0.tgz#adac458597b4a2cafe8e08cf30948af0c95cd61f"
integrity sha512-hNHRhe+yCDLUG6Q2LwvR/WdNFPOJQ5VWqsJcwIYVeI401+d2/rrCjxSXkiAdIlpx7/73eApFB4Olsmh3YN7a6g==
dependencies:
d3-array "2"
d3-axis "2"
d3-brush "2"
d3-chord "2"
d3-color "2"
d3-contour "2"
d3-delaunay "5"
d3-dispatch "2"
d3-drag "2"
d3-dsv "2"
d3-ease "2"
d3-fetch "2"
d3-force "2"
d3-format "2"
d3-geo "2"
d3-hierarchy "2"
d3-interpolate "2"
d3-path "2"
d3-polygon "2"
d3-quadtree "2"
d3-random "2"
d3-scale "3"
d3-scale-chromatic "2"
d3-selection "2"
d3-shape "2"
d3-time "2"
d3-time-format "3"
d3-timer "2"
d3-transition "2"
d3-zoom "2"
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@ -2029,6 +2273,11 @@ decode-uri-component@^0.2.0:
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
dedent-js@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dedent-js/-/dedent-js-1.0.1.tgz#bee5fb7c9e727d85dffa24590d10ec1ab1255305"
integrity sha1-vuX7fJ5yfYXf+iRZDRDsGrElUwU=
deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@ -2075,6 +2324,11 @@ defined@^1.0.0:
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
delaunator@4:
version "4.0.1"
resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-4.0.1.tgz#3d779687f57919a7a418f8ab947d3bddb6846957"
integrity sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag==
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@ -2828,7 +3082,7 @@ https-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
iconv-lite@0.4.24:
iconv-lite@0.4, iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@ -2903,6 +3157,11 @@ inherits@2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
internmap@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95"
integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==
invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@ -3155,6 +3414,11 @@ isstream@~0.1.2:
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
js-cookie@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -3385,6 +3649,13 @@ loose-envify@^1.0.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lower-case@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
dependencies:
tslib "^2.0.3"
magic-string@^0.22.4:
version "0.22.5"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
@ -3563,6 +3834,14 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
no-case@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
dependencies:
lower-case "^2.0.2"
tslib "^2.0.3"
node-addon-api@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.1.tgz#cf813cd69bb8d9100f6bdca6755fc268f54ac492"
@ -3971,6 +4250,14 @@ parseurl@~1.3.3:
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
pascal-case@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
dependencies:
no-case "^3.0.4"
tslib "^2.0.3"
pascalcase@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
@ -5120,6 +5407,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^3.0.0"
inherits "^2.0.1"
rw@1:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
@ -5540,7 +5832,22 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
svelte@^3.29.0:
svelte-routing@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/svelte-routing/-/svelte-routing-1.6.0.tgz#cdfed6b665d4a851f3d7e532e16bfbb318ce5294"
integrity sha512-+DbrSGttLA6lan7oWFz1MjyGabdn3tPRqn8Osyc471ut2UgCrzM5x1qViNMc2gahOP6fKbKK1aNtZMJEQP2vHQ==
dependencies:
svelte2tsx "^0.1.157"
svelte2tsx@^0.1.157:
version "0.1.186"
resolved "https://registry.yarnpkg.com/svelte2tsx/-/svelte2tsx-0.1.186.tgz#cf076d34137a3dcbcc043e2f4acb33521e33b592"
integrity sha512-E4BmTNmIg6yHEqazhcQ8S60GI7AaV2JKf2y5deOyr3o2zpow4gGyz7yE0uSnFDdqp2iafCD7PImWZ/v1R6uQVw==
dependencies:
dedent-js "^1.0.1"
pascal-case "^3.1.1"
svelte@^3.20.x:
version "3.37.0"
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.37.0.tgz#dc7cd24bcc275cdb3f8c684ada89e50489144ccd"
integrity sha512-TRF30F4W4+d+Jr2KzUUL1j8Mrpns/WM/WacxYlo5MMb2E5Qy2Pk1Guj6GylxsW9OnKQl1tnF8q3hG/hQ3h6VUA==
@ -5707,6 +6014,11 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"
tslib@^2.0.3:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c"
integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"

Loading…
Cancel
Save