master 32d7b7111699 cached
69 files
48.3 KB
15.2k tokens
73 symbols
1 requests
Download .txt
Repository: braydenwerner/Wern-Fullstack-Template
Branch: master
Commit: 32d7b7111699
Files: 69
Total size: 48.3 KB

Directory structure:
gitextract_cbg5532v/

├── .prettierrc.js
├── LICENSE
├── README.md
├── client/
│   ├── .babelrc
│   ├── .eslintignore
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── codegen.yml
│   ├── next-env.d.ts
│   ├── package.json
│   ├── src/
│   │   ├── components/
│   │   │   ├── Components.txt
│   │   │   ├── elements/
│   │   │   │   ├── Nav/
│   │   │   │   │   └── Nav.tsx
│   │   │   │   ├── ThemeToggle/
│   │   │   │   │   ├── ThemeToggle.styled.ts
│   │   │   │   │   └── ThemeToggle.tsx
│   │   │   │   └── index.ts
│   │   │   └── modules/
│   │   │       └── index.ts
│   │   ├── config/
│   │   │   └── config.ts
│   │   ├── generated/
│   │   │   └── graphql.tsx
│   │   ├── graphql/
│   │   │   ├── mutations/
│   │   │   │   └── createUser.graphql
│   │   │   └── queries/
│   │   │       ├── getUser.graphql
│   │   │       └── getUsers.graphql
│   │   ├── hooks/
│   │   │   └── useMediaQuery.ts
│   │   ├── pages/
│   │   │   ├── 404.tsx
│   │   │   ├── _app.tsx
│   │   │   ├── _document.tsx
│   │   │   ├── api/
│   │   │   │   └── hello.ts
│   │   │   └── index.tsx
│   │   ├── providers/
│   │   │   └── AppProvider.tsx
│   │   ├── styles/
│   │   │   ├── constantStyles.ts
│   │   │   ├── global.ts
│   │   │   ├── index.ts
│   │   │   ├── styled.d.ts
│   │   │   └── theme.ts
│   │   └── util/
│   │       ├── createURQLClient.ts
│   │       └── isServer.ts
│   └── tsconfig.json
└── server/
    ├── .dockerignore
    ├── .eslintignore
    ├── .eslintrc.js
    ├── .gitignore
    ├── Dockerfile
    ├── dist/
    │   ├── config.js
    │   ├── entities/
    │   │   ├── UserAccount.js
    │   │   └── index.js
    │   ├── index.js
    │   ├── middleware/
    │   │   └── isAuth.js
    │   ├── migrations/
    │   │   ├── 1622333914717-initDB.js
    │   │   └── 1622348668437-MockUsers.js
    │   ├── resolvers/
    │   │   ├── UserAccount.js
    │   │   ├── index.js
    │   │   └── userInput.js
    │   ├── types.js
    │   └── utils/
    │       └── validateRegister.js
    ├── ormconfig.json
    ├── package.json
    ├── src/
    │   ├── config.ts
    │   ├── entities/
    │   │   ├── UserAccount.ts
    │   │   └── index.ts
    │   ├── env.d.ts
    │   ├── index.ts
    │   ├── middleware/
    │   │   └── isAuth.ts
    │   ├── migrations/
    │   │   ├── 1622333914717-initDB.ts
    │   │   └── 1622348668437-MockUsers.ts
    │   ├── resolvers/
    │   │   ├── UserAccount.ts
    │   │   ├── index.ts
    │   │   └── userInput.ts
    │   ├── types.ts
    │   └── utils/
    │       └── validateRegister.ts
    └── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .prettierrc.js
================================================
module.exports = {
  trailingComma: 'es5',
  tabWidth: 2,
  singleQuote: true,
  arrowParens: 'always',
  useTabs: false,
  semi: false,
}


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2020 Brayden Werner

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
<p align="center">
  <img src="https://i.imgur.com/Rz2joyj.jpg" alt="phone-rig-image" width="95%"/>
</p>

### This repo is inspired by https://github.com/benawad/lireddit

<br>

## Features Include:

- Server-side rendered data from postgres
- Create user graphql mutation with password encryption
- Get users/user graphql query
- Light/dark theme support and switch component
  <br>

## Uses the following technologies:

- React
- Next.js
- MaterialUI
- Styled-Components
- TypeGraphQL
- URQL
- ApolloServer(express)
- TypeORM
- PostgresSQL
- Node.js
- TypeScript
  <br>

## Running Locally:

### <b>Client:</b>

```
npm install
npm run dev
```

### <b>Server:</b> (You must have a postgreSQL database running and update the DATABASE_URL in server/.env if you wish to add database functionality)

### A migration to create the users table can be found in server/src/migrations. To run it, uncomment the following line in server/src/index.ts

<br>

```
await conn.runMigrations()
```

```
npm install
npm run build
npm run dev2
```

<br>

## Folder Structure

```bash
├── client
│   └── src
│       ├── components
│       │   ├── elements
│       │   └── modules
│       ├── config
│       ├── generated
│       ├── graphql
│       │   ├── fragments
│       │   ├── mutations
│       │   └── queries
│       ├── hooks
│       ├── pages
│       │   └── api
│       ├── providers
│       ├── public
│       │   ├── fonts
│       │   └── images
│       ├── styles
│       └── util
└── server
    ├── dist
    │   ├── entities
    │   ├── middleware
    │   ├── resolvers
    │   └── utils
    └── src
        ├── entities
        ├── middleware
        ├── migrations
        ├── resolvers
        └── utils
```

## Hosting:

### Client</b>: Hosted with vercel

### Server: Hosted with Heroku using PostgreSQL plugin


================================================
FILE: client/.babelrc
================================================
{
  "presets": ["next/babel"],
  "plugins": [["styled-components", { "ssr": true }]]
}


================================================
FILE: client/.eslintignore
================================================
node_modules/

================================================
FILE: client/.eslintrc.js
================================================
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: ['react', '@typescript-eslint'],
  rules: {
    'comma-dangle': 'never',
    'react/react-in-jsx-scope': 'off',
    'react/prop-types': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-empty-interface': 'off',
  },
}


================================================
FILE: client/.gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel


================================================
FILE: client/codegen.yml
================================================
overwrite: true
schema: 'http://localhost:4000'
documents: 'src/graphql/**/*.graphql'
generates:
  src/generated/graphql.tsx:
    plugins:
      - 'typescript'
      - 'typescript-operations'
      - 'typescript-urql'


================================================
FILE: client/next-env.d.ts
================================================
/// <reference types="next" />
/// <reference types="next/types/global" />


================================================
FILE: client/package.json
================================================
{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "gen": "graphql-codegen --config codegen.yml"
  },
  "dependencies": {
    "@material-ui/core": "^4.11.4",
    "graphql": "^15.5.0",
    "next": "10.2.2",
    "next-urql": "^3.1.0",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-icons": "^4.2.0",
    "react-switch": "^6.0.0",
    "styled-components": "^5.3.0",
    "urql": "^2.0.3"
  },
  "devDependencies": {
    "@graphql-codegen/cli": "1.21.4",
    "@graphql-codegen/typescript": "1.22.0",
    "@graphql-codegen/typescript-operations": "^1.17.16",
    "@graphql-codegen/typescript-urql": "^2.0.6",
    "@types/styled-components": "^5.1.9",
    "@typescript-eslint/eslint-plugin": "^4.24.0",
    "@typescript-eslint/parser": "^4.24.0",
    "babel-plugin-styled-components": "^1.12.0",
    "eslint": "^7.27.0",
    "eslint-config-standard": "^16.0.2",
    "eslint-plugin-import": "^2.23.3",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^4.3.1",
    "eslint-plugin-react": "^7.23.2",
    "typescript": "^4.2.4"
  }
}


================================================
FILE: client/src/components/Components.txt
================================================
I like to break my components up into elements and modules. 

An element is an invidual component that may be used in multiple places in the app. Ex: A button
A module is a larger component generally consists of several elements. Ex: A navbar containing button components

================================================
FILE: client/src/components/elements/Nav/Nav.tsx
================================================
import { AppBar, Toolbar, Typography } from '@material-ui/core'

export const Nav: React.FC = () => {
  return (
    <AppBar position="static">
      <Toolbar>
        <Typography variant="h6">Wern Fullstack Template</Typography>
      </Toolbar>
    </AppBar>
  )
}


================================================
FILE: client/src/components/elements/ThemeToggle/ThemeToggle.styled.ts
================================================
import styled from 'styled-components'

export const SwitchContainer = styled.div`
  position: fixed;
  top: 1%;
  right: 1%;
  margin: 10px 0px 0px 0px;
  z-index: 1;
`


