Browse Source

major: GraphQL Rewrite

main
Dale 4 weeks ago
commit
eed718f36a
Signed by: Deiru GPG Key ID: AA250C0277B927E1
28 changed files with 7535 additions and 0 deletions
  1. +9
    -0
      .gitignore
  2. +11
    -0
      codegen.yml
  3. +43
    -0
      default.nix
  4. +1728
    -0
      graphql.schema.json
  5. +43
    -0
      package.json
  6. +7
    -0
      src/config/local.json
  7. +6
    -0
      src/db/index.ts
  8. +35
    -0
      src/db/models/Sessions.ts
  9. +50
    -0
      src/db/models/Users.ts
  10. +9
    -0
      src/db/models/index.ts
  11. +32
    -0
      src/db/setup-db.ts
  12. +8
    -0
      src/db/types.ts
  13. +17
    -0
      src/grpahql/errors/auth.ts
  14. +12
    -0
      src/grpahql/errors/general.ts
  15. +17
    -0
      src/grpahql/errors/users.ts
  16. +53
    -0
      src/grpahql/index.ts
  17. +13
    -0
      src/grpahql/mutations/users/auth.ts
  18. +6
    -0
      src/grpahql/mutations/users/index.ts
  19. +32
    -0
      src/grpahql/resolvers/users/index.ts
  20. +17
    -0
      src/grpahql/schema/Root.graphql
  21. +1
    -0
      src/grpahql/schema/Scalars.graphql
  22. +46
    -0
      src/grpahql/schema/User.graphql
  23. +15
    -0
      src/grpahql/schema/index.ts
  24. +13
    -0
      src/server.ts
  25. +321
    -0
      src/types/graphql.ts
  26. +15
    -0
      src/types/resolver.ts
  27. +22
    -0
      tsconfig.json
  28. +4954
    -0
      yarn.lock

+ 9
- 0
.gitignore View File

@ -0,0 +1,9 @@
node_modules/
dist/
yarn-error.log
src/**/*.js
dev.sqlite3
miracle-tv.*.zip
result/
.types

+ 11
- 0
codegen.yml View File

@ -0,0 +1,11 @@
overwrite: true
schema: "http://localhost:4000/graphql"
documents: null
generates:
src/types/graphql.ts:
plugins:
- "typescript"
- "typescript-resolvers"
./graphql.schema.json:
plugins:
- "introspection"

+ 43
- 0
default.nix View File

