diff --git a/package.json b/package.json index 9a689b6c..4ce94e06 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@types/graphql-iso-date": "^3.3.1", "@types/isomorphic-fetch": "^0.0.34", "@types/lodash": "^4.14.119", + "@types/mkdirp": "^0.5.2", "@types/node": "^10.12.18", "@types/node-emoji": "^1.8.0", "@types/pg": "^7.4.11", diff --git a/src/core/BaseModel.ts b/src/core/BaseModel.ts index d615d75f..5b3278a2 100644 --- a/src/core/BaseModel.ts +++ b/src/core/BaseModel.ts @@ -50,9 +50,13 @@ export abstract class BaseModel implements BaseGraphQLObject { @VersionColumn() version!: number; + getId() { + return shortid.generate(); + } + @BeforeInsert() setId() { - this.id = shortid.generate(); + this.id = this.getId(); } } diff --git a/src/core/Context.ts b/src/core/Context.ts index 39cde895..4103cfbd 100644 --- a/src/core/Context.ts +++ b/src/core/Context.ts @@ -5,11 +5,7 @@ import { Connection } from 'typeorm'; export interface Context { connection: Connection; request: Request; - user: { - email: string; - id: string; - permissions: string[]; - }; + user?: any; dataLoader: { initialized: boolean; loaders: { [key: string]: { [key: string]: any } }; diff --git a/src/core/app.ts b/src/core/app.ts index 96cd6885..38e7465c 100644 --- a/src/core/app.ts +++ b/src/core/app.ts @@ -9,6 +9,7 @@ import { printSchema, GraphQLSchema } from 'graphql'; import { Binding } from 'graphql-binding'; import { Server as HttpServer } from 'http'; import { Server as HttpsServer } from 'https'; +import * as mkdirp from 'mkdirp'; import * as path from 'path'; import { buildSchema, useContainer as TypeGraphQLUseContainer } from 'type-graphql'; // formatArgumentValidationError import { Connection, ConnectionOptions, useContainer as TypeORMUseContainer } from 'typeorm'; @@ -22,9 +23,9 @@ import { generateBindingFile } from './binding'; export interface AppOptions { container?: any; // TODO: fix types - Container from typeDI - host?: string; generatedFolder?: string; + middlewares?: any[]; // TODO: fix port?: string | number; warthogImportPath?: string; } @@ -49,9 +50,16 @@ export class App { TypeORMUseContainer(this.appOptions.container); } - this.appHost = this.appOptions.host || process.env.APP_HOST || 'localhost'; + const host: string | undefined = this.appOptions.host || process.env.APP_HOST; + if (!host) { + throw new Error('`host` is required'); + } + + this.appHost = host; this.appPort = parseInt(String(this.appOptions.port || process.env.APP_PORT), 10) || 4000; this.generatedFolder = this.appOptions.generatedFolder || path.join(process.cwd(), 'generated'); + + mkdirp.sync(this.generatedFolder); } async establishDBConnection(): Promise { @@ -65,10 +73,10 @@ export class App { return this.connection; } - async getBinding(): Promise { + async getBinding(options: { origin?: string; token?: string } = {}): Promise { return getRemoteBinding(`http://${this.appHost}:${this.appPort}/graphql`, { - origin: 'seed-script', // TODO: allow this to be passed in - token: 'faketoken' // TODO: allow this to be passed in + origin: 'warthog', + ...options }); } @@ -93,10 +101,10 @@ export class App { if (!this.schema) { this.schema = await buildSchema({ authChecker, - globalMiddlewares: [DataLoaderMiddleware], // ErrorLoggerMiddleware + // TODO: ErrorLoggerMiddleware + globalMiddlewares: [DataLoaderMiddleware, ...(this.appOptions.middlewares || [])], resolvers: [process.cwd() + '/**/*.resolver.ts'] - // TODO - // scalarsMap: [{ type: GraphQLDate, scalar: GraphQLDate }] + // TODO: scalarsMap: [{ type: GraphQLDate, scalar: GraphQLDate }] }); } @@ -129,21 +137,16 @@ export class App { await this.generateBinding(); this.graphQLServer = new ApolloServer({ - context: (options: { request: Request }) => { + context: (options: { request: Request; context?: any }) => { const context: Context = { connection: this.connection, dataLoader: { initialized: false, loaders: {} }, - request: options.request, - user: { - email: 'admin@test.com', - id: 'abc12345', - permissions: ['user:read', 'user:update', 'user:create', 'user:delete', 'photo:delete'] - } + request: options.request }; - return context; + return { ...context, ...(options.context || {}) }; }, schema: this.schema }); diff --git a/src/core/binding.ts b/src/core/binding.ts index 0991abf3..433308ce 100644 --- a/src/core/binding.ts +++ b/src/core/binding.ts @@ -10,18 +10,18 @@ import * as path from 'path'; // require('ts-node').register(); -import { StringMap } from '..'; +import { StringMapOptional } from '..'; const debug = Debug('binding'); -interface LinkOptions { - token: string; +interface LinkOptions extends StringMapOptional { + token?: string; origin: string; } export class Link extends HttpLink { constructor(uri: string, options: LinkOptions) { - let headers: StringMap = { ...options }; + let headers = { ...options }; if (headers.token) { headers['Authorization'] = `Bearer ${headers.token}`; delete headers.token; diff --git a/src/core/types.ts b/src/core/types.ts index 8fa5389d..0e3f39ce 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -1,6 +1,7 @@ export type Omit = Pick>; export type StringMap = { [key: string]: string }; +export type StringMapOptional = { [key: string]: string | undefined }; export type DateTime = string; export type IDType = string; diff --git a/yarn.lock b/yarn.lock index 803d3d31..0a45a9b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -377,6 +377,13 @@ resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/mkdirp@^0.5.2": + version "0.5.2" + resolved "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" + integrity sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg== + dependencies: + "@types/node" "*" + "@types/node-emoji@^1.8.0": version "1.8.0" resolved "https://registry.npmjs.org/@types/node-emoji/-/node-emoji-1.8.0.tgz#6bc88a880cdcb3c165e2828d056db242e8829a8b"