================================================
FILE: client/src/components/elements/ThemeToggle/ThemeToggle.tsx
================================================
import { useContext } from 'react'
import { FaMoon, FaSun } from 'react-icons/fa'
import Switch from 'react-switch'

import { ThemeContext } from '../../../providers/AppProvider'
import { SwitchContainer } from './ThemeToggle.styled'

export const ThemeToggle: React.FC = () => {
  const { toggleTheme, themeMode } = useContext(ThemeContext)

  const handleThemeChange = () => {
    toggleTheme()
  }

  return (
    <SwitchContainer>
      <Switch
        checked={themeMode === 'light' ? true : false}
        height={25}
        width={60}
        handleDiameter={10}
        onColor={'#FF5733'}
        offColor={'#124EAA'}
        checkedIcon={
          <FaSun
            style={{
              display: 'flex',
              justifyContent: 'center',
              alignItems: 'center',
              height: '100%',
              fontSize: 18,
              paddingLeft: 5,
            }}
            color={themeMode === 'light' ? 'white' : 'grey'}
          />
        }
        uncheckedIcon={
          <FaMoon
            style={{
              display: 'flex',
              justifyContent: 'center',
              alignItems: 'center',
              height: '100%',
              fontSize: 18,
              paddingLeft: 14,
            }}
            color={themeMode === 'dark' ? 'blue' : 'blue'}
          />
        }
        onChange={handleThemeChange}
      />
    </SwitchContainer>
  )
}


================================================
FILE: client/src/components/elements/index.ts
================================================
export { Nav } from './Nav/Nav'
export { ThemeToggle } from './ThemeToggle/ThemeToggle'


================================================
FILE: client/src/components/modules/index.ts
================================================
export {}


================================================
FILE: client/src/config/config.ts
================================================
const dev = process.env.NODE_ENV !== 'production'

export const URL = dev
  ? 'http://localhost:3000/api'
  : 'https://fullstack-wern-boilerplate.vercel.app/api'

export const serverURL = dev
  ? 'http://localhost:4000'
  : 'https://wern-fullstack-template.herokuapp.com/'


================================================
FILE: client/src/generated/graphql.tsx
================================================
import gql from 'graphql-tag';
import * as Urql from 'urql';
export type Maybe<T> = T | null;
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
  ID: string;
  String: string;
  Boolean: boolean;
  Int: number;
  Float: number;
};

export type FieldError = {
  __typename?: 'FieldError';
  field: Scalars['String'];
  message: Scalars['String'];
};

export type Mutation = {
  __typename?: 'Mutation';
  createUser: UserResponse;
};


export type MutationCreateUserArgs = {
  options: UserInput;
};

export type Query = {
  __typename?: 'Query';
  user?: Maybe<UserAccount>;
  users?: Maybe<Array<UserAccount>>;
};


export type QueryUserArgs = {
  id: Scalars['String'];
};

export type UserAccount = {
  __typename?: 'UserAccount';
  id: Scalars['Float'];
  username: Scalars['String'];
  email: Scalars['String'];
  createdAt: Scalars['String'];
  updatedAt: Scalars['String'];
};

export type UserInput = {
  email: Scalars['String'];
  username: Scalars['String'];
  password: Scalars['String'];
};

export type UserResponse = {
  __typename?: 'UserResponse';
  errors?: Maybe<Array<FieldError>>;
  user?: Maybe<UserAccount>;
};

export type CreateUserMutationVariables = Exact<{
  username: Scalars['String'];
  email: Scalars['String'];
  password: Scalars['String'];
}>;


export type CreateUserMutation = (
  { __typename?: 'Mutation' }
  & { createUser: (
    { __typename?: 'UserResponse' }
    & { errors?: Maybe<Array<(
      { __typename?: 'FieldError' }
      & Pick<FieldError, 'field' | 'message'>
    )>>, user?: Maybe<(
      { __typename?: 'UserAccount' }
      & Pick<UserAccount, 'id' | 'username'>
    )> }
  ) }
);

export type GetUserQueryVariables = Exact<{
  id: Scalars['String'];
}>;


export type GetUserQuery = (
  { __typename?: 'Query' }
  & { user?: Maybe<(
    { __typename?: 'UserAccount' }
    & Pick<UserAccount, 'id' | 'username' | 'email'>
  )> }
);

export type GetUsersQueryVariables = Exact<{ [key: string]: never; }>;


export type GetUsersQuery = (
  { __typename?: 'Query' }
  & { users?: Maybe<Array<(
    { __typename?: 'UserAccount' }
    & Pick<UserAccount, 'id' | 'username' | 'email'>
  )>> }
);


export const CreateUserDocument = gql`
    mutation CreateUser($username: String!, $email: String!, $password: String!) {
  createUser(options: {username: $username, email: $email, password: $password}) {
    errors {
      field
      message
    }
    user {
      id
      username
    }
  }
}
    `;

export function useCreateUserMutation() {
  return Urql.useMutation<CreateUserMutation, CreateUserMutationVariables>(CreateUserDocument);
};
export const GetUserDocument = gql`
    query getUser($id: String!) {
  user(id: $id) {
    id
    username
    email
  }
}
    `;

export function useGetUserQuery(options: Omit<Urql.UseQueryArgs<GetUserQueryVariables>, 'query'> = {}) {
  return Urql.useQuery<GetUserQuery>({ query: GetUserDocument, ...options });
};
export const GetUsersDocument = gql`
    query getUsers {
  users {
    id
    username
    email
  }
}
    `;

export function useGetUsersQuery(options: Omit<Urql.UseQueryArgs<GetUsersQueryVariables>, 'query'> = {}) {
  return Urql.useQuery<GetUsersQuery>({ query: GetUsersDocument, ...options });
};

================================================
FILE: client/src/graphql/mutations/createUser.graphql
================================================
mutation CreateUser($username: String!, $email: String!, $password: String!) {
  createUser(
    options: { username: $username, email: $email, password: $password }
  ) {
    errors {
      field
      message
    }
    user {
      id
      username
    }
  }
}


================================================
FILE: client/src/graphql/queries/getUser.graphql
================================================
query getUser($id: String!) {
  user(id: $id) {
    id
    username
    email
  }
}


================================================
FILE: client/src/graphql/queries/getUsers.graphql
================================================
query getUsers {
  users {
    id
    username
    email
  }
}


================================================
FILE: client/src/hooks/useMediaQuery.ts
================================================
import { useState, useEffect } from 'react'

export function useMediaQuery(query: string) {
  const [matches, setMatches] = useState(false)

  useEffect(() => {
    const media = window.matchMedia(query)
    if (media.matches !== matches) {
      setMatches(media.matches)
    }
    const listener = () => setMatches(media.matches)

    media.addEventListener('change', listener)
    return () => media.removeEventListener('change', listener)
  }, [matches, query])

  return matches
}


================================================
FILE: client/src/pages/404.tsx
================================================
const Error: React.FC = () => {
  return <div>404 Error</div>
}
export default Error


================================================
FILE: client/src/pages/_app.tsx
================================================
import Head from 'next/head'
import type { AppProps } from 'next/app'

import { AppProvider } from '../providers/AppProvider'

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Head>
        <title>Wern Template</title>
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width"
        />
      </Head>
      <AppProvider>
        <Component {...pageProps} />
      </AppProvider>
    </>
  )
}

export default MyApp


================================================
FILE: client/src/pages/_document.tsx
================================================
import React from 'react'
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { ServerStyleSheets } from '@material-ui/core/styles'

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <Head>
          <meta httpEquiv="Content-Type" content="text/html; charset=utf-8" />
          <meta
            httpEquiv="Content-Security-Policy"
            content="upgrade-insecure-requests"
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

MyDocument.getInitialProps = async (ctx) => {
  const sheets = new ServerStyleSheets()
  const originalRenderPage = ctx.renderPage

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
    })

  const initialProps = await Document.getInitialProps(ctx)

  return {
    ...initialProps,
    styles: [
      ...React.Children.toArray(initialProps.styles),
      sheets.getStyleElement(),
    ],
  }
}


================================================
FILE: client/src/pages/api/hello.ts
================================================
export default (req: any, res: any) => {
  console.log(req)
  res.status(200).json({ name: 'John Doe' })
}


================================================
FILE: client/src/pages/index.tsx
================================================
import { withUrqlClient } from 'next-urql'
import styled from 'styled-components'

import { /*useGetUserQuery*/ useGetUsersQuery } from '../generated/graphql'
import { Nav, ThemeToggle } from '../components/elements/index'
import { createUrqlClient } from '../util/createURQLClient'
import {
  CenterContainer,
  StyledGridContainer,
  StyledHeaderText,
  StyledSubText,
} from '../styles/constantStyles'
import { useMediaQuery } from '../hooks/useMediaQuery'