@ -0,0 +1,43 @@
with import <nixpkgs> {};
let
executableName = "miracle-tv";
version = "0.1.0";
src = ./.;
nodePkg = pkgs.nodejs-14_x;
yarnPkg = pkgs.yarn.override { nodejs = nodePkg; };
in mkYarnPackage rec {
name = "miarcle-tv";
inherit version src nodePkg yarnPkg;
doDist = false;
packageJSON = "${src}/package.json";
yarnLock = "${src}/yarn.lock";
yarnNix = "${src}/yarn.nix";
configurePhase = ''
rm -rf ./node_modules || true
ln -s $node_modules ./node_modules
'';
buildPhase = ''
sh ./bin/build.sh
'';
installPhase = ''
mkdir $out
cp -R ./dist/* $out
cp -R ./migrations $out/migrations
'';
distPhase = ''
true
'';
nativeBuildInputs = with pkgs; [
nodePkg yarnPkg makeWrapper
automake autoconf m4 git bash
libpng libGL gcc
];
}

+ 1728
- 0
graphql.schema.json
File diff suppressed because it is too large
View File


+ 43
- 0
package.json View File

@ -0,0 +1,43 @@
{
"name": "miracle-tv",
"version": "0.1.0",
"main": "server.js",
"repository": "https://code.gensokyo.social/Gensokyo.social/miracle-tv",
"license": "MIT",
"scripts": {
"server": "ts-node -r $node_modules/tsconfig-paths/register src/server.ts",
"codegen": "graphql-codegen --config codegen.yml",
"dev": "nodemon -e ts,tsx,graphql --exec \"yarn run server\""
},
"dependencies": {
"apollo-server": "^2.24.0",
"apollo-server-express": "^2.24.0",
"async": "^3.2.0",
"express": "^4.17.1",
"express-graphql": "^0.12.0",
"glob": "^7.1.7",
"graphql": "^15.5.0",
"luxon": "^1.27.0",
"md5": "^2.3.0",
"ramda": "^0.27.1",
"rethinkdb": "^2.4.2"
},
"devDependencies": {
"@graphql-codegen/cli": "1.21.4",
"@graphql-codegen/introspection": "1.18.2",
"@graphql-codegen/typescript": "1.22.0",
"@graphql-codegen/typescript-resolvers": "1.19.1",
"@types/async": "^3.2.6",
"@types/express": "^4.17.11",
"@types/express-graphql": "^0.9.0",
"@types/glob": "^7.1.3",
"@types/luxon": "^1.26.5",
"@types/md5": "^2.3.0",
"@types/ramda": "^0.27.40",
"@types/rethinkdb": "^2.3.16",
"nodemon": "^2.0.7",
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.4"
}
}

+ 7
- 0
src/config/local.json View File

@ -0,0 +1,7 @@
{
"database": {
"host": "localhost",
"port": 28015,
"db": "miracle-tv"
}
}

+ 6
- 0
src/db/index.ts View File

@ -0,0 +1,6 @@
import rethinkdb from 'rethinkdb'
import config from 'miracle-tv/config/local.json';
const db = rethinkdb.db(config.database.db);
export default db;

+ 35
- 0
src/db/models/Sessions.ts View File

@ -0,0 +1,35 @@
import db from 'miracle-tv/db';
import { DbUser } from 'miracle-tv/db/types';
import { Model } from 'miracle-tv/db/models';
import { Session, SessionResponse } from 'miracle-tv/types/graphql';
import { DateTime } from 'luxon';
import { head } from 'ramda'
import { ServerError } from 'miracle-tv/grpahql/errors/general';
export class SessionsModel extends Model {
table = db.table('sessions')
async createSession(userId: string): Promise<SessionResponse> {
return await this.table.insert({
user: userId,
expiresAt: DateTime.now().plus({ days: 30 }).toLocal().toISO(),
})
.run(this.conn)
.then(async (res) => {
const key = head(res.generated_keys)
const session = await this.getSessionById(key)
if (session) {
return { token: session.id, expiresAt: session.expiresAt }
}
throw new ServerError('Couldn\'t create session')
})
}
async getSessionById(id: string): Promise<Session> {
return await this.table.get(id).run(this.conn) as Session
}
async getUsers(filter?: Record<keyof DbUser, any>): Promise<Session[]> {
return await this.table.filter(filter).coerceTo('array').run(this.conn) as Session[]
}
}

+ 50
- 0
src/db/models/Users.ts View File

@ -0,0 +1,50 @@
import db from 'miracle-tv/db';
import { DbUser } from 'miracle-tv/db/types';
import { Model } from 'miracle-tv/db/models';
import { CreateUserInput, User } from 'miracle-tv/types/graphql';
import { head, map, omit } from 'ramda';
import { EmailExistsError, UserExistsError } from 'miracle-tv/grpahql/errors/users';
type UsersFilter = Partial<Record <keyof DbUser, any>>
export class UsersModel extends Model {
table = db.table('users');
sanitizeUser(dbUser: DbUser): User {
return omit(['password'], dbUser);
}
async createUserSafe({ password, ...input }: CreateUserInput): Promise<User> {
const saltedPassword = `salted+${password}`;
const dbUsers = await this.getUsers({ username: input.username });
const dbEmails = await this.getUsers({ email: input.email });
if (dbUsers.length > 0) {
throw new UserExistsError();
}
if (dbEmails.length > 0) {
throw new EmailExistsError();
}
return await this.table
.insert({ password: saltedPassword, ...input, singleUserMode: false }).run(this.conn)
.then((result) => {
const key = head(result.generated_keys);
return this.table.get(key).run(this.conn).then(this.sanitizeUser)
}) as User;
}
async getUserById(id: string): Promise<DbUser | null> {
return await this.table.get(id).run(this.conn) as DbUser | null;
}
async getUserByIdSafe(id: string): Promise<User> {
return await this.getUserById(id).then(this.sanitizeUser);
}
async getUsers(filter?: UsersFilter): Promise<DbUser[]> {
return await this.table.filter(filter).coerceTo('array').run(this.conn) as DbUser[];
}
async getUsersSafe(filter?: UsersFilter): Promise<User[]> {
return await this.getUsers(filter).then(map(this.sanitizeUser)) as User[];
}
}

+ 9
- 0
src/db/models/index.ts View File

@ -0,0 +1,9 @@
import { Connection, Table } from "rethinkdb";
export class Model {
conn: Connection;
constructor(conn: Connection) {
this.conn = conn;
}
}

+ 32
- 0
src/db/setup-db.ts View File

@ -0,0 +1,32 @@
import * as rdb from 'rethinkdb';
import config from 'src/config/local.json';
const tables: string[] = ['users', 'sessions'];
export const connection = rdb.connect({ host: 'localhost', port: 28015 }).then((con) => {
console.log('\x1b[33m', '[Checking Database Setup]', '\x1b[0m')
console.log('\x1b[33m', `- Checking database \`${config.database.db}\`...`, '\x1b[0m')
return rdb.dbList().run(con).then((dbList) => {
if (!dbList.includes(config.database.db)) {
console.log('\x1b[33m', `-- Creating database \`${config.database.db}\`...`, '\x1b[0m')
return rdb.dbCreate(config.database.db).run(con);
} else {
console.log('\x1b[32m', `-- ✔ Database \`${config.database.db}\` ok!`, '\x1b[0m')
}
}).then(() => {
rdb.db(config.database.db).tableList().run(con).then((tableList) => {
tables.forEach((table) => {
console.log('\x1b[33m', `- Checking \`${table}\` Table`, '\x1b[0m')
if (!tableList.includes(table)) {
console.log('\x1b[33m', `-- Creating \`${table}\` table...`, '\x1b[0m')
rdb.db(config.database.db).tableCreate(table).run(con);
} else {
console.log('\x1b[32m', `-- Table \`${table}\` ok!`, '\x1b[0m')
}
})
console.log('\x1b[32m', '- ✔ Table Check Complete!', '\x1b[0m')
console.log('\x1b[32m', '✔ Database Check Complete!', '\x1b[0m')
})
return con
})
})

+ 8
- 0
src/db/types.ts View File

@ -0,0 +1,8 @@
import { Session, User } from "miracle-tv/types/graphql";
export type DbUser = Omit<User, 'emailHash'> & {
email: string
password: string
}
export type DbSession = Session

+ 17
- 0
src/grpahql/errors/auth.ts View File

@ -0,0 +1,17 @@
import { ApolloError } from 'apollo-server-errors';
export class InputErrorLogin extends ApolloError {
constructor() {
super('User was not found or wrong password provided', 'E_LOGIN');
Object.defineProperty(this, 'name', { value: 'InputErrorLogin' });
}
}
export class AuthenticationError extends ApolloError {
constructor() {
super('User is not authenticated', 'E_AUTHENTICATION');
Object.defineProperty(this, 'name', { value: 'AuthenticationError' });
}
}

+ 12
- 0
src/grpahql/errors/general.ts View File

@ -0,0 +1,12 @@
import { ApolloError } from 'apollo-server-errors';
export class ServerError extends ApolloError {
constructor(msg?: string) {
const message = msg
? `Following server error has occured: ${msg}`
: 'A server error has occured';
super(message, 'E_SERVER');
Object.defineProperty(this, 'name', { value: 'ServerError' });
}
}

+ 17
- 0
src/grpahql/errors/users.ts View File

@ -0,0 +1,17 @@
import { ApolloError } from "apollo-server-errors";
export class UserExistsError extends ApolloError {
constructor() {
super('User with this username already exists', 'E_USER_EXISTS');
Object.defineProperty(this, 'name', { value: 'UserExistsError' });
}
}
export class EmailExistsError extends ApolloError {
constructor() {
super('User with this email already exists', 'E_EMAIL_EXISTS');
Object.defineProperty(this, 'name', { value: 'UserExistsError' });
}
}

+ 53
- 0
src/grpahql/index.ts View File

@ -0,0 +1,53 @@
import schema from 'miracle-tv/grpahql/schema';
import { Resolvers } from 'miracle-tv/types/graphql';
import { connection } from 'miracle-tv/db/setup-db';
import { ResolverContext } from 'miracle-tv/types/resolver';
import { userQueryResolver, userResolver, userListQueryResolver, userSelfQueryResolver, userTestQueryResolver } from './resolvers/users';
import { signUpMutation } from './mutations/users';
import { ApolloServer } from 'apollo-server-express';
import { signInMutation } from './mutations/users/auth';
import { DbSession, DbUser } from 'miracle-tv/db/types';
import { DateTime } from 'luxon';
import { SessionsModel } from 'miracle-tv/db/models/Sessions';
import { UsersModel } from 'miracle-tv/db/models/Users';
const resolvers: Resolvers<ResolverContext> = {
Query: {
info: () => ({
version: process.env.npm_package_version || 'none',
packageName: process.env.npm_package_name || 'none',
}),
users: userListQueryResolver,
user: userQueryResolver,
self: userSelfQueryResolver,
test: userTestQueryResolver,
},
Mutation: {
ping: (...args) => {
args
return 'pong';
},
signUp: signUpMutation,
signIn: signInMutation,
},
User: userResolver,
}
export const graphqlEndpoint = new ApolloServer({ typeDefs: schema, resolvers, context: async ({ req }) => {
const con = await connection
const db = {
sessions: new SessionsModel(con),
users: new UsersModel(con)
};
const session = await db.sessions.getSessionById(req.headers.authorization || '') as DbSession | null
const sessionIsValid = DateTime.fromISO(session?.expiresAt).diffNow('seconds').seconds > 0 || false
const user = sessionIsValid
? await db.users.getUserById(session?.user) as DbUser | null
: null
return {
db,
session,
user,
}
} })

+ 13
- 0
src/grpahql/mutations/users/auth.ts View File

@ -0,0 +1,13 @@
import { MutationResolvers } from 'miracle-tv/types/graphql';
import { ResolverContext } from 'miracle-tv/types/resolver';
import { head } from 'ramda';
import { InputErrorLogin } from 'miracle-tv/grpahql/errors/auth';
export const signInMutation: MutationResolvers<ResolverContext>['signIn'] = async (_, { input: { username, password } }, { db: { users, sessions } }) => {
const userList = await users.getUsers({ username });
const user = head(userList)
if (user?.password === `salted+${password}`) {
return await sessions.createSession(user?.id!)
}
throw new InputErrorLogin()
}

+ 6
- 0
src/grpahql/mutations/users/index.ts View File

@ -0,0 +1,6 @@
import { MutationResolvers } from "miracle-tv/types/graphql";
import { ResolverContext } from "miracle-tv/types/resolver";
export const signUpMutation: MutationResolvers<ResolverContext>['signUp'] = (_, { input }, { db: { users }}) => {
return users.createUserSafe(input)
};

+ 32
- 0
src/grpahql/resolvers/users/index.ts View File

@ -0,0 +1,32 @@
import md5 from 'md5';
import { AuthenticationError } from 'miracle-tv/grpahql/errors/auth';
import { QueryResolvers, User, UserResolvers } from 'miracle-tv/types/graphql';
import { ResolverContext } from 'miracle-tv/types/resolver';
export const userListQueryResolver: QueryResolvers<ResolverContext>['users'] = (_, _args, { db: { users } }): Promise<User[]> => {
return users.getUsersSafe();
}
export const userQueryResolver: QueryResolvers<ResolverContext>['user'] = (_, args, { db: { users } }) => {
return users.getUserByIdSafe(args.id);
}
export const userSelfQueryResolver: QueryResolvers<ResolverContext>['self'] = async (_, _args, { user }) => {
if (user) {
return user
}
throw new AuthenticationError()
}
export const userTestQueryResolver: QueryResolvers<ResolverContext>['test'] = (_, _args, { user }) => {
if (user) {
return { secret: 'sauce' }
}
throw new AuthenticationError()
}
export const userResolver: UserResolvers = {
id: (user) => user.id,
username: (user) => user.username,
emailHash: (user) => md5((user as any).email || ''),
}

+ 17
- 0
src/grpahql/schema/Root.graphql View File

@ -0,0 +1,17 @@
type InfoResponse {
version: String!
packageName: String!
}
type TestResponse {
secret: String!
}
type Query {
info: InfoResponse!
test: TestResponse!
}
type Mutation {
ping: String!
}

+ 1
- 0
src/grpahql/schema/Scalars.graphql View File

@ -0,0 +1 @@
scalar DateTime

+ 46
- 0
src/grpahql/schema/User.graphql View File

@ -0,0 +1,46 @@
type User {
id: ID
username: String!
displayName: String
bio: String
singleUserMode: Boolean!
emailHash: String
}
type Session {
id: ID!
user: ID!
expiresAt: DateTime!
}
type SessionResponse {
token: ID!
expiresAt: DateTime!
}
type UserSettings {
id: ID
useGravatar: Boolean
}
extend type Query {
users: [User]!
self: User!
user(id: ID!): User
}
input CreateUserInput {
username: String!
password: String!
email: String!
}
input SignInInput {
username: String!
password: String!
}
extend type Mutation {
signUp(input: CreateUserInput!): User!
signIn(input: SignInInput): SessionResponse
}

+ 15
- 0
src/grpahql/schema/index.ts View File

@ -0,0 +1,15 @@
import glob from 'glob';
import path from 'path';
import {gql} from 'apollo-server';
import { readFileSync } from 'fs';
import { buildSchema } from 'graphql';
const schemaString = glob.sync(path.resolve(__dirname, './**/*.graphql')).map(filename => {
const contents = readFileSync(filename).toString();
return contents;
}).join('\n');
const schema = gql`${schemaString}`
export default schema;

