Compare commits
1 Commits
auth-backe
...
solid-urql
| Author | SHA1 | Date | |
|---|---|---|---|
| fbe19ff41d |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -57,7 +57,7 @@ node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
#.env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
.vercel
|
||||
@@ -65,5 +65,3 @@ node_modules
|
||||
dist
|
||||
.graphqlrc.yml
|
||||
codegen.yml
|
||||
backend/src/config/kc.config.json
|
||||
backend/.env
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir : __dirname,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
||||
35
backend/.gitignore
vendored
35
backend/.gitignore
vendored
@@ -1,35 +0,0 @@
|
||||
# compiled output
|
||||
/dist
|
||||
/node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
## Running the app
|
||||
|
||||
```bash
|
||||
# development
|
||||
$ npm run start
|
||||
|
||||
# watch mode
|
||||
$ npm run start:dev
|
||||
|
||||
# production mode
|
||||
$ npm run start:prod
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ npm run test
|
||||
|
||||
# e2e tests
|
||||
$ npm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ npm run test:cov
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
|
||||
## Stay in touch
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
|
||||
## License
|
||||
|
||||
Nest is [MIT licensed](LICENSE).
|
||||
@@ -1,11 +0,0 @@
|
||||
import { GraphQLDefinitionsFactory } from '@nestjs/graphql';
|
||||
import { join } from 'path';
|
||||
|
||||
const definitionFactory = new GraphQLDefinitionsFactory();
|
||||
|
||||
definitionFactory.generate({
|
||||
typePaths: ['./**/*.graphql'],
|
||||
path: join(process.cwd(), 'src/graphql/graphql.typings.ts'),
|
||||
outputAs: 'class',
|
||||
watch: true,
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
/*
|
||||
* -------------------------------------------------------
|
||||
* THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
|
||||
* -------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export class CreateUserInput {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export class User {
|
||||
id: string;
|
||||
email: string;
|
||||
time_joined: number;
|
||||
}
|
||||
|
||||
export abstract class IQuery {
|
||||
abstract users(): Nullable<User>[] | Promise<Nullable<User>[]>;
|
||||
|
||||
abstract user(id: string): Nullable<User> | Promise<Nullable<User>>;
|
||||
}
|
||||
|
||||
export abstract class IMutation {
|
||||
abstract createUser(createUserInput: CreateUserInput): User | Promise<User>;
|
||||
|
||||
abstract removeUser(id: string): Nullable<User> | Promise<Nullable<User>>;
|
||||
}
|
||||
|
||||
export type DateTime = any;
|
||||
type Nullable<T> = T | null;
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src"
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"gen:types": "ts-node ./graphql/generate.typings",
|
||||
"prisma:gen": "prisma generate --watch",
|
||||
"dev": "concurrently \"npm:start:dev\" \"npm:gen:types\" \"npm:prisma:gen\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/apollo": "^10.1.0",
|
||||
"@nestjs/common": "^9.0.0",
|
||||
"@nestjs/config": "^2.2.0",
|
||||
"@nestjs/core": "^9.0.0",
|
||||
"@nestjs/graphql": "^10.1.1",
|
||||
"@nestjs/mapped-types": "*",
|
||||
"@nestjs/platform-express": "^9.0.0",
|
||||
"@prisma/client": "4.3.1",
|
||||
"apollo-server-express": "^3.10.2",
|
||||
"graphql": "^16.6.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.2.0",
|
||||
"supertokens-node": "^11.3.0",
|
||||
"ts-morph": "^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^9.0.0",
|
||||
"@nestjs/schematics": "^9.0.0",
|
||||
"@nestjs/testing": "^9.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "28.1.8",
|
||||
"@types/node": "^16.0.0",
|
||||
"@types/supertest": "^2.0.11",
|
||||
"concurrently": "^7.4.0",
|
||||
"jest": "28.1.3",
|
||||
"prettier": "^2.3.2",
|
||||
"prisma": "4.3.1",
|
||||
"source-map-support": "^0.5.20",
|
||||
"supertest": "^6.1.3",
|
||||
"ts-jest": "28.0.8",
|
||||
"ts-loader": "^9.2.3",
|
||||
"ts-node": "^10.0.0",
|
||||
"tsconfig-paths": "4.1.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
"js",
|
||||
"json",
|
||||
"ts"
|
||||
],
|
||||
"rootDir": "src",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
},
|
||||
"collectCoverageFrom": [
|
||||
"**/*.(t|j)s"
|
||||
],
|
||||
"coverageDirectory": "../coverage",
|
||||
"testEnvironment": "node"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"time_joined" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
@@ -1,3 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "password" TEXT,
|
||||
ALTER COLUMN "time_joined" DROP NOT NULL;
|
||||
@@ -1,3 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "createdAt" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||
ADD COLUMN "updatedAt" TIMESTAMP(3);
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `User` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropTable
|
||||
DROP TABLE "User";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "all_auth_recipe_users" (
|
||||
"user_id" CHAR(36) NOT NULL,
|
||||
"recipe_id" VARCHAR(128) NOT NULL,
|
||||
"time_joined" BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT "all_auth_recipe_users_pkey" PRIMARY KEY ("user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "emailpassword_pswd_reset_tokens" (
|
||||
"user_id" CHAR(36) NOT NULL,
|
||||
"token" VARCHAR(128) NOT NULL,
|
||||
"token_expiry" BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT "emailpassword_pswd_reset_tokens_pkey" PRIMARY KEY ("user_id","token")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "emailpassword_users" (
|
||||
"user_id" CHAR(36) NOT NULL,
|
||||
"email" VARCHAR(256) NOT NULL,
|
||||
"password_hash" VARCHAR(128) NOT NULL,
|
||||
"time_joined" BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT "emailpassword_users_pkey" PRIMARY KEY ("user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "emailverification_tokens" (
|
||||
"user_id" VARCHAR(128) NOT NULL,
|
||||
"email" VARCHAR(256) NOT NULL,
|
||||
"token" VARCHAR(128) NOT NULL,
|
||||
"token_expiry" BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT "emailverification_tokens_pkey" PRIMARY KEY ("user_id","email","token")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "emailverification_verified_emails" (
|
||||
"user_id" VARCHAR(128) NOT NULL,
|
||||
"email" VARCHAR(256) NOT NULL,
|
||||
|
||||
CONSTRAINT "emailverification_verified_emails_pkey" PRIMARY KEY ("user_id","email")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "jwt_signing_keys" (
|
||||
"key_id" VARCHAR(255) NOT NULL,
|
||||
"key_string" TEXT NOT NULL,
|
||||
"algorithm" VARCHAR(10) NOT NULL,
|
||||
"created_at" BIGINT,
|
||||
|
||||
CONSTRAINT "jwt_signing_keys_pkey" PRIMARY KEY ("key_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "key_value" (
|
||||
"name" VARCHAR(128) NOT NULL,
|
||||
"value" TEXT,
|
||||
"created_at_time" BIGINT,
|
||||
|
||||
CONSTRAINT "key_value_pkey" PRIMARY KEY ("name")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "passwordless_codes" (
|
||||
"code_id" CHAR(36) NOT NULL,
|
||||
"device_id_hash" CHAR(44) NOT NULL,
|
||||
"link_code_hash" CHAR(44) NOT NULL,
|
||||
"created_at" BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT "passwordless_codes_pkey" PRIMARY KEY ("code_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "passwordless_devices" (
|
||||
"device_id_hash" CHAR(44) NOT NULL,
|
||||
"email" VARCHAR(256),
|
||||
"phone_number" VARCHAR(256),
|
||||
"link_code_salt" CHAR(44) NOT NULL,
|
||||
"failed_attempts" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "passwordless_devices_pkey" PRIMARY KEY ("device_id_hash")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "passwordless_users" (
|
||||
"user_id" CHAR(36) NOT NULL,
|
||||
"email" VARCHAR(256),
|
||||
"phone_number" VARCHAR(256),
|
||||
"time_joined" BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT "passwordless_users_pkey" PRIMARY KEY ("user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "role_permissions" (
|
||||
"role" VARCHAR(255) NOT NULL,
|
||||
"permission" VARCHAR(255) NOT NULL,
|
||||
|
||||
CONSTRAINT "role_permissions_pkey" PRIMARY KEY ("role","permission")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "roles" (
|
||||
"role" VARCHAR(255) NOT NULL,
|
||||
|
||||
CONSTRAINT "roles_pkey" PRIMARY KEY ("role")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "session_access_token_signing_keys" (
|
||||
"created_at_time" BIGINT NOT NULL,
|
||||
"value" TEXT,
|
||||
|
||||
CONSTRAINT "session_access_token_signing_keys_pkey" PRIMARY KEY ("created_at_time")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "session_info" (
|
||||
"session_handle" VARCHAR(255) NOT NULL,
|
||||
"user_id" VARCHAR(128) NOT NULL,
|
||||
"refresh_token_hash_2" VARCHAR(128) NOT NULL,
|
||||
"session_data" TEXT,
|
||||
"expires_at" BIGINT NOT NULL,
|
||||
"created_at_time" BIGINT NOT NULL,
|
||||
"jwt_user_payload" TEXT,
|
||||
|
||||
CONSTRAINT "session_info_pkey" PRIMARY KEY ("session_handle")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "thirdparty_users" (
|
||||
"third_party_id" VARCHAR(28) NOT NULL,
|
||||
"third_party_user_id" VARCHAR(128) NOT NULL,
|
||||
"user_id" CHAR(36) NOT NULL,
|
||||
"email" VARCHAR(256) NOT NULL,
|
||||
"time_joined" BIGINT NOT NULL,
|
||||
|
||||
CONSTRAINT "thirdparty_users_pkey" PRIMARY KEY ("third_party_id","third_party_user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_metadata" (
|
||||
"user_id" VARCHAR(128) NOT NULL,
|
||||
"user_metadata" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "user_metadata_pkey" PRIMARY KEY ("user_id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_roles" (
|
||||
"user_id" VARCHAR(128) NOT NULL,
|
||||
"role" VARCHAR(255) NOT NULL,
|
||||
|
||||
CONSTRAINT "user_roles_pkey" PRIMARY KEY ("user_id","role")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "userid_mapping" (
|
||||
"supertokens_user_id" CHAR(36) NOT NULL,
|
||||
"external_user_id" VARCHAR(128) NOT NULL,
|
||||
"external_user_id_info" TEXT,
|
||||
|
||||
CONSTRAINT "userid_mapping_pkey" PRIMARY KEY ("supertokens_user_id","external_user_id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "all_auth_recipe_users_pagination_index" ON "all_auth_recipe_users"("time_joined" DESC, "user_id" DESC);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "emailpassword_pswd_reset_tokens_token_key" ON "emailpassword_pswd_reset_tokens"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "emailpassword_password_reset_token_expiry_index" ON "emailpassword_pswd_reset_tokens"("token_expiry");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "emailpassword_users_email_key" ON "emailpassword_users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "emailverification_tokens_token_key" ON "emailverification_tokens"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "emailverification_tokens_index" ON "emailverification_tokens"("token_expiry");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "passwordless_codes_link_code_hash_key" ON "passwordless_codes"("link_code_hash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "passwordless_codes_created_at_index" ON "passwordless_codes"("created_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "passwordless_codes_device_id_hash_index" ON "passwordless_codes"("device_id_hash");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "passwordless_devices_email_index" ON "passwordless_devices"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "passwordless_devices_phone_number_index" ON "passwordless_devices"("phone_number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "passwordless_users_email_key" ON "passwordless_users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "passwordless_users_phone_number_key" ON "passwordless_users"("phone_number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "role_permissions_permission_index" ON "role_permissions"("permission");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "thirdparty_users_user_id_key" ON "thirdparty_users"("user_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_roles_role_index" ON "user_roles"("role");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "userid_mapping_supertokens_user_id_key" ON "userid_mapping"("supertokens_user_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "userid_mapping_external_user_id_key" ON "userid_mapping"("external_user_id");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "emailpassword_pswd_reset_tokens" ADD CONSTRAINT "emailpassword_pswd_reset_tokens_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "emailpassword_users"("user_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "passwordless_codes" ADD CONSTRAINT "passwordless_codes_device_id_hash_fkey" FOREIGN KEY ("device_id_hash") REFERENCES "passwordless_devices"("device_id_hash") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_role_fkey" FOREIGN KEY ("role") REFERENCES "roles"("role") ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_fkey" FOREIGN KEY ("role") REFERENCES "roles"("role") ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "userid_mapping" ADD CONSTRAINT "userid_mapping_supertokens_user_id_fkey" FOREIGN KEY ("supertokens_user_id") REFERENCES "all_auth_recipe_users"("user_id") ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
@@ -1,3 +0,0 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
@@ -1,15 +0,0 @@
|
||||
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
@Injectable()
|
||||
export class PrismaService extends PrismaClient implements OnModuleInit {
|
||||
async onModuleInit() {
|
||||
await this.$connect();
|
||||
}
|
||||
|
||||
async enableShutdownHooks(app: INestApplication) {
|
||||
this.$on('beforeExit', async () => {
|
||||
await app.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model all_auth_recipe_users {
|
||||
user_id String @id @db.Char(36)
|
||||
recipe_id String @db.VarChar(128)
|
||||
time_joined BigInt
|
||||
userid_mapping userid_mapping?
|
||||
|
||||
@@index([time_joined(sort: Desc), user_id(sort: Desc)], map: "all_auth_recipe_users_pagination_index")
|
||||
}
|
||||
|
||||
model emailpassword_pswd_reset_tokens {
|
||||
user_id String @db.Char(36)
|
||||
token String @unique @db.VarChar(128)
|
||||
token_expiry BigInt
|
||||
emailpassword_users emailpassword_users @relation(fields: [user_id], references: [user_id], onDelete: Cascade)
|
||||
|
||||
@@id([user_id, token])
|
||||
@@index([token_expiry], map: "emailpassword_password_reset_token_expiry_index")
|
||||
}
|
||||
|
||||
model emailpassword_users {
|
||||
user_id String @id @db.Char(36)
|
||||
email String @unique @db.VarChar(256)
|
||||
password_hash String @db.VarChar(128)
|
||||
time_joined BigInt
|
||||
emailpassword_pswd_reset_tokens emailpassword_pswd_reset_tokens[]
|
||||
}
|
||||
|
||||
model emailverification_tokens {
|
||||
user_id String @db.VarChar(128)
|
||||
email String @db.VarChar(256)
|
||||
token String @unique @db.VarChar(128)
|
||||
token_expiry BigInt
|
||||
|
||||
@@id([user_id, email, token])
|
||||
@@index([token_expiry], map: "emailverification_tokens_index")
|
||||
}
|
||||
|
||||
model emailverification_verified_emails {
|
||||
user_id String @db.VarChar(128)
|
||||
email String @db.VarChar(256)
|
||||
|
||||
@@id([user_id, email])
|
||||
}
|
||||
|
||||
model jwt_signing_keys {
|
||||
key_id String @id @db.VarChar(255)
|
||||
key_string String
|
||||
algorithm String @db.VarChar(10)
|
||||
created_at BigInt?
|
||||
}
|
||||
|
||||
model key_value {
|
||||
name String @id @db.VarChar(128)
|
||||
value String?
|
||||
created_at_time BigInt?
|
||||
}
|
||||
|
||||
model passwordless_codes {
|
||||
code_id String @id @db.Char(36)
|
||||
device_id_hash String @db.Char(44)
|
||||
link_code_hash String @unique @db.Char(44)
|
||||
created_at BigInt
|
||||
passwordless_devices passwordless_devices @relation(fields: [device_id_hash], references: [device_id_hash], onDelete: Cascade)
|
||||
|
||||
@@index([created_at], map: "passwordless_codes_created_at_index")
|
||||
@@index([device_id_hash], map: "passwordless_codes_device_id_hash_index")
|
||||
}
|
||||
|
||||
model passwordless_devices {
|
||||
device_id_hash String @id @db.Char(44)
|
||||
email String? @db.VarChar(256)
|
||||
phone_number String? @db.VarChar(256)
|
||||
link_code_salt String @db.Char(44)
|
||||
failed_attempts Int
|
||||
passwordless_codes passwordless_codes[]
|
||||
|
||||
@@index([email], map: "passwordless_devices_email_index")
|
||||
@@index([phone_number], map: "passwordless_devices_phone_number_index")
|
||||
}
|
||||
|
||||
model passwordless_users {
|
||||
user_id String @id @db.Char(36)
|
||||
email String? @unique @db.VarChar(256)
|
||||
phone_number String? @unique @db.VarChar(256)
|
||||
time_joined BigInt
|
||||
}
|
||||
|
||||
model role_permissions {
|
||||
role String @db.VarChar(255)
|
||||
permission String @db.VarChar(255)
|
||||
roles roles @relation(fields: [role], references: [role], onDelete: Cascade, onUpdate: NoAction)
|
||||
|
||||
@@id([role, permission])
|
||||
@@index([permission], map: "role_permissions_permission_index")
|
||||
}
|
||||
|
||||
model roles {
|
||||
role String @id @db.VarChar(255)
|
||||
role_permissions role_permissions[]
|
||||
user_roles user_roles[]
|
||||
}
|
||||
|
||||
model session_access_token_signing_keys {
|
||||
created_at_time BigInt @id
|
||||
value String?
|
||||
}
|
||||
|
||||
model session_info {
|
||||
session_handle String @id @db.VarChar(255)
|
||||
user_id String @db.VarChar(128)
|
||||
refresh_token_hash_2 String @db.VarChar(128)
|
||||
session_data String?
|
||||
expires_at BigInt
|
||||
created_at_time BigInt
|
||||
jwt_user_payload String?
|
||||
}
|
||||
|
||||
model thirdparty_users {
|
||||
third_party_id String @db.VarChar(28)
|
||||
third_party_user_id String @db.VarChar(128)
|
||||
user_id String @unique @db.Char(36)
|
||||
email String @db.VarChar(256)
|
||||
time_joined BigInt
|
||||
|
||||
@@id([third_party_id, third_party_user_id])
|
||||
}
|
||||
|
||||
model user_metadata {
|
||||
user_id String @id @db.VarChar(128)
|
||||
user_metadata String
|
||||
}
|
||||
|
||||
model user_roles {
|
||||
user_id String @db.VarChar(128)
|
||||
role String @db.VarChar(255)
|
||||
roles roles @relation(fields: [role], references: [role], onDelete: Cascade, onUpdate: NoAction)
|
||||
|
||||
@@id([user_id, role])
|
||||
@@index([role], map: "user_roles_role_index")
|
||||
}
|
||||
|
||||
model userid_mapping {
|
||||
supertokens_user_id String @unique @db.Char(36)
|
||||
external_user_id String @unique @db.VarChar(128)
|
||||
external_user_id_info String?
|
||||
all_auth_recipe_users all_auth_recipe_users @relation(fields: [supertokens_user_id], references: [user_id], onDelete: Cascade, onUpdate: NoAction)
|
||||
|
||||
@@id([supertokens_user_id, external_user_id])
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Controller, Get, Session, UseGuards } from '@nestjs/common';
|
||||
import { AuthGuard } from './auth/guards/auth.guard';
|
||||
import { SessionContainer } from "supertokens-node/recipe/session";
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
|
||||
@Get()
|
||||
getHello(): string {
|
||||
return "API";
|
||||
}
|
||||
|
||||
@Get('test')
|
||||
@UseGuards(AuthGuard)
|
||||
async getTest(@Session() session: SessionContainer): Promise<string> {
|
||||
// TODO: magic
|
||||
return "magic";
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { GraphQLISODateTime, GraphQLModule } from '@nestjs/graphql';
|
||||
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
import { ApolloServerPluginLandingPageLocalDefault } from 'apollo-server-core';
|
||||
// import { UsersModule } from './users/users.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot(),
|
||||
AuthModule.forRoot({
|
||||
connectionURI: process.env.ST_API_URL,
|
||||
apiKey: process.env.ST_API_KEY,
|
||||
appInfo: {
|
||||
appName: process.env.APP_NAME,
|
||||
apiDomain: process.env.APP_URL,
|
||||
websiteDomain: process.env.WEBAPP_URL,
|
||||
apiBasePath: '/auth/api',
|
||||
websiteBasePath: '/auth',
|
||||
},
|
||||
}),
|
||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||
driver: ApolloDriver,
|
||||
typePaths: ['./**/*.graphql'],
|
||||
debug: true,
|
||||
playground: false,
|
||||
resolvers: { DateTime: GraphQLISODateTime },
|
||||
plugins: [ApolloServerPluginLandingPageLocalDefault()],
|
||||
}),
|
||||
// UsersModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [],
|
||||
})
|
||||
export class AppModule {}
|
||||
@@ -1,43 +0,0 @@
|
||||
import {
|
||||
DynamicModule,
|
||||
MiddlewareConsumer,
|
||||
Module,
|
||||
NestModule,
|
||||
} from '@nestjs/common';
|
||||
import { AuthMiddleware } from './middlewares/auth.middleware';
|
||||
import { AuthModuleConfig, ConfigInjectionToken } from './interfaces/config.interface';
|
||||
import { SupertokensService } from './supertokens/supertokens.service';
|
||||
|
||||
@Module({
|
||||
providers: [],
|
||||
exports: [],
|
||||
controllers: [],
|
||||
})
|
||||
export class AuthModule implements NestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer.apply(AuthMiddleware).forRoutes('*');
|
||||
}
|
||||
|
||||
static forRoot({
|
||||
connectionURI,
|
||||
apiKey,
|
||||
appInfo,
|
||||
}: AuthModuleConfig): DynamicModule {
|
||||
return {
|
||||
providers: [
|
||||
{
|
||||
useValue: {
|
||||
appInfo,
|
||||
connectionURI,
|
||||
apiKey,
|
||||
},
|
||||
provide: ConfigInjectionToken,
|
||||
},
|
||||
SupertokensService,
|
||||
],
|
||||
exports: [],
|
||||
imports: [],
|
||||
module: AuthModule,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||
|
||||
export const Session = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
return request.session;
|
||||
},
|
||||
);
|
||||
@@ -1,29 +0,0 @@
|
||||
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
|
||||
import { errorHandler } from 'supertokens-node/framework/express';
|
||||
import { Error as STError } from 'supertokens-node';
|
||||
import { Request, Response, NextFunction, ErrorRequestHandler } from 'express';
|
||||
|
||||
|
||||
@Catch(STError)
|
||||
export class SupertokensExceptionFilter implements ExceptionFilter {
|
||||
handler: ErrorRequestHandler;
|
||||
constructor() {
|
||||
this.handler = errorHandler();
|
||||
}
|
||||
catch(exception: Error, host: ArgumentsHost) {
|
||||
const ctx = host.switchToHttp();
|
||||
|
||||
const resp = ctx.getResponse<Response>();
|
||||
if (resp.headersSent) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handler(
|
||||
exception,
|
||||
ctx.getRequest<Request>(),
|
||||
resp,
|
||||
ctx.getNext<NextFunction>(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
|
||||
import { Error as STError } from 'supertokens-node';
|
||||
|
||||
import { verifySession } from 'supertokens-node/recipe/session/framework/express';
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const ctx = context.switchToHttp();
|
||||
|
||||
let err = undefined;
|
||||
const resp = ctx.getResponse();
|
||||
// You can create an optional version of this by passing {sessionRequired: false} to verifySession
|
||||
await verifySession()(ctx.getRequest(), resp, (res) => {
|
||||
err = res;
|
||||
});
|
||||
|
||||
if (resp.headersSent) {
|
||||
throw new STError({
|
||||
message: 'RESPONSE_SENT',
|
||||
type: 'RESPONSE_SENT',
|
||||
});
|
||||
}
|
||||
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { AppInfo } from 'supertokens-node/types';
|
||||
|
||||
export const ConfigInjectionToken = 'ConfigInjectionToken';
|
||||
|
||||
export type AuthModuleConfig = {
|
||||
appInfo: AppInfo;
|
||||
connectionURI: string;
|
||||
apiKey?: string;
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { middleware } from 'supertokens-node/framework/express';
|
||||
|
||||
@Injectable()
|
||||
export class AuthMiddleware implements NestMiddleware {
|
||||
supertokensMiddleware: any;
|
||||
|
||||
constructor() {
|
||||
this.supertokensMiddleware = middleware();
|
||||
}
|
||||
|
||||
use(req: Request, res: any, next: () => void) {
|
||||
return this.supertokensMiddleware(req, res, next);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
AuthModuleConfig,
|
||||
ConfigInjectionToken,
|
||||
} from '../interfaces/config.interface';
|
||||
import supertokens from 'supertokens-node';
|
||||
import ThirdPartyEmailPassword from 'supertokens-node/recipe/thirdpartyemailpassword';
|
||||
import EmailPassword from 'supertokens-node/recipe/emailpassword';
|
||||
import { STMPService } from 'supertokens-node/recipe/thirdpartyemailpassword/emaildelivery';
|
||||
|
||||
import Session from 'supertokens-node/recipe/session';
|
||||
|
||||
@Injectable()
|
||||
export class SupertokensService {
|
||||
constructor(@Inject(ConfigInjectionToken) private config: AuthModuleConfig) {
|
||||
supertokens.init({
|
||||
appInfo: config.appInfo,
|
||||
supertokens: {
|
||||
connectionURI: config.connectionURI,
|
||||
apiKey: config.apiKey,
|
||||
},
|
||||
recipeList: [
|
||||
EmailPassword.init({
|
||||
emailDelivery: {
|
||||
service: new STMPService({
|
||||
smtpSettings: {
|
||||
host: process.env.SMTP_HOST,
|
||||
authUsername: process.env.SMTP_USERNAME,
|
||||
password: process.env.SMTP_PASSWORD,
|
||||
port: parseInt(process.env.SMTP_PORT),
|
||||
from: {
|
||||
name: process.env.SMTP_FROM_NAME,
|
||||
email: process.env.SMTP_FROM_EMAIL,
|
||||
},
|
||||
secure: process.env.SMTP_SECURE ? true : false,
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
ThirdPartyEmailPassword.init({
|
||||
providers: [
|
||||
ThirdPartyEmailPassword.Google({
|
||||
clientId:
|
||||
'1060725074195-kmeum4crr01uirfl2op9kd5acmi9jutn.apps.googleusercontent.com',
|
||||
clientSecret: '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',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
Session.init({
|
||||
// antiCsrf: "VIA_CUSTOM_HEADER",
|
||||
jwt: {
|
||||
enable: true,
|
||||
issuer: `${process.env.APP_URL}/auth/api`,
|
||||
},
|
||||
override: {
|
||||
functions: function (originalImplementation) {
|
||||
return {
|
||||
...originalImplementation,
|
||||
createNewSession: async function (input) {
|
||||
input.accessTokenPayload = {
|
||||
...input.accessTokenPayload,
|
||||
'https://hasura.io/jwt/claims': {
|
||||
'x-hasura-user-id': input.userId,
|
||||
'x-hasura-default-role': 'user',
|
||||
'x-hasura-allowed-roles': ['user'],
|
||||
},
|
||||
};
|
||||
|
||||
return originalImplementation.createNewSession(input);
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
|
||||
/*
|
||||
* -------------------------------------------------------
|
||||
* THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY)
|
||||
* -------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export class CreateUserInput {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export class UpdateUserInput {
|
||||
email?: Nullable<string>;
|
||||
password?: Nullable<string>;
|
||||
time_joined?: Nullable<number>;
|
||||
createdAt?: Nullable<DateTime>;
|
||||
updatedAt?: Nullable<DateTime>;
|
||||
}
|
||||
|
||||
export class User {
|
||||
id: string;
|
||||
email: string;
|
||||
password?: Nullable<string>;
|
||||
time_joined?: Nullable<number>;
|
||||
createdAt?: Nullable<DateTime>;
|
||||
updatedAt?: Nullable<DateTime>;
|
||||
}
|
||||
|
||||
export abstract class IQuery {
|
||||
abstract users(): Nullable<User>[] | Promise<Nullable<User>[]>;
|
||||
|
||||
abstract user(id: string): Nullable<User> | Promise<Nullable<User>>;
|
||||
}
|
||||
|
||||
export abstract class IMutation {
|
||||
abstract createUser(createUserInput: CreateUserInput): User | Promise<User>;
|
||||
|
||||
abstract updateUser(id: string, updateUserInput: UpdateUserInput): Nullable<User> | Promise<Nullable<User>>;
|
||||
|
||||
abstract removeUser(id: string): Nullable<User> | Promise<Nullable<User>>;
|
||||
}
|
||||
|
||||
export type DateTime = any;
|
||||
type Nullable<T> = T | null;
|
||||
@@ -1,20 +0,0 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import supertokens from 'supertokens-node';
|
||||
import { SupertokensExceptionFilter } from './auth/filters/auth.filter';
|
||||
// import { PrismaService } from 'prisma/prisma.service';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
app.enableCors({
|
||||
origin: [process.env.WEBAPP_URL, 'http://server.home:8081'],
|
||||
allowedHeaders: ['content-type', ...supertokens.getAllCORSHeaders()],
|
||||
credentials: true,
|
||||
});
|
||||
app.useGlobalFilters(new SupertokensExceptionFilter());
|
||||
// const prismaService = app.get(PrismaService);
|
||||
// await prismaService.enableShutdownHooks(app);
|
||||
|
||||
await app.listen(process.env.APP_PORT);
|
||||
}
|
||||
bootstrap();
|
||||
@@ -1,34 +0,0 @@
|
||||
scalar DateTime
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
email: String!
|
||||
password: String
|
||||
time_joined: Int
|
||||
createdAt: DateTime
|
||||
updatedAt: DateTime
|
||||
}
|
||||
|
||||
input CreateUserInput {
|
||||
email: String!
|
||||
password: String!
|
||||
}
|
||||
|
||||
input UpdateUserInput {
|
||||
email: String
|
||||
password: String
|
||||
time_joined: Int
|
||||
createdAt: DateTime
|
||||
updatedAt: DateTime
|
||||
}
|
||||
|
||||
type Query {
|
||||
users: [User]!
|
||||
user(id: ID!): User
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createUser(createUserInput: CreateUserInput!): User!
|
||||
updateUser(id: ID!, updateUserInput: UpdateUserInput!): User
|
||||
removeUser(id: ID!): User
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersResolver } from './users.resolver';
|
||||
import { PrismaService } from 'prisma/prisma.service';
|
||||
|
||||
@Module({
|
||||
providers: [PrismaService, UsersResolver, UsersService],
|
||||
})
|
||||
export class UsersModule {}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { UsersService } from './users.service';
|
||||
|
||||
@Resolver('User')
|
||||
export class UsersResolver {
|
||||
constructor(private readonly usersService: UsersService) {}
|
||||
|
||||
// @Mutation('createUser')
|
||||
// create(@Args('createUserInput') createUserInput: Prisma.UserCreateInput) {
|
||||
// return this.usersService.create(createUserInput);
|
||||
// }
|
||||
// @Query('users')
|
||||
// findAll(@Args('params') params?: Prisma.UserFindManyArgs) {
|
||||
// return this.usersService.users(params);
|
||||
// }
|
||||
|
||||
// @Query('user')
|
||||
// findOne(@Args('id') id: string) {
|
||||
// return this.usersService.user({ id });
|
||||
// }
|
||||
|
||||
// @Mutation('updateUser')
|
||||
// update(@Args('updateUserInput') updateUserInput: UpdateUserInput) {
|
||||
// return this.usersService.update(updateUserInput.id, updateUserInput);
|
||||
// }
|
||||
|
||||
// @Mutation('removeUser')
|
||||
// remove(@Args('id') id: string) {
|
||||
// return this.usersService.remove(id);
|
||||
// }
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
// import { Prisma, User } from '@prisma/client';
|
||||
import { PrismaService } from 'prisma/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
// async user(uniqueInput: Prisma.UserWhereUniqueInput) {
|
||||
// return await this.prismaService.user.findUnique({ where: uniqueInput });
|
||||
// }
|
||||
|
||||
// async users(params?: Prisma.UserFindManyArgs) {
|
||||
// return await this.prismaService.user.findMany(params);
|
||||
// }
|
||||
|
||||
// create(createUserInput: Prisma.UserCreateInput) {
|
||||
// return this.prismaService.user.create({ data: createUserInput });
|
||||
// }
|
||||
|
||||
// update(id: string, userUpdateInput: Prisma.UserUpdateInput) {
|
||||
// return this.prismaService.user.update({
|
||||
// where: { id },
|
||||
// data: userUpdateInput,
|
||||
// });
|
||||
// }
|
||||
|
||||
// remove(id: string) {
|
||||
// return `This action removes a #${id} user`;
|
||||
// }
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from './../src/app.module';
|
||||
|
||||
describe('AppController (e2e)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
|
||||
app = moduleFixture.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('/ (GET)', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Hello World!');
|
||||
});
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": ".",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".e2e-spec.ts$",
|
||||
"transform": {
|
||||
"^.+\\.(t|j)s$": "ts-jest"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "es2017",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
||||
5261
backend/yarn.lock
5261
backend/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
||||
import type { Component } from "solid-js";
|
||||
import AppRouter from "./routes";
|
||||
|
||||
import SuperTokens from "supertokens-web-js";
|
||||
import EmailPass from "supertokens-web-js/recipe/emailpassword";
|
||||
import Session from "supertokens-web-js/recipe/session";
|
||||
import AuthProvider from "./context/AuthContext";
|
||||
|
||||
SuperTokens.init({
|
||||
appInfo: {
|
||||
apiDomain: "http://localhost:3300",
|
||||
apiBasePath: "/auth/api",
|
||||
appName: "Fluxem",
|
||||
},
|
||||
recipeList: [EmailPass.init(), Session.init()],
|
||||
});
|
||||
|
||||
const App: Component = () => {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<AppRouter />
|
||||
</AuthProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -1,9 +0,0 @@
|
||||
const AuthLoader = () => {
|
||||
return (
|
||||
<div>
|
||||
<h2>Auth Loading...</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AuthLoader;
|
||||
@@ -1,13 +0,0 @@
|
||||
interface TestComponentProps {
|
||||
// add props here
|
||||
}
|
||||
|
||||
function TestComponent(props: TestComponentProps) {
|
||||
return (
|
||||
<div>
|
||||
<h2>TestComponent</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TestComponent;
|
||||
@@ -1,69 +0,0 @@
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { createContext, onMount, Show, useContext } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
import { UserType } from "supertokens-web-js/recipe/emailpassword";
|
||||
import AuthLoader from "../components/AuthLoader";
|
||||
import { currentUser } from "../services/auth.service";
|
||||
|
||||
const AuthStateContext = createContext();
|
||||
const AuthDispatchContext = createContext<any>();
|
||||
|
||||
interface InitState {
|
||||
isLoading: boolean;
|
||||
isAuthenticated: boolean;
|
||||
currentUser: UserType | null;
|
||||
}
|
||||
|
||||
const initialState: InitState = {
|
||||
isLoading: true,
|
||||
isAuthenticated: false,
|
||||
currentUser: null,
|
||||
};
|
||||
|
||||
const AuthProvider = (props: any) => {
|
||||
const [store, setStore] = createStore(initialState);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const loadCurrentUser = async () => {
|
||||
const user = await currentUser();
|
||||
if (user) {
|
||||
setStore("isAuthenticated", true);
|
||||
setStore("currentUser", user);
|
||||
}
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
await loadCurrentUser();
|
||||
setStore("isLoading", false);
|
||||
});
|
||||
|
||||
const setCurrentUser = (user?: UserType) => {
|
||||
if (user) {
|
||||
setStore("isAuthenticated", true);
|
||||
setStore("currentUser", user);
|
||||
}
|
||||
};
|
||||
const removeCurrentUser = () => {
|
||||
setStore("isAuthenticated", false);
|
||||
setStore("currentUser", null);
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthStateContext.Provider value={store}>
|
||||
<AuthDispatchContext.Provider
|
||||
value={{
|
||||
setCurrentUser,
|
||||
removeCurrentUser,
|
||||
}}
|
||||
>
|
||||
<Show when={!store.isLoading} fallback={<AuthLoader />}>
|
||||
{props.children}
|
||||
</Show>
|
||||
</AuthDispatchContext.Provider>
|
||||
</AuthStateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default AuthProvider;
|
||||
export const useAuthState = () => useContext(AuthStateContext);
|
||||
export const useAuthDispatch = () => useContext(AuthDispatchContext);
|
||||
@@ -1,5 +0,0 @@
|
||||
import { createClient } from "@urql/core";
|
||||
|
||||
const client = createClient({
|
||||
url: ''
|
||||
});
|
||||
@@ -1,61 +0,0 @@
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { createSignal } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
|
||||
import { useAuthDispatch } from "../../context/AuthContext";
|
||||
import {
|
||||
delUserFromLocalStorage,
|
||||
loginService,
|
||||
logoutService,
|
||||
setUserInLocalStorage,
|
||||
} from "../../services/auth.service";
|
||||
|
||||
const useLogin = () => {
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
const [form, setForm] = createStore({
|
||||
email: "",
|
||||
password: "",
|
||||
});
|
||||
|
||||
const { setCurrentUser } = useAuthDispatch();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleInput = (ev: any) => {
|
||||
setForm([ev.currentTarget.name], ev.currentTarget.value);
|
||||
};
|
||||
const handleLogin = async (ev: any) => {
|
||||
ev.preventDefault();
|
||||
setLoading(true);
|
||||
try {
|
||||
const loginData = await loginService({
|
||||
formFields: [
|
||||
{ id: "email", value: form.email },
|
||||
{ id: "password", value: form.password },
|
||||
],
|
||||
});
|
||||
if (loginData.status === "OK") {
|
||||
setCurrentUser(loginData.user);
|
||||
setUserInLocalStorage(loginData.user);
|
||||
navigate("/", { replace: true });
|
||||
}
|
||||
if (loginData.status === "FIELD_ERROR") {
|
||||
// TODO: Handle error in UI
|
||||
console.log("FIELD_ERROR", loginData);
|
||||
}
|
||||
if (loginData.status === "WRONG_CREDENTIALS_ERROR") {
|
||||
// TODO: Handle error in UI
|
||||
console.log("WRONG_CREDENTIALS_ERROR", loginData);
|
||||
}
|
||||
} catch (error) {
|
||||
//TODO: Handle error in UI
|
||||
console.error("ERRRRRRRRRRr", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return { handleInput, loading, handleLogin, form };
|
||||
};
|
||||
|
||||
export default useLogin;
|
||||
@@ -1,28 +0,0 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { useAuthDispatch } from "../../context/AuthContext";
|
||||
import {
|
||||
delUserFromLocalStorage,
|
||||
logoutService,
|
||||
} from "../../services/auth.service";
|
||||
|
||||
const useLogout = () => {
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
const { removeCurrentUser } = useAuthDispatch();
|
||||
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await logoutService();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
removeCurrentUser();
|
||||
delUserFromLocalStorage();
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return { handleLogout, loading };
|
||||
};
|
||||
|
||||
export default useLogout;
|
||||
@@ -1,34 +0,0 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
import EmailPassRecipe from "supertokens-web-js/recipe/emailpassword";
|
||||
|
||||
const useRegister = () => {
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
const [form, setForm] = createStore({
|
||||
email: "",
|
||||
password: "",
|
||||
});
|
||||
const handleInput = (ev: any) => {
|
||||
setForm([ev.currentTarget.name], ev.currentTarget.value);
|
||||
};
|
||||
|
||||
const handleRegister = async (ev: any) => {
|
||||
ev.preventDefault();
|
||||
setLoading(true);
|
||||
try {
|
||||
const login = await EmailPassRecipe.signUp({
|
||||
formFields: [
|
||||
{ id: "email", value: form.email },
|
||||
{ id: "password", value: form.password },
|
||||
],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
return { handleInput, loading, handleRegister, form };
|
||||
};
|
||||
|
||||
export default useRegister;
|
||||
@@ -1,52 +0,0 @@
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAuthState } from "../../../context/AuthContext";
|
||||
import useLogin from "../../../hooks/auth/login.hook";
|
||||
const Login: Component = () => {
|
||||
const navigate = useNavigate();
|
||||
const { handleLogin, handleInput, loading, form } = useLogin();
|
||||
const authState: any = useAuthState();
|
||||
if (authState.isAuthenticated) {
|
||||
navigate("/");
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<form onsubmit={handleLogin}>
|
||||
<div>
|
||||
<label for="email">Username or Email</label>
|
||||
<br />
|
||||
<input
|
||||
id="email"
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Email/Username"
|
||||
value={form.email}
|
||||
onInput={handleInput}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<br />
|
||||
<input
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
value={form.password}
|
||||
onInput={handleInput}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<button disabled={loading()} type="submit">
|
||||
<Show when={!loading()} fallback="Logging in...">
|
||||
Log In
|
||||
</Show>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
export default Login;
|
||||
@@ -1,18 +0,0 @@
|
||||
import EmailPassRecipe from "supertokens-web-js/recipe/emailpassword";
|
||||
|
||||
const VerifyEmail = () => {
|
||||
let text = "Verifying email";
|
||||
const verifyEmail = EmailPassRecipe.verifyEmail();
|
||||
verifyEmail.then((data) => {
|
||||
console.log(data);
|
||||
text = "Email verified successfully";
|
||||
});
|
||||
// console.log(verifyEmail);
|
||||
return (
|
||||
<div>
|
||||
<h2>{text}</h2>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VerifyEmail;
|
||||
@@ -1,31 +0,0 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import { useAuthState } from "../../../context/AuthContext";
|
||||
import useLogin from "../../../hooks/auth/login.hook";
|
||||
import useLogout from "../../../hooks/auth/logout.hook";
|
||||
|
||||
const Home: Component = () => {
|
||||
const authState: any = useAuthState();
|
||||
const { handleLogout, loading } = useLogout();
|
||||
return (
|
||||
<div>
|
||||
<p>Home</p>
|
||||
|
||||
<Show when={authState?.isAuthenticated}>
|
||||
<div>
|
||||
<p>Authenticated</p>
|
||||
<button onclick={handleLogout} disabled={loading()}>
|
||||
<Show when={!loading()} fallback="Signing out...">
|
||||
Sign Out
|
||||
</Show>
|
||||
</button>
|
||||
<p>{JSON.stringify(authState)}</p>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={!authState?.isAuthenticated}>
|
||||
<a href="/auth/login">Login</a>
|
||||
</Show>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
@@ -1,61 +0,0 @@
|
||||
import EmailPassRecipe, {
|
||||
UserType,
|
||||
} from "supertokens-web-js/recipe/emailpassword";
|
||||
import Session from "supertokens-web-js/recipe/session";
|
||||
|
||||
const curentUserKey = "current_user";
|
||||
|
||||
export interface AuthData {
|
||||
formFields: FormFields[];
|
||||
}
|
||||
interface FormFields {
|
||||
id: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const currentUser = async () => {
|
||||
// This method might produce bugs. Localstorage may not be the same as logged in user
|
||||
// TODO: endpoing in backend (getCurrentUser)
|
||||
if (
|
||||
localStorage.getItem("current_user") &&
|
||||
(await Session.doesSessionExist())
|
||||
) {
|
||||
let sessionUserId = await Session.getUserId();
|
||||
const user = getUserFromLocaStorage();
|
||||
if (user) {
|
||||
if (sessionUserId === user.id) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const loginService = async (loginData: AuthData) => {
|
||||
return await EmailPassRecipe.signIn(loginData);
|
||||
};
|
||||
|
||||
const logoutService = async () => {
|
||||
await EmailPassRecipe.signOut();
|
||||
};
|
||||
|
||||
const setUserInLocalStorage = (user: UserType) => {
|
||||
localStorage.setItem(curentUserKey, JSON.stringify(user));
|
||||
};
|
||||
|
||||
const getUserFromLocaStorage = () => {
|
||||
const user: UserType = JSON.parse(localStorage.getItem(curentUserKey)!);
|
||||
return user;
|
||||
};
|
||||
|
||||
const delUserFromLocalStorage = () => {
|
||||
localStorage.removeItem(curentUserKey);
|
||||
};
|
||||
|
||||
export {
|
||||
loginService,
|
||||
logoutService,
|
||||
currentUser,
|
||||
setUserInLocalStorage,
|
||||
delUserFromLocalStorage,
|
||||
};
|
||||
@@ -28,6 +28,6 @@
|
||||
"@urql/core": "^3.0.3",
|
||||
"graphql": "^16.6.0",
|
||||
"solid-js": "^1.5.1",
|
||||
"supertokens-web-js": "^0.1.6"
|
||||
"solid-urql": "^0.2.0"
|
||||
}
|
||||
}
|
||||
14
src/App.tsx
Normal file
14
src/App.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { Component } from "solid-js";
|
||||
import { Provider } from "solid-urql";
|
||||
import client from "./graphql/client";
|
||||
import AppRouter from "./routes";
|
||||
|
||||
const App: Component = () => {
|
||||
return (
|
||||
<Provider value={client}>
|
||||
<AppRouter />
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
7
src/graphql/client.ts
Normal file
7
src/graphql/client.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { createClient } from "solid-urql";
|
||||
|
||||
const client = createClient({
|
||||
url: 'https://hasura.apps.artservis.al/v1/graphql'
|
||||
});
|
||||
|
||||
export default client;
|
||||
22
src/hooks/auth/login.hook.ts
Normal file
22
src/hooks/auth/login.hook.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { createSignal } from "solid-js";
|
||||
import { createStore } from "solid-js/store";
|
||||
|
||||
const useLogin = () => {
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
const [form, setForm] = createStore({
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
const handleInput = (ev: any) => {
|
||||
setForm([ev.currentTarget.name], ev.currentTarget.value);
|
||||
};
|
||||
const handleLogin = (ev: any) => {
|
||||
ev.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
};
|
||||
|
||||
return { handleInput, loading, handleLogin, form };
|
||||
};
|
||||
|
||||
export default useLogin;
|
||||
@@ -4,6 +4,7 @@ import { render } from "solid-js/web";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
import { Router } from "@solidjs/router";
|
||||
|
||||
render(
|
||||
() => (
|
||||
<Router>
|
||||
@@ -5,7 +5,7 @@ const Home = lazy(() => import("./views/home/Home"));
|
||||
const AuthLayout = lazy(() => import("./views/auth/AuthLayout"));
|
||||
const Login = lazy(() => import("./views/auth/Login"));
|
||||
const Register = lazy(() => import("./views/auth/Register"));
|
||||
const VerifyEmail = lazy(() => import("./views/auth/VerifyEmail"));
|
||||
|
||||
const AppRouter: Component = () => {
|
||||
return (
|
||||
<Routes>
|
||||
@@ -13,7 +13,6 @@ const AppRouter: Component = () => {
|
||||
<Route path="/auth" element={<AuthLayout />}>
|
||||
<Route path="/login" element={<Login />}></Route>
|
||||
<Route path="/register" element={<Register />}></Route>
|
||||
<Route path="/verify-email" element={<VerifyEmail />}></Route>
|
||||
</Route>
|
||||
</Routes>
|
||||
);
|
||||
39
src/routes/views/auth/Login.tsx
Normal file
39
src/routes/views/auth/Login.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Component, Show } from "solid-js";
|
||||
import useLogin from "../../../hooks/auth/login.hook";
|
||||
const { handleLogin, handleInput, loading, form } = useLogin();
|
||||
const Login: Component = () => {
|
||||
return (
|
||||
<div>
|
||||
<form onsubmit={handleLogin}>
|
||||
<div>
|
||||
{/* <label for="name">Username or Email</label> */}
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
placeholder="Email/Username"
|
||||
value={form.username}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{/* <label for="name">Password</label> */}
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
value={form.password}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button disabled={loading()} type="submit">
|
||||
<Show when={!loading()} fallback="Logging in...">
|
||||
Log In
|
||||
</Show>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
||||
20
src/routes/views/auth/Register.tsx
Normal file
20
src/routes/views/auth/Register.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import type { Component } from "solid-js";
|
||||
import { useAllUsersQuery } from "../../../graphql/generated/graphql";
|
||||
|
||||
const mockHasura = () => {
|
||||
const getUsers = useAllUsersQuery();
|
||||
console.log(getUsers);
|
||||
};
|
||||
|
||||
const Register: Component = () => {
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Register</h2>
|
||||
<button onclick={mockHasura}>Mock</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Register;
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { Component } from "solid-js";
|
||||
const Register: Component = () => {
|
||||
|
||||
const Home: Component = () => {
|
||||
return (
|
||||
<div>
|
||||
<h2>Register</h2>
|
||||
<h2>Home</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Register;
|
||||
export default Home;
|
||||
@@ -1297,13 +1297,6 @@ braces@^3.0.2, braces@~3.0.2:
|
||||
dependencies:
|
||||
fill-range "^7.0.1"
|
||||
|
||||
browser-tabs-lock@^1.2.14:
|
||||
version "1.2.15"
|
||||
resolved "https://registry.yarnpkg.com/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz#d5012e652e2a0cb4eba471b0a2300c2fa5d92788"
|
||||
integrity sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==
|
||||
dependencies:
|
||||
lodash ">=4.17.21"
|
||||
|
||||
browserslist@^4.20.2:
|
||||
version "4.21.3"
|
||||
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
|
||||
@@ -2472,7 +2465,7 @@ lodash.once@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
||||
integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==
|
||||
|
||||
lodash@>=4.17.21, lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0:
|
||||
lodash@^4.17.20, lodash@^4.17.21, lodash@~4.17.0:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
@@ -3091,6 +3084,11 @@ solid-refresh@^0.4.1:
|
||||
"@babel/helper-module-imports" "^7.16.7"
|
||||
"@babel/types" "^7.18.4"
|
||||
|
||||
solid-urql@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/solid-urql/-/solid-urql-0.2.0.tgz#b6305480a4e46d176a195a4bc586291e19944a7a"
|
||||
integrity sha512-3sLtHBbbfwANBTP0toZLdVeRKa4UJDBjgfP5rv2z4ip4+a8vBlfFHWy/5N6fgxBhQ0IdbuYKRAcJECkJd80auw==
|
||||
|
||||
source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
@@ -3136,27 +3134,6 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
supertokens-js-override@0.0.4, supertokens-js-override@^0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/supertokens-js-override/-/supertokens-js-override-0.0.4.tgz#9af583fbc5e1f0195dbb358c4fcf75f44c76dc09"
|
||||
integrity sha512-r0JFBjkMIdep3Lbk3JA+MpnpuOtw4RSyrlRAbrzMcxwiYco3GFWl/daimQZ5b1forOiUODpOlXbSOljP/oyurg==
|
||||
|
||||
supertokens-web-js@^0.1.6:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.yarnpkg.com/supertokens-web-js/-/supertokens-web-js-0.1.6.tgz#81165f9f7604518db05088a8a527c756b3b48178"
|
||||
integrity sha512-Cyu97r6tRJc4ryiKhOqYlqYQ+1XB5x5rJfMudg0kgANu7bvNMo39mI4KAb4eLaXQfXAPQ6Y/As+uqUVP7gbKDw==
|
||||
dependencies:
|
||||
supertokens-js-override "0.0.4"
|
||||
supertokens-website "^13.0.2"
|
||||
|
||||
supertokens-website@^13.0.2:
|
||||
version "13.0.2"
|
||||
resolved "https://registry.yarnpkg.com/supertokens-website/-/supertokens-website-13.0.2.tgz#c1eba0d1745ee2d7c019fa88eb9d7029309fc6e9"
|
||||
integrity sha512-WVCHky05ndJhPXW2khAWy3CBlWn1ZwRF32TPTiGgYLrpQYO9q5doHJi9z2H1OiSmOEFJDEKWtaPW9HxAHABo1Q==
|
||||
dependencies:
|
||||
browser-tabs-lock "^1.2.14"
|
||||
supertokens-js-override "^0.0.4"
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
Reference in New Issue
Block a user