const Home: React.FC = () => {
  const [{ data }] = useGetUsersQuery()

  //  example query with id parameter
  // const [user] = useGetUserQuery({ variables: { id: '1' } })

  const largerThan500px = useMediaQuery('(min-width: 775px)')

  return (
    <>
      <ThemeToggle />
      <Nav />
      {data &&
        data.users?.map((user, i: number) => {
          return (
            <CenterContainer key={i}>
              <StyledGridContainer>
                <StyledUserContainer largerThan500px={largerThan500px}>
                  <StyledHeaderText>{user.username}</StyledHeaderText>
                  <StyledSubText>Id: {user.id}</StyledSubText>
                  <StyledSubText>{user.email}</StyledSubText>
                </StyledUserContainer>
              </StyledGridContainer>
            </CenterContainer>
          )
        })}
    </>
  )
}

interface StyledUserContainerProps {
  largerThan500px: boolean
}

const StyledUserContainer = styled.div<StyledUserContainerProps>`
  width: ${(props) => (props.largerThan500px ? '700px' : '90%')};
  height: 100%;
  padding: 15px;
  margin: 20px 0px 20px 0px;
  border-radius: 10px;
  background-color: ${(props) => props.theme.secondary};
`

//  creates client with server side rendering enabled
export default withUrqlClient(createUrqlClient, { ssr: true })(Home)


================================================
FILE: client/src/providers/AppProvider.tsx
================================================
import React, { useEffect, createContext, useState, useMemo } from 'react'
import { ThemeProvider } from 'styled-components'

import { GlobalStyles, theme } from '../styles/index'

export const ThemeContext = createContext({
  themeMode: 'dark',
  toggleTheme: () => {
    return
  },
})

export const AppProvider: React.FC = ({ children }) => {
  const [themeMode, setThemeMode] = useState<string>('dark')
  const currentTheme = (theme as any)[themeMode]

  useEffect(() => {
    setThemeMode(localStorage.getItem('theme') || 'dark')
  }, [])

  useEffect(() => {
    localStorage.setItem('theme', themeMode)
  }, [themeMode])

  const toggleTheme = () => {
    setThemeMode((oldTheme) => {
      if (oldTheme === 'light') return 'dark'
      else return 'light'
    })
  }

  //  combine into one object for global ThemeContext state
  const value = useMemo(() => ({ themeMode, toggleTheme }), [themeMode])
  return (
    <ThemeContext.Provider value={value}>
      <ThemeProvider theme={currentTheme}>
        <GlobalStyles />
        {children}
      </ThemeProvider>
    </ThemeContext.Provider>
  )
}


================================================
FILE: client/src/styles/constantStyles.ts
================================================
import styled from 'styled-components'
import { Grid } from '@material-ui/core'

export const CenterContainer = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
`

export const StyledGridContainer = styled(Grid)`
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
`

export const StyledHeaderText = styled.div`
  font-size: 20px;
`

export const StyledSubText = styled.div`
  font-size: 15px;
  color: ${(props) => props.theme.subText};