+ 13
- 0
src/server.ts View File

@ -0,0 +1,13 @@
import Express from 'express';
import { graphqlEndpoint } from 'miracle-tv/grpahql';
import 'miracle-tv/db/setup-db';
const app = Express();
app.get('/', (_, res) => res.send('FUCK!'));
graphqlEndpoint.applyMiddleware({ app })
app.listen(4000, () => {
console.info('Server started on localhost:4000');
})

+ 321
- 0
src/types/graphql.ts View File

@ -0,0 +1,321 @@
import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql';
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 RequireFields<T, K extends keyof T> = { [X in Exclude<keyof T, K>]?: T[X] } & { [P in K]-?: NonNullable<T[P]> };
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: string;
String: string;
Boolean: boolean;
Int: number;
Float: number;
DateTime: any;
/** The `Upload` scalar type represents a file upload. */
Upload: any;
};
export enum CacheControlScope {
Public = 'PUBLIC',
Private = 'PRIVATE'
}
export type CreateUserInput = {
username: Scalars['String'];
password: Scalars['String'];
email: Scalars['String'];
};
export type InfoResponse = {
__typename?: 'InfoResponse';
version: Scalars['String'];
packageName: Scalars['String'];
};
export type Mutation = {
__typename?: 'Mutation';
ping: Scalars['String'];
signUp: User;
signIn?: Maybe<SessionResponse>;
};
export type MutationSignUpArgs = {
input: CreateUserInput;
};
export type MutationSignInArgs = {
input?: Maybe<SignInInput>;
};
export type Query = {
__typename?: 'Query';
info: InfoResponse;
test: TestResponse;
users: Array<Maybe<User>>;
self: User;
user?: Maybe<User>;
};
export type QueryUserArgs = {
id: Scalars['ID'];
};
export type Session = {
__typename?: 'Session';
id: Scalars['ID'];
user: Scalars['ID'];
expiresAt: Scalars['DateTime'];
};
export type SessionResponse = {
__typename?: 'SessionResponse';
token: Scalars['ID'];
expiresAt: Scalars['DateTime'];
};
export type SignInInput = {
username: Scalars['String'];
password: Scalars['String'];
};
export type TestResponse = {
__typename?: 'TestResponse';
secret: Scalars['String'];
};
export type User = {
__typename?: 'User';
id?: Maybe<Scalars['ID']>;
username: Scalars['String'];
displayName?: Maybe<Scalars['String']>;
bio?: Maybe<Scalars['String']>;
singleUserMode: Scalars['Boolean'];
emailHash?: Maybe<Scalars['String']>;
};
export type UserSettings = {
__typename?: 'UserSettings';
id?: Maybe<Scalars['ID']>;
useGravatar?: Maybe<Scalars['Boolean']>;
};
export type ResolverTypeWrapper<T> = Promise<T> | T;
export type LegacyStitchingResolver<TResult, TParent, TContext, TArgs> = {
fragment: string;
resolve: ResolverFn<TResult, TParent, TContext, TArgs>;
};
export type NewStitchingResolver<TResult, TParent, TContext, TArgs> = {
selectionSet: string;
resolve: ResolverFn<TResult, TParent, TContext, TArgs>;
};
export type StitchingResolver<TResult, TParent, TContext, TArgs> = LegacyStitchingResolver<TResult, TParent, TContext, TArgs> | NewStitchingResolver<TResult, TParent, TContext, TArgs>;
export type Resolver<TResult, TParent = {}, TContext = {}, TArgs = {}> =
| ResolverFn<TResult, TParent, TContext, TArgs>
| StitchingResolver<TResult, TParent, TContext, TArgs>;
export type ResolverFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => Promise<TResult> | TResult;
export type SubscriptionSubscribeFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => AsyncIterator<TResult> | Promise<AsyncIterator<TResult>>;
export type SubscriptionResolveFn<TResult, TParent, TContext, TArgs> = (
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => TResult | Promise<TResult>;
export interface SubscriptionSubscriberObject<TResult, TKey extends string, TParent, TContext, TArgs> {
subscribe: SubscriptionSubscribeFn<{ [key in TKey]: TResult }, TParent, TContext, TArgs>;
resolve?: SubscriptionResolveFn<TResult, { [key in TKey]: TResult }, TContext, TArgs>;
}
export interface SubscriptionResolverObject<TResult, TParent, TContext, TArgs> {
subscribe: SubscriptionSubscribeFn<any, TParent, TContext, TArgs>;
resolve: SubscriptionResolveFn<TResult, any, TContext, TArgs>;
}
export type SubscriptionObject<TResult, TKey extends string, TParent, TContext, TArgs> =
| SubscriptionSubscriberObject<TResult, TKey, TParent, TContext, TArgs>
| SubscriptionResolverObject<TResult, TParent, TContext, TArgs>;
export type SubscriptionResolver<TResult, TKey extends string, TParent = {}, TContext = {}, TArgs = {}> =
| ((...args: any[]) => SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>)
| SubscriptionObject<TResult, TKey, TParent, TContext, TArgs>;
export type TypeResolveFn<TTypes, TParent = {}, TContext = {}> = (
parent: TParent,
context: TContext,
info: GraphQLResolveInfo
) => Maybe<TTypes> | Promise<Maybe<TTypes>>;
export type IsTypeOfResolverFn<T = {}, TContext = {}> = (obj: T, context: TContext, info: GraphQLResolveInfo) => boolean | Promise<boolean>;
export type NextResolverFn<T> = () => Promise<T>;
export type DirectiveResolverFn<TResult = {}, TParent = {}, TContext = {}, TArgs = {}> = (
next: NextResolverFn<TResult>,
parent: TParent,
args: TArgs,
context: TContext,
info: GraphQLResolveInfo
) => TResult | Promise<TResult>;
/** Mapping between all available schema types and the resolvers types */
export type ResolversTypes = {
CacheControlScope: CacheControlScope;
CreateUserInput: CreateUserInput;
String: ResolverTypeWrapper<Scalars['String']>;
DateTime: ResolverTypeWrapper<Scalars['DateTime']>;
InfoResponse: ResolverTypeWrapper<InfoResponse>;
Mutation: ResolverTypeWrapper<{}>;
Query: ResolverTypeWrapper<{}>;
ID: ResolverTypeWrapper<Scalars['ID']>;
Session: ResolverTypeWrapper<Session>;
SessionResponse: ResolverTypeWrapper<SessionResponse>;
SignInInput: SignInInput;
TestResponse: ResolverTypeWrapper<TestResponse>;
Upload: ResolverTypeWrapper<Scalars['Upload']>;
User: ResolverTypeWrapper<User>;
Boolean: ResolverTypeWrapper<Scalars['Boolean']>;
UserSettings: ResolverTypeWrapper<UserSettings>;
Int: ResolverTypeWrapper<Scalars['Int']>;
};
/** Mapping between all available schema types and the resolvers parents */
export type ResolversParentTypes = {
CreateUserInput: CreateUserInput;
String: Scalars['String'];
DateTime: Scalars['DateTime'];
InfoResponse: InfoResponse;
Mutation: {};
Query: {};
ID: Scalars['ID'];
Session: Session;
SessionResponse: SessionResponse;
SignInInput: SignInInput;
TestResponse: TestResponse;
Upload: Scalars['Upload'];
User: User;
Boolean: Scalars['Boolean'];
UserSettings: UserSettings;
Int: Scalars['Int'];
};
export type CacheControlDirectiveArgs = { maxAge?: Maybe<Scalars['Int']>;
scope?: Maybe<CacheControlScope>; };
export type CacheControlDirectiveResolver<Result, Parent, ContextType = any, Args = CacheControlDirectiveArgs> = DirectiveResolverFn<Result, Parent, ContextType, Args>;
export interface DateTimeScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['DateTime'], any> {
name: 'DateTime';
}
export type InfoResponseResolvers<ContextType = any, ParentType extends ResolversParentTypes['InfoResponse'] = ResolversParentTypes['InfoResponse']> = {
version?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
packageName?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type MutationResolvers<ContextType = any, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = {
ping?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
signUp?: Resolver<ResolversTypes['User'], ParentType, ContextType, RequireFields<MutationSignUpArgs, 'input'>>;
signIn?: Resolver<Maybe<ResolversTypes['SessionResponse']>, ParentType, ContextType, RequireFields<MutationSignInArgs, never>>;
};
export type QueryResolvers<ContextType = any, ParentType extends ResolversParentTypes['Query'] = ResolversParentTypes['Query']> = {
info?: Resolver<ResolversTypes['InfoResponse'], ParentType, ContextType>;
test?: Resolver<ResolversTypes['TestResponse'], ParentType, ContextType>;
users?: Resolver<Array<Maybe<ResolversTypes['User']>>, ParentType, ContextType>;
self?: Resolver<ResolversTypes['User'], ParentType, ContextType>;
user?: Resolver<Maybe<ResolversTypes['User']>, ParentType, ContextType, RequireFields<QueryUserArgs, 'id'>>;
};
export type SessionResolvers<ContextType = any, ParentType extends ResolversParentTypes['Session'] = ResolversParentTypes['Session']> = {
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
user?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
expiresAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type SessionResponseResolvers<ContextType = any, ParentType extends ResolversParentTypes['SessionResponse'] = ResolversParentTypes['SessionResponse']> = {
token?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
expiresAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type TestResponseResolvers<ContextType = any, ParentType extends ResolversParentTypes['TestResponse'] = ResolversParentTypes['TestResponse']> = {
secret?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export interface UploadScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['Upload'], any> {
name: 'Upload';
}
export type UserResolvers<ContextType = any, ParentType extends ResolversParentTypes['User'] = ResolversParentTypes['User']> = {
id?: Resolver<Maybe<ResolversTypes['ID']>, ParentType, ContextType>;
username?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
displayName?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
bio?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
singleUserMode?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
emailHash?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type UserSettingsResolvers<ContextType = any, ParentType extends ResolversParentTypes['UserSettings'] = ResolversParentTypes['UserSettings']> = {
id?: Resolver<Maybe<ResolversTypes['ID']>, ParentType, ContextType>;
useGravatar?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type Resolvers<ContextType = any> = {
DateTime?: GraphQLScalarType;
InfoResponse?: InfoResponseResolvers<ContextType>;
Mutation?: MutationResolvers<ContextType>;
Query?: QueryResolvers<ContextType>;
Session?: SessionResolvers<ContextType>;
SessionResponse?: SessionResponseResolvers<ContextType>;
TestResponse?: TestResponseResolvers<ContextType>;
Upload?: GraphQLScalarType;
User?: UserResolvers<ContextType>;
UserSettings?: UserSettingsResolvers<ContextType>;
};
/**
* @deprecated
* Use "Resolvers" root object instead. If you wish to get "IResolvers", add "typesPrefix: I" to your config.
*/
export type IResolvers<ContextType = any> = Resolvers<ContextType>;
export type DirectiveResolvers<ContextType = any> = {
cacheControl?: CacheControlDirectiveResolver<any, any, ContextType>;
};
/**
* @deprecated
* Use "DirectiveResolvers" root object instead. If you wish to get "IDirectiveResolvers", add "typesPrefix: I" to your config.
*/
export type IDirectiveResolvers<ContextType = any> = DirectiveResolvers<ContextType>;

+ 15
- 0
src/types/resolver.ts View File

@ -0,0 +1,15 @@
import { SessionsModel } from "miracle-tv/db/models/Sessions"
import { UsersModel } from "miracle-tv/db/models/Users"
import { DbSession, DbUser } from "miracle-tv/db/types"
import { Operation } from "rethinkdb"
export type DbRunFn = <T>(request: Operation<T>) => Promise<T>
export type ResolverContext = {
session: DbSession
user: DbUser
db: {
users: UsersModel,
sessions: SessionsModel,
}
}

+ 22
- 0
tsconfig.json View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"lib": ["es2015", "es2016", "dom", "es2017", "es6", "es5"],
"esModuleInterop": true,
"noImplicitAny": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"sourceMap": false,
"outDir": "./dist/server",
"baseUrl": "./",
"types": [],
"typeRoots" : ["./node_modules", "./node_modules/@types"],
"paths": {
"miracle-tv/*": [ "src/*" ]
}
},
"include": [
"./src/**/*"
]
}

+ 4954
- 0
yarn.lock
File diff suppressed because it is too large
View File


Loading…
Cancel
Save