`


================================================
FILE: client/src/styles/global.ts
================================================
import { createGlobalStyle, css } from 'styled-components'

export default createGlobalStyle`
${({ theme }) => css`
  html {
    height: 100%;
    body {
      display: flex;
      flex-direction: column;
      height: 100%;
      margin: 0;
      background: ${theme.background};
      color: ${theme.primaryText};
      font-family: Newsreader;
    }
  }
`}
`


================================================
FILE: client/src/styles/index.ts
================================================
export { default as GlobalStyles } from './global'
export { default as theme } from './theme'


================================================
FILE: client/src/styles/styled.d.ts
================================================
import {} from 'styled-components'
import { ThemeType } from './theme'
declare module 'styled-components' {
  export interface DefaultTheme extends ThemeType {}
}


================================================
FILE: client/src/styles/theme.ts
================================================
export type ThemeType = typeof theme['light']

const theme = {
  light: {
    background: '#ACDDDE',
    secondary: '#CAF1DE',
    secondaryDark: '#E1F8DC',
    primaryText: 'black',
    subText: 'gray',
  },
  dark: {
    background: '#444444',
    secondary: '#1E2328',
    secondaryDark: '#878683',
    primaryText: 'white',
    subText: 'gray',
  },
}

export const commonColors = {
  red: '#C6493A',
}
export default theme


================================================
FILE: client/src/util/createURQLClient.ts
================================================
import { dedupExchange, cacheExchange, fetchExchange } from '@urql/core'

import { serverURL } from '../config/config'
// import { isServer } from './isServer'

export const createUrqlClient = (ssrExchange: any, ctx: any) => {
  //  uncomment if necessary to send cookie to the server. Useful for authentification
  // let cookie = ''
  // if (isServer()) {
  //   cookie = ctx?.req?.headers?.cookie
  // }

  return {
    url: serverURL,
    fetchOptions: {
      credentials: 'include' as const,
      //  this will send a cookie to the server
      // headers: cookie
      //   ? {
      //       cookie,
      //     }
      //   : undefined,
    },
    exchanges: [
      dedupExchange,
      cacheExchange,
      ssrExchange, // Add `ssr` in front of the `fetchExchange`
      fetchExchange,
    ],
  }
}


================================================
FILE: client/src/util/isServer.ts
================================================
export const isServer = () => typeof window === 'undefined'


================================================
FILE: client/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}


================================================
FILE: server/.dockerignore
================================================
  node_modules
npm-debug.log

================================================
FILE: server/.eslintignore
================================================
node_modules

================================================
FILE: server/.eslintrc.js
================================================
module.exports = {
  env: {
    browser: true,
    commonjs: true,
    es2021: true,
  },
  extends: ['standard'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 12,
  },
  plugins: ['@typescript-eslint'],
  rules: {
    'comma-dangle': 'never',
  },
}


================================================
FILE: server/.gitignore
================================================
#   add .env for real application
node_modules/

================================================
FILE: server/Dockerfile
================================================
FROM node:14

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .
COPY .env.production .env

ENV NODE_ENV production

EXPOSE 8080
CMD [ "node", "dist/index.js" ]

================================================
FILE: server/dist/config.js
================================================
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__prod__ = void 0;
exports.__prod__ = process.env.NODE_ENV === 'production';
//# sourceMappingURL=config.js.map

================================================
FILE: server/dist/entities/UserAccount.js
================================================
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UserAccount = void 0;
const type_graphql_1 = require("type-graphql");
const typeorm_1 = require("typeorm");
let UserAccount = class UserAccount extends typeorm_1.BaseEntity {
};
__decorate([
    type_graphql_1.Field(),
    typeorm_1.PrimaryGeneratedColumn(),
    __metadata("design:type", Number)
], UserAccount.prototype, "id", void 0);
__decorate([
    type_graphql_1.Field(),
    typeorm_1.Column({ unique: true }),
    __metadata("design:type", String)
], UserAccount.prototype, "username", void 0);
__decorate([
    type_graphql_1.Field(),
    typeorm_1.Column({ unique: true }),
    __metadata("design:type", String)
], UserAccount.prototype, "email", void 0);
__decorate([
    typeorm_1.Column(),
    __metadata("design:type", String)
], UserAccount.prototype, "password", void 0);
__decorate([
    type_graphql_1.Field(() => String),
    typeorm_1.CreateDateColumn(),
    __metadata("design:type", Date)
], UserAccount.prototype, "createdAt", void 0);
__decorate([
    type_graphql_1.Field(() => String),
    typeorm_1.UpdateDateColumn(),
    __metadata("design:type", Date)
], UserAccount.prototype, "updatedAt", void 0);
UserAccount = __decorate([
    type_graphql_1.ObjectType(),
    typeorm_1.Entity()
], UserAccount);
exports.UserAccount = UserAccount;
//# sourceMappingURL=UserAccount.js.map

================================================
FILE: server/dist/entities/index.js
================================================
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var UserAccount_1 = require("./UserAccount");
Object.defineProperty(exports, "UserAccount", { enumerable: true, get: function () { return UserAccount_1.UserAccount; } });
//# sourceMappingURL=index.js.map

================================================
FILE: server/dist/index.js
================================================
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
require("reflect-metadata");
require("dotenv-safe/config");
const express_1 = __importDefault(require("express"));
const path_1 = __importDefault(require("path"));
const cors_1 = __importDefault(require("cors"));
const apollo_server_express_1 = require("apollo-server-express");
const type_graphql_1 = require("type-graphql");
const typeorm_1 = require("typeorm");
const index_1 = require("./entities/index");
const index_2 = require("./resolvers/index");
const main = () => __awaiter(void 0, void 0, void 0, function* () {
    console.log(process.env.DATABASE_URL);
    yield typeorm_1.createConnection({
        type: 'postgres',
        url: process.env.DATABASE_URL,
        logging: true,
        synchronize: true,
        entities: [index_1.UserAccount],
        migrations: [path_1.default.join(__dirname, './migrations/*')],
        ssl: {
            rejectUnauthorized: false,
        },
    });
    const app = express_1.default();
    app.set('trust proxy', 1);
    app.use(cors_1.default({
        origin: process.env.CORS_ORIGIN,
        credentials: true,
    }));
    const apolloServer = new apollo_server_express_1.ApolloServer({
        schema: yield type_graphql_1.buildSchema({
            resolvers: [index_2.UserResolver],
            validate: false,
        }),
        context: ({ req, res }) => ({
            req,
            res,
        }),
    });
    apolloServer.applyMiddleware({
        app,
        cors: false,
        path: '/',
    });
    app.listen(parseInt(process.env.PORT), () => {
        console.log(`server started on localhost:${process.env.PORT}`);
    });
});
main().catch((err) => {
    console.error(err);
});
//# sourceMappingURL=index.js.map

================================================
FILE: server/dist/middleware/isAuth.js
================================================
//# sourceMappingURL=isAuth.js.map

================================================
FILE: server/dist/migrations/1622333914717-initDB.js
================================================
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.initDB1622333914717 = void 0;
class initDB1622333914717 {
    constructor() {
        this.name = 'initDB1622333914717';
    }
    up(queryRunner) {
        return __awaiter(this, void 0, void 0, function* () {
            yield queryRunner.query(`CREATE TABLE "User_Account" ("id" SERIAL NOT NULL, "username" character varying NOT NULL, "email" character varying NOT NULL, "password" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`);
        });
    }
    down(queryRunner) {
        return __awaiter(this, void 0, void 0, function* () {
            yield queryRunner.query(`DROP TABLE "user_account"`);
        });
    }
}
exports.initDB1622333914717 = initDB1622333914717;
//# sourceMappingURL=1622333914717-initDB.js.map

================================================
FILE: server/dist/migrations/1622348668437-MockUsers.js
================================================
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockUsers1622348668437 = void 0;
class MockUsers1622348668437 {
    up(queryRunner) {
        return __awaiter(this, void 0, void 0, function* () {
            yield queryRunner.query(`
        insert into UserAccount (id, username, email, password, "createdAt", "updatedAt") values (1, 'sbauldry0', 'ctrewett0@unicef.org', 'jhZk91W5W', '4/18/2021', '7/22/2020');
insert into UserAccount (id, username, email, password, "createdAt", "updatedAt") values (2, 'gduiguid1', 'asallnow1@dell.com', 'U58IqmAs', '3/2/2021', '8/7/2020');
insert into UserAccount (id, username, email, password, "createdAt", "updatedAt") values (3, 'dwrey2', 'sportress2@google.com.au', 'MjoXnUBNnE', '1/23/2021', '10/5/2020');
insert into UserAccount (id, username, email, password, "createdAt", "updatedAt") values (4, 'hwebley3', 'whauxby3@live.com', 'aclMGjnKB4jC', '12/2/2020', '5/7/2021');
insert into UserAccount (id, username, email, password, "createdAt", "updatedAt") values (5, 'lscourgie4', 'kkerwick4@pen.io', '6slgst6', '6/28/2020', '3/13/2021');
insert into UserAccount (id, username, email, password, "createdAt", "updatedAt") values (6, 'hbrundall5', 'teaglestone5@tmall.com', 'hgmvqTD', '11/10/2020', '11/26/2020');
        `);
        });
    }
    down(_) {
        return __awaiter(this, void 0, void 0, function* () { });
    }
}
exports.MockUsers1622348668437 = MockUsers1622348668437;
//# sourceMappingURL=1622348668437-MockUsers.js.map

================================================
FILE: server/dist/resolvers/UserAccount.js
================================================
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UserResolver = void 0;
const type_graphql_1 = require("type-graphql");
const typeorm_1 = require("typeorm");
const argon2 = __importStar(require("argon2"));
const validateRegister_1 = require("../utils/validateRegister");
const index_1 = require("../entities/index");
const userInput_1 = require("./userInput");
let FieldError = class FieldError {
};
__decorate([
    type_graphql_1.Field(),
    __metadata("design:type", String)
], FieldError.prototype, "field", void 0);
__decorate([
    type_graphql_1.Field(),
    __metadata("design:type", String)
], FieldError.prototype, "message", void 0);
FieldError = __decorate([
    type_graphql_1.ObjectType()
], FieldError);
let UserResponse = class UserResponse {
};
__decorate([
    type_graphql_1.Field(() => [FieldError], { nullable: true }),
    __metadata("design:type", Array)
], UserResponse.prototype, "errors", void 0);
__decorate([
    type_graphql_1.Field(() => index_1.UserAccount, { nullable: true }),
    __metadata("design:type", index_1.UserAccount)
], UserResponse.prototype, "user", void 0);
UserResponse = __decorate([
    type_graphql_1.ObjectType()
], UserResponse);
let UserResolver = class UserResolver {
    user(id) {
        const user = index_1.UserAccount.findOne({ where: { id } });
        if (!user)
            return null;
        return user;
    }
    users() {
        console.log('users query reached');
        const users = index_1.UserAccount.find();
        if (!users)
            return null;
        return users;
    }
    createUser(options) {
        return __awaiter(this, void 0, void 0, function* () {
            const errors = validateRegister_1.validateRegister(options);
            if (errors) {
                return { errors };
            }
            const hashedPassword = yield argon2.hash(options.password);
            let user;
            try {
                const result = yield typeorm_1.getConnection()
                    .createQueryBuilder()
                    .insert()
                    .into(index_1.UserAccount)
                    .values({
                    username: options.username,
                    email: options.email,
                    password: hashedPassword,
                })
                    .returning('*')
                    .execute();
                user = result.raw[0];
            }
            catch (err) {
                if (err.code === '23505') {
                    return {
                        errors: [
                            {
                                field: 'username',
                                message: 'username already taken',
                            },
                        ],
                    };
                }
            }
            return { user };
        });
    }
};
__decorate([
    type_graphql_1.Query(() => index_1.UserAccount, { nullable: true }),
    __param(0, type_graphql_1.Arg('id')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", void 0)
], UserResolver.prototype, "user", null);
__decorate([
    type_graphql_1.Query(() => [index_1.UserAccount], { nullable: true }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], UserResolver.prototype, "users", null);
__decorate([
    type_graphql_1.Mutation(() => UserResponse),
    __param(0, type_graphql_1.Arg('options')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [userInput_1.UserInput]),
    __metadata("design:returntype", Promise)
], UserResolver.prototype, "createUser", null);
UserResolver = __decorate([
    type_graphql_1.Resolver(index_1.UserAccount)
], UserResolver);
exports.UserResolver = UserResolver;
//# sourceMappingURL=UserAccount.js.map

================================================
FILE: server/dist/resolvers/index.js
================================================
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var UserAccount_1 = require("./UserAccount");
Object.defineProperty(exports, "UserResolver", { enumerable: true, get: function () { return UserAccount_1.UserResolver; } });
//# sourceMappingURL=index.js.map

================================================
FILE: server/dist/resolvers/userInput.js
================================================
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UserInput = void 0;
const type_graphql_1 = require("type-graphql");
let UserInput = class UserInput {
};
__decorate([
    type_graphql_1.Field(),
    __metadata("design:type", String)
], UserInput.prototype, "email", void 0);
__decorate([
    type_graphql_1.Field(),
    __metadata("design:type", String)
], UserInput.prototype, "username", void 0);
__decorate([
    type_graphql_1.Field(),
    __metadata("design:type", String)
], UserInput.prototype, "password", void 0);
UserInput = __decorate([
    type_graphql_1.InputType()
], UserInput);
exports.UserInput = UserInput;
//# sourceMappingURL=userInput.js.map

================================================
FILE: server/dist/types.js
================================================
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map

================================================
FILE: server/dist/utils/validateRegister.js
================================================
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateRegister = void 0;
exports.validateRegister = (options) => {
    if (!options.email.includes('@')) {
        return [
            {
                field: 'email',
                message: 'invalid email',
            },
        ];
    }
    if (options.username.length <= 2) {
        return [
            {
                field: 'username',
                message: 'length must be greater than 2',
            },
        ];
    }
    if (options.username.includes('@')) {
        return [
            {
                field: 'username',
                message: 'cannot include an @',
            },
        ];
    }
    if (options.password.length <= 2) {
        return [
            {
                field: 'password',
                message: 'length must be greater than 2',
            },
        ];
    }
    return null;
};
//# sourceMappingURL=validateRegister.js.map

================================================
FILE: server/ormconfig.json
================================================
{
  "type": "postgres",
  "host": "localhost",
  "port": "5432",
  "username": "postgres",
  "password": "postgres",
  "database": "thumbnailgame",
  "entities": ["dist/entities/*.js"]
}


================================================
FILE: server/package.json
================================================
{
  "name": "wern-fullstack-template-server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "gen-env": "gen-env-types .env -o src/env.d.ts -e .",
    "build": "tsc",
    "watch": "tsc -w",
    "dev": "nodemon dist/index.js",
    "start": "node dist/index.js",
    "start2": "ts-node src/index.ts",
    "dev2": "nodemon --exec ts-node src/index.ts"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/connect-redis": "^0.0.14",
    "@types/cors": "^2.8.7",
    "@types/express": "^4.17.7",
    "@types/express-session": "^1.17.0",
    "@types/ioredis": "^4.17.3",
    "@types/node": "^14.0.27",
    "@types/nodemailer": "^6.4.0",
    "@types/redis": "^2.8.25",
    "@types/uuid": "^8.0.1",
    "gen-env-types": "^1.0.3",
    "nodemon": "^2.0.4",
    "ts-node": "^8.10.2",
    "typescript": "^3.9.7"
  },
  "dependencies": {
    "apollo-server-express": "^2.16.1",
    "argon2": "^0.26.2",
    "connect-redis": "^5.0.0",
    "cors": "^2.8.5",
    "dataloader": "^2.0.0",
    "dotenv-safe": "^8.2.0",
    "express": "^4.17.1",
    "express-session": "^1.17.1",
    "graphql": "^15.3.0",
    "nodemailer": "^6.4.11",
    "pg": "^8.3.0",
    "reflect-metadata": "^0.1.13",
    "type-graphql": "^1.0.0-rc.3",
    "typeorm": "^0.2.25",
    "uuid": "^8.3.0"
  },
  "mikro-orm": {
    "useTsNode": true,
    "configPaths": [
      "./src/mikro-orm.config.ts",
      "./dist/mikro-orm.config.js"
    ]
  }
}


================================================
FILE: server/src/config.ts
================================================
export const __prod__ = process.env.NODE_ENV === 'production'


================================================
FILE: server/src/entities/UserAccount.ts
================================================
import { ObjectType, Field } from 'type-graphql'
import {
  Entity,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  Column,
  BaseEntity,
} from 'typeorm'

@ObjectType()
@Entity()
export class UserAccount extends BaseEntity {
  @Field()
  @PrimaryGeneratedColumn()
  id!: number

  @Field()
  @Column({ unique: true })
  username!: string

  @Field()
  @Column({ unique: true })
  email!: string

  @Column()
  password!: string

  @Field(() => String)
  @CreateDateColumn()
  createdAt: Date

  @Field(() => String)
  @UpdateDateColumn()
  updatedAt: Date
}


================================================
FILE: server/src/entities/index.ts
================================================
export { UserAccount } from './UserAccount'


================================================
FILE: server/src/env.d.ts
================================================
declare namespace NodeJS {
  interface ProcessEnv {
    DATABASE_URL: string;
    REDIS_URL: string;
    PORT: string;
    SESSION_SECRET: string;
    CORS_ORIGIN: string;
  }
}

================================================
FILE: server/src/index.ts
================================================
import 'reflect-metadata'
import 'dotenv-safe/config'
import express from 'express'
import path from 'path'
import cors from 'cors'
import { ApolloServer } from 'apollo-server-express'
import { buildSchema } from 'type-graphql'
import { createConnection } from 'typeorm'

import { __prod__ } from './config'
import { UserAccount } from './entities/index'
import { UserResolver } from './resolvers/index'

const main = async () => {
  console.log(process.env.DATABASE_URL)
  /*const conn =*/ await createConnection({
    type: 'postgres',
    url: process.env.DATABASE_URL,
    logging: true,
    //  do not want synchronize true in production, possiblility of losing data
    synchronize: false,
    entities: [UserAccount],
    migrations: [path.join(__dirname, './migrations/*')],
    //  need this to use postgres heroku plugin
    ssl: {
      rejectUnauthorized: false,
    },
  })
  // await conn.runMigrations()

  const app = express()

  app.set('trust proxy', 1)
  app.use(
    cors({
      origin: process.env.CORS_ORIGIN,
      credentials: true,
    })
  )

  const apolloServer = new ApolloServer({
    schema: await buildSchema({
      resolvers: [UserResolver],
      validate: false,
    }),
    context: ({ req, res }) => ({
      req,
      res,
    }),
  })

  apolloServer.applyMiddleware({
    app,
    cors: false,
    path: '/',
  })

  app.listen(parseInt(process.env.PORT!), () => {
    console.log(`server started on localhost:${process.env.PORT!}`)
  })
}

main().catch((err) => {
  console.error(err)
})


================================================
FILE: server/src/middleware/isAuth.ts
================================================
// import { MiddlewareFn } from 'type-graphql'
// import { MyContext } from '../types'

// export const isAuth: MiddlewareFn<MyContext> = ({ context }, next) => {
//   if (!context.req.session.userId) {
//     throw new Error('not authenticated')
//   }

//   return next()
// }


================================================
FILE: server/src/migrations/1622333914717-initDB.ts
================================================
import { MigrationInterface, QueryRunner } from 'typeorm'

export class initDB1622333914717 implements MigrationInterface {
  name = 'initDB1622333914717'

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(
      `CREATE TABLE "User_Account" ("id" SERIAL NOT NULL, "username" character varying NOT NULL, "email" character varying NOT NULL, "password" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_78a916df40e02a9deb1c4b75edb" UNIQUE ("username"), CONSTRAINT "UQ_e12875dfb3b1d92d7d7c5377e22" UNIQUE ("email"), CONSTRAINT "PK_cace4a159ff9f2512dd42373760" PRIMARY KEY ("id"))`
    )
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE "user_account"`)
  }
}


================================================
FILE: server/src/migrations/1622348668437-MockUsers.ts
================================================
import { MigrationInterface, QueryRunner } from 'typeorm'

export class MockUsers1622348668437 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
        insert into User_Account (id, username, email, password, "createdAt", "updatedAt") values (2, 'sbauldry0', 'ctrewett0@unicef.org', 'jhZk91W5W', '4/18/2021', '7/22/2020');
insert into User_Account (id, username, email, password, "createdAt", "updatedAt") values (3, 'gduiguid1', 'asallnow1@dell.com', 'U58IqmAs', '3/2/2021', '8/7/2020');
insert into User_Account (id, username, email, password, "createdAt", "updatedAt") values (4, 'dwrey2', 'sportress2@google.com.au', 'MjoXnUBNnE', '1/23/2021', '10/5/2020');
insert into User_Account (id, username, email, password, "createdAt", "updatedAt") values (5, 'hwebley3', 'whauxby3@live.com', 'aclMGjnKB4jC', '12/2/2020', '5/7/2021');
insert into User_Account (id, username, email, password, "createdAt", "updatedAt") values (6, 'lscourgie4', 'kkerwick4@pen.io', '6slgst6', '6/28/2020', '3/13/2021');
insert into User_Account (id, username, email, password, "createdAt", "updatedAt") values (7, 'hbrundall5', 'teaglestone5@tmall.com', 'hgmvqTD', '11/10/2020', '11/26/2020');
        `)
  }

  public async down(_: QueryRunner): Promise<void> {}
}


================================================
FILE: server/src/resolvers/UserAccount.ts
================================================
import {
  Resolver,
  Mutation,
  Arg,
  Field,
  // Ctx,
  ObjectType,
  Query,
  // FieldResolver,
  // Root,
} from 'type-graphql'
import { getConnection } from 'typeorm'
import * as argon2 from 'argon2'

// import { MyContext } from '../types'
import { validateRegister } from '../utils/validateRegister'
import { UserAccount } from '../entities/index'
import { UserInput } from './userInput'

@ObjectType()
class FieldError {
  @Field()
  field: string
  @Field()
  message: string
}

@ObjectType()
//  return the errors associated and the user
class UserResponse {
  @Field(() => [FieldError], { nullable: true })
  errors?: FieldError[]

  @Field(() => UserAccount, { nullable: true })
  user?: UserAccount
}

@Resolver(UserAccount)
export class UserResolver {
  @Query(() => UserAccount, { nullable: true })
  user(@Arg('id') id: string) {
    const user = UserAccount.findOne({ where: { id } })
    if (!user) return null

    return user
  }

  @Query(() => [UserAccount], { nullable: true })
  users() {
    console.log('users query reached')
    const users = UserAccount.find()
    if (!users) return null

    return users
  }

  @Mutation(() => UserResponse)
  async createUser(@Arg('options') options: UserInput): Promise<UserResponse> {
    const errors = validateRegister(options)
    if (errors) {
      return { errors }
    }

    const hashedPassword = await argon2.hash(options.password)
    let user
    try {
      const result = await getConnection()
        .createQueryBuilder()
        .insert()
        .into(UserAccount)
        .values({
          username: options.username,
          email: options.email,
          password: hashedPassword,
        })
        .returning('*')
        .execute()
      user = result.raw[0]
    } catch (err) {
      if (err.code === '23505') {
        return {
          errors: [
            {
              field: 'username',
              message: 'username already taken',
            },
          ],
        }
      }
    }

    return { user }
  }
}


================================================
FILE: server/src/resolvers/index.ts
================================================
export { UserResolver } from './UserAccount'


================================================
FILE: server/src/resolvers/userInput.ts
================================================
import { InputType, Field } from 'type-graphql'

@InputType()
export class UserInput {
  @Field()
  email: string
  @Field()
  username: string
  @Field()
  password: string
}


================================================
FILE: server/src/types.ts
================================================
import { Request, Response } from 'express'

export type MyContext = {
  req: Request
  res: Response
}


================================================
FILE: server/src/utils/validateRegister.ts
================================================
import { UserInput } from '../resolvers/userInput'

export const validateRegister = (options: UserInput) => {
  if (!options.email.includes('@')) {
    return [
      {
        field: 'email',
        message: 'invalid email',
      },
    ]
  }

  if (options.username.length <= 2) {
    return [
      {
        field: 'username',
        message: 'length must be greater than 2',
      },
    ]
  }

  if (options.username.includes('@')) {
    return [
      {
        field: 'username',
        message: 'cannot include an @',
      },
    ]
  }

  if (options.password.length <= 2) {
    return [
      {
        field: 'password',
        message: 'length must be greater than 2',
      },
    ]
  }

  return null
}


================================================
FILE: server/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "lib": ["dom", "es6", "es2017", "esnext.asynciterable"],
    "skipLibCheck": true,
    "sourceMap": true,
    "outDir": "./dist",
    "moduleResolution": "node",
    "removeComments": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "resolveJsonModule": true,
    "baseUrl": "."
  },
  "exclude": ["node_modules"],
  "include": ["./src/**/*.tsx", "./src/**/*.ts", "1622348668437-MockUsers.ts"]
}
Download .txt
gitextract_cbg5532v/

├── .prettierrc.js
├── LICENSE
├── README.md
├── client/
│   ├── .babelrc
│   ├── .eslintignore
│   ├── .eslintrc.js
│   ├── .gitignore
│   ├── codegen.yml
│   ├── next-env.d.ts
│   ├── package.json
│   ├── src/
│   │   ├── components/
│   │   │   ├── Components.txt
│   │   │   ├── elements/
│   │   │   │   ├── Nav/
│   │   │   │   │   └── Nav.tsx
│   │   │   │   ├── ThemeToggle/
│   │   │   │   │   ├── ThemeToggle.styled.ts
│   │   │   │   │   └── ThemeToggle.tsx
│   │   │   │   └── index.ts
│   │   │   └── modules/
│   │   │       └── index.ts
│   │   ├── config/
│   │   │   └── config.ts
│   │   ├── generated/
│   │   │   └── graphql.tsx
│   │   ├── graphql/
│   │   │   ├── mutations/
│   │   │   │   └── createUser.graphql
│   │   │   └── queries/
│   │   │       ├── getUser.graphql
│   │   │       └── getUsers.graphql
│   │   ├── hooks/
│   │   │   └── useMediaQuery.ts
│   │   ├── pages/
│   │   │   ├── 404.tsx
│   │   │   ├── _app.tsx
│   │   │   ├── _document.tsx
│   │   │   ├── api/
│   │   │   │   └── hello.ts
│   │   │   └── index.tsx
│   │   ├── providers/
│   │   │   └── AppProvider.tsx
│   │   ├── styles/
│   │   │   ├── constantStyles.ts
│   │   │   ├── global.ts
│   │   │   ├── index.ts
│   │   │   ├── styled.d.ts
│   │   │   └── theme.ts
│   │   └── util/
│   │       ├── createURQLClient.ts
│   │       └── isServer.ts
│   └── tsconfig.json
└── server/
    ├── .dockerignore
    ├── .eslintignore
    ├── .eslintrc.js
    ├── .gitignore
    ├── Dockerfile
    ├── dist/
    │   ├── config.js
    │   ├── entities/
    │   │   ├── UserAccount.js
    │   │   └── index.js
    │   ├── index.js
    │   ├── middleware/
    │   │   └── isAuth.js
    │   ├── migrations/
    │   │   ├── 1622333914717-initDB.js
    │   │   └── 1622348668437-MockUsers.js
    │   ├── resolvers/
    │   │   ├── UserAccount.js
    │   │   ├── index.js
    │   │   └── userInput.js
    │   ├── types.js
    │   └── utils/
    │       └── validateRegister.js
    ├── ormconfig.json
    ├── package.json
    ├── src/
    │   ├── config.ts
    │   ├── entities/
    │   │   ├── UserAccount.ts
    │   │   └── index.ts
    │   ├── env.d.ts
    │   ├── index.ts
    │   ├── middleware/
    │   │   └── isAuth.ts
    │   ├── migrations/
    │   │   ├── 1622333914717-initDB.ts
    │   │   └── 1622348668437-MockUsers.ts
    │   ├── resolvers/
    │   │   ├── UserAccount.ts
    │   │   ├── index.ts
    │   │   └── userInput.ts
    │   ├── types.ts
    │   └── utils/
    │       └── validateRegister.ts
    └── tsconfig.json
Download .txt
SYMBOL INDEX (73 symbols across 19 files)

FILE: client/src/config/config.ts
  constant URL (line 3) | const URL = dev

FILE: client/src/generated/graphql.tsx
  type Maybe (line 3) | type Maybe<T> = T | null;
  type Exact (line 4) | type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K...
  type MakeOptional (line 5) | type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?:...
  type MakeMaybe (line 6) | type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: May...
  type Omit (line 7) | type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
  type Scalars (line 9) | type Scalars = {
  type FieldError (line 17) | type FieldError = {
  type Mutation (line 23) | type Mutation = {
  type MutationCreateUserArgs (line 29) | type MutationCreateUserArgs = {
  type Query (line 33) | type Query = {
  type QueryUserArgs (line 40) | type QueryUserArgs = {
  type UserAccount (line 44) | type UserAccount = {
  type UserInput (line 53) | type UserInput = {
  type UserResponse (line 59) | type UserResponse = {
  type CreateUserMutationVariables (line 65) | type CreateUserMutationVariables = Exact<{
  type CreateUserMutation (line 72) | type CreateUserMutation = (
  type GetUserQueryVariables (line 86) | type GetUserQueryVariables = Exact<{
  type GetUserQuery (line 91) | type GetUserQuery = (
  type GetUsersQueryVariables (line 99) | type GetUsersQueryVariables = Exact<{ [key: string]: never; }>;
  type GetUsersQuery (line 102) | type GetUsersQuery = (
  function useCreateUserMutation (line 126) | function useCreateUserMutation() {
  function useGetUserQuery (line 139) | function useGetUserQuery(options: Omit<Urql.UseQueryArgs<GetUserQueryVar...
  function useGetUsersQuery (line 152) | function useGetUsersQuery(options: Omit<Urql.UseQueryArgs<GetUsersQueryV...

FILE: client/src/hooks/useMediaQuery.ts
  function useMediaQuery (line 3) | function useMediaQuery(query: string) {

FILE: client/src/pages/_app.tsx
  function MyApp (line 6) | function MyApp({ Component, pageProps }: AppProps) {

FILE: client/src/pages/_document.tsx
  class MyDocument (line 5) | class MyDocument extends Document {
    method render (line 6) | render() {

FILE: client/src/pages/index.tsx
  type StyledUserContainerProps (line 45) | interface StyledUserContainerProps {

FILE: client/src/styles/styled.d.ts
  type DefaultTheme (line 4) | interface DefaultTheme extends ThemeType {}

FILE: client/src/styles/theme.ts
  type ThemeType (line 1) | type ThemeType = typeof theme['light']

FILE: server/dist/index.js
  function adopt (line 3) | function adopt(value) { return value instanceof P ? value : new P(functi...
  function fulfilled (line 5) | function fulfilled(value) { try { step(generator.next(value)); } catch (...
  function rejected (line 6) | function rejected(value) { try { step(generator["throw"](value)); } catc...
  function step (line 7) | function step(result) { result.done ? resolve(result.value) : adopt(resu...

FILE: server/dist/migrations/1622333914717-initDB.js
  function adopt (line 3) | function adopt(value) { return value instanceof P ? value : new P(functi...
  function fulfilled (line 5) | function fulfilled(value) { try { step(generator.next(value)); } catch (...
  function rejected (line 6) | function rejected(value) { try { step(generator["throw"](value)); } catc...
  function step (line 7) | function step(result) { result.done ? resolve(result.value) : adopt(resu...
  class initDB1622333914717 (line 13) | class initDB1622333914717 {
    method constructor (line 14) | constructor() {
    method up (line 17) | up(queryRunner) {
    method down (line 22) | down(queryRunner) {

FILE: server/dist/migrations/1622348668437-MockUsers.js
  function adopt (line 3) | function adopt(value) { return value instanceof P ? value : new P(functi...
  function fulfilled (line 5) | function fulfilled(value) { try { step(generator.next(value)); } catch (...
  function rejected (line 6) | function rejected(value) { try { step(generator["throw"](value)); } catc...
  function step (line 7) | function step(result) { result.done ? resolve(result.value) : adopt(resu...
  class MockUsers1622348668437 (line 13) | class MockUsers1622348668437 {
    method up (line 14) | up(queryRunner) {
    method down (line 26) | down(_) {

FILE: server/dist/resolvers/UserAccount.js
  function adopt (line 34) | function adopt(value) { return value instanceof P ? value : new P(functi...
  function fulfilled (line 36) | function fulfilled(value) { try { step(generator.next(value)); } catch (...
  function rejected (line 37) | function rejected(value) { try { step(generator["throw"](value)); } catc...
  function step (line 38) | function step(result) { result.done ? resolve(result.value) : adopt(resu...
  method user (line 77) | user(id) {
  method users (line 83) | users() {
  method createUser (line 90) | createUser(options) {

FILE: server/src/entities/UserAccount.ts
  class UserAccount (line 13) | class UserAccount extends BaseEntity {

FILE: server/src/env.d.ts
  type ProcessEnv (line 2) | interface ProcessEnv {

FILE: server/src/migrations/1622333914717-initDB.ts
  class initDB1622333914717 (line 3) | class initDB1622333914717 implements MigrationInterface {
    method up (line 6) | public async up(queryRunner: QueryRunner): Promise<void> {
    method down (line 12) | public async down(queryRunner: QueryRunner): Promise<void> {

FILE: server/src/migrations/1622348668437-MockUsers.ts
  class MockUsers1622348668437 (line 3) | class MockUsers1622348668437 implements MigrationInterface {
    method up (line 4) | public async up(queryRunner: QueryRunner): Promise<void> {
    method down (line 15) | public async down(_: QueryRunner): Promise<void> {}

FILE: server/src/resolvers/UserAccount.ts
  class FieldError (line 20) | @ObjectType()
  class UserResponse (line 28) | @ObjectType()
  class UserResolver (line 39) | class UserResolver {
    method user (line 41) | user(@Arg('id') id: string) {
    method users (line 49) | users() {
    method createUser (line 58) | async createUser(@Arg('options') options: UserInput): Promise<UserResp...

FILE: server/src/resolvers/userInput.ts
  class UserInput (line 4) | class UserInput {

FILE: server/src/types.ts
  type MyContext (line 3) | type MyContext = {
Condensed preview — 69 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (56K chars).
[
  {
    "path": ".prettierrc.js",
    "chars": 139,
    "preview": "module.exports = {\n  trailingComma: 'es5',\n  tabWidth: 2,\n  singleQuote: true,\n  arrowParens: 'always',\n  useTabs: false"
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "MIT License\n\nCopyright (c) 2020 Brayden Werner\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "README.md",
    "chars": 1814,
    "preview": "<p align=\"center\">\n  <img src=\"https://i.imgur.com/Rz2joyj.jpg\" alt=\"phone-rig-image\" width=\"95%\"/>\n</p>\n\n### This repo "
  },
  {
    "path": "client/.babelrc",
    "chars": 87,
    "preview": "{\n  \"presets\": [\"next/babel\"],\n  \"plugins\": [[\"styled-components\", { \"ssr\": true }]]\n}\n"
  },
  {
    "path": "client/.eslintignore",
    "chars": 13,
    "preview": "node_modules/"
  },
  {
    "path": "client/.eslintrc.js",
    "chars": 622,
    "preview": "module.exports = {\n  env: {\n    browser: true,\n    es2021: true,\n  },\n  extends: [\n    'eslint:recommended',\n    'plugin"
  },
  {
    "path": "client/.gitignore",
    "chars": 386,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "client/codegen.yml",
    "chars": 218,
    "preview": "overwrite: true\nschema: 'http://localhost:4000'\ndocuments: 'src/graphql/**/*.graphql'\ngenerates:\n  src/generated/graphql"
  },
  {
    "path": "client/next-env.d.ts",
    "chars": 75,
    "preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/types/global\" />\n"
  },
  {
    "path": "client/package.json",
    "chars": 1163,
    "preview": "{\n  \"name\": \"client\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next "
  },
  {
    "path": "client/src/components/Components.txt",
    "chars": 271,
    "preview": "I like to break my components up into elements and modules. \n\nAn element is an invidual component that may be used in mu"
  },
  {
    "path": "client/src/components/elements/Nav/Nav.tsx",
    "chars": 267,
    "preview": "import { AppBar, Toolbar, Typography } from '@material-ui/core'\n\nexport const Nav: React.FC = () => {\n  return (\n    <Ap"
  },
  {
    "path": "client/src/components/elements/ThemeToggle/ThemeToggle.styled.ts",
    "chars": 170,
    "preview": "import styled from 'styled-components'\n\nexport const SwitchContainer = styled.div`\n  position: fixed;\n  top: 1%;\n  right"
  },
  {
    "path": "client/src/components/elements/ThemeToggle/ThemeToggle.tsx",
    "chars": 1413,
    "preview": "import { useContext } from 'react'\nimport { FaMoon, FaSun } from 'react-icons/fa'\nimport Switch from 'react-switch'\n\nimp"
  },
  {
    "path": "client/src/components/elements/index.ts",
    "chars": 88,
    "preview": "export { Nav } from './Nav/Nav'\nexport { ThemeToggle } from './ThemeToggle/ThemeToggle'\n"
  },
  {
    "path": "client/src/components/modules/index.ts",
    "chars": 10,
    "preview": "export {}\n"
  },
  {
    "path": "client/src/config/config.ts",
    "chars": 273,
    "preview": "const dev = process.env.NODE_ENV !== 'production'\n\nexport const URL = dev\n  ? 'http://localhost:3000/api'\n  : 'https://f"
  },
  {
    "path": "client/src/generated/graphql.tsx",
    "chars": 3610,
    "preview": "import gql from 'graphql-tag';\nimport * as Urql from 'urql';\nexport type Maybe<T> = T | null;\nexport type Exact<T extend"
  },
  {
    "path": "client/src/graphql/mutations/createUser.graphql",
    "chars": 264,
    "preview": "mutation CreateUser($username: String!, $email: String!, $password: String!) {\n  createUser(\n    options: { username: $u"
  },
  {
    "path": "client/src/graphql/queries/getUser.graphql",
    "chars": 84,
    "preview": "query getUser($id: String!) {\n  user(id: $id) {\n    id\n    username\n    email\n  }\n}\n"
  },
  {
    "path": "client/src/graphql/queries/getUsers.graphql",
    "chars": 63,
    "preview": "query getUsers {\n  users {\n    id\n    username\n    email\n  }\n}\n"
  },
  {
    "path": "client/src/hooks/useMediaQuery.ts",
    "chars": 486,
    "preview": "import { useState, useEffect } from 'react'\n\nexport function useMediaQuery(query: string) {\n  const [matches, setMatches"
  },
  {
    "path": "client/src/pages/404.tsx",
    "chars": 85,
    "preview": "const Error: React.FC = () => {\n  return <div>404 Error</div>\n}\nexport default Error\n"
  },
  {
    "path": "client/src/pages/_app.tsx",
    "chars": 500,
    "preview": "import Head from 'next/head'\nimport type { AppProps } from 'next/app'\n\nimport { AppProvider } from '../providers/AppProv"
  },
  {
    "path": "client/src/pages/_document.tsx",
    "chars": 1065,
    "preview": "import React from 'react'\nimport Document, { Html, Head, Main, NextScript } from 'next/document'\nimport { ServerStyleShe"
  },
  {
    "path": "client/src/pages/api/hello.ts",
    "chars": 107,
    "preview": "export default (req: any, res: any) => {\n  console.log(req)\n  res.status(200).json({ name: 'John Doe' })\n}\n"
  },
  {
    "path": "client/src/pages/index.tsx",
    "chars": 1789,
    "preview": "import { withUrqlClient } from 'next-urql'\nimport styled from 'styled-components'\n\nimport { /*useGetUserQuery*/ useGetUs"
  },
  {
    "path": "client/src/providers/AppProvider.tsx",
    "chars": 1107,
    "preview": "import React, { useEffect, createContext, useState, useMemo } from 'react'\nimport { ThemeProvider } from 'styled-compone"
  },
  {
    "path": "client/src/styles/constantStyles.ts",
    "chars": 514,
    "preview": "import styled from 'styled-components'\nimport { Grid } from '@material-ui/core'\n\nexport const CenterContainer = styled.d"
  },
  {
    "path": "client/src/styles/global.ts",
    "chars": 362,
    "preview": "import { createGlobalStyle, css } from 'styled-components'\n\nexport default createGlobalStyle`\n${({ theme }) => css`\n  ht"
  },
  {
    "path": "client/src/styles/index.ts",
    "chars": 94,
    "preview": "export { default as GlobalStyles } from './global'\nexport { default as theme } from './theme'\n"
  },
  {
    "path": "client/src/styles/styled.d.ts",
    "chars": 163,
    "preview": "import {} from 'styled-components'\nimport { ThemeType } from './theme'\ndeclare module 'styled-components' {\n  export int"
  },
  {
    "path": "client/src/styles/theme.ts",
    "chars": 428,
    "preview": "export type ThemeType = typeof theme['light']\n\nconst theme = {\n  light: {\n    background: '#ACDDDE',\n    secondary: '#CA"
  },
  {
    "path": "client/src/util/createURQLClient.ts",
    "chars": 812,
    "preview": "import { dedupExchange, cacheExchange, fetchExchange } from '@urql/core'\n\nimport { serverURL } from '../config/config'\n/"
  },
  {
    "path": "client/src/util/isServer.ts",
    "chars": 60,
    "preview": "export const isServer = () => typeof window === 'undefined'\n"
  },
  {
    "path": "client/tsconfig.json",
    "chars": 484,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"sk"
  },
  {
    "path": "server/.dockerignore",
    "chars": 28,
    "preview": "  node_modules\nnpm-debug.log"
  },
  {
    "path": "server/.eslintignore",
    "chars": 12,
    "preview": "node_modules"
  },
  {
    "path": "server/.eslintrc.js",
    "chars": 281,
    "preview": "module.exports = {\n  env: {\n    browser: true,\n    commonjs: true,\n    es2021: true,\n  },\n  extends: ['standard'],\n  par"
  },
  {
    "path": "server/.gitignore",
    "chars": 47,
    "preview": "#   add .env for real application\nnode_modules/"
  },
  {
    "path": "server/Dockerfile",
    "chars": 180,
    "preview": "FROM node:14\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\n\nRUN npm install\n\nCOPY . .\nCOPY .env.production .env\n\nENV NODE"
  },
  {
    "path": "server/dist/config.js",
    "chars": 196,
    "preview": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.__prod__ = void 0;\nexports.__prod__"
  },
  {
    "path": "server/dist/entities/UserAccount.js",
    "chars": 2139,
    "preview": "\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n    var c = argum"
  },
  {
    "path": "server/dist/entities/index.js",
    "chars": 281,
    "preview": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar UserAccount_1 = require(\"./UserAccount\""
  },
  {
    "path": "server/dist/index.js",
    "chars": 2593,
    "preview": "\"use strict\";\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n    function ad"
  },
  {
    "path": "server/dist/middleware/isAuth.js",
    "chars": 34,
    "preview": "//# sourceMappingURL=isAuth.js.map"
  },
  {
    "path": "server/dist/migrations/1622333914717-initDB.js",
    "chars": 1754,
    "preview": "\"use strict\";\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n    function ad"
  },
  {
    "path": "server/dist/migrations/1622348668437-MockUsers.js",
    "chars": 2199,
    "preview": "\"use strict\";\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n    function ad"
  },
  {
    "path": "server/dist/resolvers/UserAccount.js",
    "chars": 6341,
    "preview": "\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n    if ("
  },
  {
    "path": "server/dist/resolvers/index.js",
    "chars": 283,
    "preview": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nvar UserAccount_1 = require(\"./UserAccount\""
  },
  {
    "path": "server/dist/resolvers/userInput.js",
    "chars": 1447,
    "preview": "\"use strict\";\nvar __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n    var c = argum"
  },
  {
    "path": "server/dist/types.js",
    "chars": 110,
    "preview": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=types.js.map"
  },
  {
    "path": "server/dist/utils/validateRegister.js",
    "chars": 975,
    "preview": "\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.validateRegister = void 0;\nexports."
  },
  {
    "path": "server/ormconfig.json",
    "chars": 187,
    "preview": "{\n  \"type\": \"postgres\",\n  \"host\": \"localhost\",\n  \"port\": \"5432\",\n  \"username\": \"postgres\",\n  \"password\": \"postgres\",\n  \""
  },
  {
    "path": "server/package.json",
    "chars": 1478,
    "preview": "{\n  \"name\": \"wern-fullstack-template-server\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"script"
  },
  {
    "path": "server/src/config.ts",
    "chars": 62,
    "preview": "export const __prod__ = process.env.NODE_ENV === 'production'\n"
  },
  {
    "path": "server/src/entities/UserAccount.ts",
    "chars": 579,
    "preview": "import { ObjectType, Field } from 'type-graphql'\nimport {\n  Entity,\n  PrimaryGeneratedColumn,\n  CreateDateColumn,\n  Upda"
  },
  {
    "path": "server/src/entities/index.ts",
    "chars": 44,
    "preview": "export { UserAccount } from './UserAccount'\n"
  },
  {
    "path": "server/src/env.d.ts",
    "chars": 177,
    "preview": "declare namespace NodeJS {\n  interface ProcessEnv {\n    DATABASE_URL: string;\n    REDIS_URL: string;\n    PORT: string;\n "
  },
  {
    "path": "server/src/index.ts",
    "chars": 1533,
    "preview": "import 'reflect-metadata'\nimport 'dotenv-safe/config'\nimport express from 'express'\nimport path from 'path'\nimport cors "
  },
  {
    "path": "server/src/middleware/isAuth.ts",
    "chars": 279,
    "preview": "// import { MiddlewareFn } from 'type-graphql'\n// import { MyContext } from '../types'\n\n// export const isAuth: Middlewa"
  },
  {
    "path": "server/src/migrations/1622333914717-initDB.ts",
    "chars": 839,
    "preview": "import { MigrationInterface, QueryRunner } from 'typeorm'\n\nexport class initDB1622333914717 implements MigrationInterfac"
  },
  {
    "path": "server/src/migrations/1622348668437-MockUsers.ts",
    "chars": 1317,
    "preview": "import { MigrationInterface, QueryRunner } from 'typeorm'\n\nexport class MockUsers1622348668437 implements MigrationInter"
  },
  {
    "path": "server/src/resolvers/UserAccount.ts",
    "chars": 2024,
    "preview": "import {\n  Resolver,\n  Mutation,\n  Arg,\n  Field,\n  // Ctx,\n  ObjectType,\n  Query,\n  // FieldResolver,\n  // Root,\n} from "
  },
  {
    "path": "server/src/resolvers/index.ts",
    "chars": 45,
    "preview": "export { UserResolver } from './UserAccount'\n"
  },
  {
    "path": "server/src/resolvers/userInput.ts",
    "chars": 176,
    "preview": "import { InputType, Field } from 'type-graphql'\n\n@InputType()\nexport class UserInput {\n  @Field()\n  email: string\n  @Fie"
  },
  {
    "path": "server/src/types.ts",
    "chars": 104,
    "preview": "import { Request, Response } from 'express'\n\nexport type MyContext = {\n  req: Request\n  res: Response\n}\n"
  },
  {
    "path": "server/src/utils/validateRegister.ts",
    "chars": 723,
    "preview": "import { UserInput } from '../resolvers/userInput'\n\nexport const validateRegister = (options: UserInput) => {\n  if (!opt"
  },
  {
    "path": "server/tsconfig.json",
    "chars": 824,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es6\",\n    \"module\": \"commonjs\",\n    \"lib\": [\"dom\", \"es6\", \"es2017\", \"esnext.asyn"
  }
]

About this extraction

This page contains the full source code of the braydenwerner/Wern-Fullstack-Template GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 69 files (48.3 KB), approximately 15.2k tokens, and a symbol index with 73 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!