diff --git a/packages/prime-core/.env.example b/packages/prime-core/.env.example index 66d720278..067fd52b7 100644 --- a/packages/prime-core/.env.example +++ b/packages/prime-core/.env.example @@ -1,3 +1,8 @@ DATABASE_URL=postgresql://localhost:5432/prime TEST_DATABASE_URL=postgresql://localhost:5432/prime-test SESSION_SECRET=keyboard-cat-dart + +S3_BUCKET= +S3_REGION= +S3_ACCESS_KEY_ID= +S3_SECRET_ACCESS_KEY= diff --git a/packages/prime-core/package.json b/packages/prime-core/package.json index 81ffebfce..1f1a146d6 100644 --- a/packages/prime-core/package.json +++ b/packages/prime-core/package.json @@ -51,12 +51,14 @@ "@primecms/field-slice": "^0.3.4-beta.0", "@primecms/field-string": "^0.3.4-beta.0", "apollo-server-express": "2.4.0", + "aws-sdk": "*", "class-validator": "0.9.1", "cors": "2.8.5", "dataloader": "1.4.0", "debug": "4.1.1", "dotenv": "6.2.0", "express": "4.16.4", + "file-type": "^11.0.0", "graphql": "^14.1.1", "graphql-iso-date": "3.6.1", "graphql-type-json": "^0.2.1", diff --git a/packages/prime-core/src/entities/Asset.ts b/packages/prime-core/src/entities/Asset.ts new file mode 100644 index 000000000..9b1c811d6 --- /dev/null +++ b/packages/prime-core/src/entities/Asset.ts @@ -0,0 +1,66 @@ +import { User } from '@accounts/typeorm'; +import { GraphQLFloat } from 'graphql'; +import { Field, ID, ObjectType } from 'type-graphql'; +import { + Column, + CreateDateColumn, + Entity, + ManyToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity() +@ObjectType() +export class Asset { + @Field(type => ID) + @PrimaryGeneratedColumn('uuid') + public id: string; + + @CreateDateColumn() + @Field({ nullable: true }) + public createdAt: Date; + + @UpdateDateColumn() + @Field({ nullable: true }) + public updatedAt: Date; + + @Column({ type: 'timestamp', nullable: true }) + @Field({ nullable: true }) + public deletedAt: Date; + + @Column({ nullable: false }) + @Field({ nullable: false }) + public url: string; + + @Column({ nullable: false }) + @Field({ nullable: false }) + public mimeType: string; + + @Column({ nullable: false }) + @Field({ nullable: false }) + public handle: string; + + @Column({ nullable: false }) + @Field({ nullable: false }) + public fileName: string; + + @Column({ nullable: false }) + @Field({ nullable: false }) + public fileSize: number; + + @Column('float', { nullable: true }) + @Field(type => GraphQLFloat, { nullable: true }) + public width: number; + + @Column('float', { nullable: true }) + @Field(type => GraphQLFloat, { nullable: true }) + public height: number; + + @Column({ nullable: true }) + @Field({ nullable: true }) + public userId?: string; + + @ManyToOne(type => User, { nullable: true, onDelete: 'SET NULL' }) + public user: User; +} diff --git a/packages/prime-core/src/modules/external/interfaces/Upload.ts b/packages/prime-core/src/modules/external/interfaces/Upload.ts new file mode 100644 index 000000000..0d7566a32 --- /dev/null +++ b/packages/prime-core/src/modules/external/interfaces/Upload.ts @@ -0,0 +1,23 @@ +import { ReadStream } from 'fs'; + +/** + * File upload details, resolved from an `Upload` scalar promise. + * See: https://github.com/jaydenseric/graphql-upload + */ +export interface Upload { + /** File name */ + filename: string; + + /** File MIME type. Provided by the client and can’t be trusted. */ + mimetype: string; + + /** File stream transfer encoding. */ + encoding: string; + + /** + * createReadStream Returns a Node.js readable stream of the file contents, + * for processing and storing the file. Multiple calls create independent streams. + * Throws if called after all resolvers have resolved, or after an error has interrupted the request. + */ + createReadStream: () => ReadStream; +} diff --git a/packages/prime-core/src/modules/internal/index.ts b/packages/prime-core/src/modules/internal/index.ts index 4fad4c7ac..65a7dca30 100644 --- a/packages/prime-core/src/modules/internal/index.ts +++ b/packages/prime-core/src/modules/internal/index.ts @@ -7,6 +7,7 @@ import { Connection } from 'typeorm'; import { pubSub } from '../../utils/pubSub'; import { createAccounts } from '../accounts'; import { AccessTokenResolver } from './resolvers/AccessTokenResolver'; +import { AssetResolver } from './resolvers/AssetResolver'; import { DocumentResolver } from './resolvers/DocumentResolver'; import { PrimeResolver } from './resolvers/PrimeResolver'; import { ReleaseResolver } from './resolvers/ReleaseResolver'; @@ -29,6 +30,7 @@ export const createInternal = async (connection: Connection) => { const schema = await buildTypeDefsAndResolvers({ resolvers: [ AccessTokenResolver, + AssetResolver, DocumentResolver, PrimeResolver, ReleaseResolver, diff --git a/packages/prime-core/src/modules/internal/repositories/AssetRepository.ts b/packages/prime-core/src/modules/internal/repositories/AssetRepository.ts new file mode 100644 index 000000000..cd202b18e --- /dev/null +++ b/packages/prime-core/src/modules/internal/repositories/AssetRepository.ts @@ -0,0 +1,6 @@ +import { EntityRepository } from 'typeorm'; +import { Asset } from '../../../entities/Asset'; +import { DataLoaderRepository } from './DataLoaderRepository'; + +@EntityRepository(Asset) +export class AssetRepository extends DataLoaderRepository {} diff --git a/packages/prime-core/src/modules/internal/resolvers/AssetResolver.ts b/packages/prime-core/src/modules/internal/resolvers/AssetResolver.ts new file mode 100644 index 000000000..ef8610a38 --- /dev/null +++ b/packages/prime-core/src/modules/internal/resolvers/AssetResolver.ts @@ -0,0 +1,111 @@ +import { Context } from 'apollo-server-core'; +import { GraphQLResolveInfo } from 'graphql'; +import { + Arg, + Args, + Ctx, + FieldResolver, + ID, + Info, + Mutation, + Query, + registerEnumType, + Resolver, + Root, +} from 'type-graphql'; +import Container from 'typedi'; +import { getRepository } from 'typeorm'; +import { EntityConnection } from 'typeorm-cursor-connection'; +import { InjectRepository } from 'typeorm-typedi-extensions'; +import { Asset } from '../../../entities/Asset'; +import { S3Storage } from '../../../utils/S3Storage'; +import { AssetRepository } from '../repositories/AssetRepository'; +import { AssetInput } from '../types/AssetInput'; +import { ConnectionArgs, createConnectionType } from '../types/createConnectionType'; +import { User } from '../types/User'; +import { Authorized } from '../utils/Authorized'; + +const AssetConnection = createConnectionType(Asset); + +enum AssetOrder { + updatedAt_ASC, + updatedAt_DESC, + id_ASC, + id_DESC, + fileName_ASC, + fileName_DESC, +} + +registerEnumType(AssetOrder, { + name: 'AssetConnectionOrder', +}); + +@Resolver(of => Asset) +export class AssetResolver { + @InjectRepository(AssetRepository) + private readonly assetRepository: AssetRepository; + private readonly storage: S3Storage; + + constructor() { + this.storage = Container.get(S3Storage); + } + + @Authorized() + @Query(returns => Asset, { nullable: true, description: 'Get Asset by ID' }) + public Asset( + @Arg('id', type => ID) id: string, + @Ctx() context: Context, + @Info() info: GraphQLResolveInfo + ) { + return this.assetRepository.loadOne(id); + } + + @Authorized() + @Query(returns => AssetConnection, { description: 'Get many Assets' }) + public async allAssets( + @Args() args: ConnectionArgs, + @Arg('order', type => AssetOrder, { defaultValue: 0 }) orderBy: string + ) { + const [sort, order]: any = orderBy.split('_'); + const connection = await new EntityConnection(args, { + repository: this.assetRepository, + sortOptions: [{ sort: `Asset.${sort}`, order }], + }); + return { + edges: await connection.edges, + totalCount: await this.assetRepository.count(), + }; + } + + @Authorized() + @Mutation(returns => Asset, { description: 'Create Asset' }) + public async createAsset( + @Arg('input') input: AssetInput, + @Ctx() context: Context + ): Promise { + const upload = await input.upload; + const assetInput = await this.storage.upload(upload.filename, upload.createReadStream()); + const asset = this.assetRepository.create(assetInput); + await this.assetRepository.save(asset); + return asset; + } + + @Authorized() + @Mutation(returns => Boolean, { description: 'Remove Asset by ID' }) + public async removeAsset( + @Arg('id', type => ID) id: string, + @Ctx() context: Context + ): Promise { + const entity = await this.assetRepository.findOneOrFail(id); + await this.storage.delete(entity.fileName); + return Boolean(await this.assetRepository.remove(entity)); + } + + @FieldResolver(returns => User, { description: 'Get Asset User' }) + public user(@Root() asset: Asset): Promise { + return getRepository(User).findOneOrFail({ + cache: 1000, + where: asset.user, + }); + } +} diff --git a/packages/prime-core/src/modules/internal/types/AssetInput.ts b/packages/prime-core/src/modules/internal/types/AssetInput.ts new file mode 100644 index 000000000..c68eeb14a --- /dev/null +++ b/packages/prime-core/src/modules/internal/types/AssetInput.ts @@ -0,0 +1,9 @@ +import { GraphQLUpload } from 'graphql-upload'; +import { Field, InputType } from 'type-graphql'; +import { Upload } from '../../external/interfaces/Upload'; + +@InputType() +export class AssetInput { + @Field(type => GraphQLUpload, { nullable: false }) + public upload: Promise; +} diff --git a/packages/prime-core/src/utils/S3Storage.ts b/packages/prime-core/src/utils/S3Storage.ts new file mode 100644 index 000000000..29a354d0f --- /dev/null +++ b/packages/prime-core/src/utils/S3Storage.ts @@ -0,0 +1,77 @@ +import S3 from 'aws-sdk/clients/s3'; +import fileType from 'file-type'; +import { ReadStream } from 'fs'; +import { Service } from 'typedi'; +import uuidv4 from 'uuid/v4'; +import { Asset } from '../entities/Asset'; + +@Service() +export class S3Storage { + private bucket: string; + private s3: S3; + + constructor() { + if (!process.env.S3_BUCKET) { + throw Error('S3_BUCKET not set'); + } + if (!process.env.S3_ACCESS_KEY_ID) { + throw Error('S3_ACCESS_KEY_ID not set'); + } + if (!process.env.S3_SECRET_ACCESS_KEY) { + throw Error('S3_SECRET_ACCESS_KEY not set'); + } + + this.bucket = process.env.S3_BUCKET; + this.s3 = new S3({ + credentials: { + accessKeyId: process.env.S3_ACCESS_KEY_ID, + secretAccessKey: process.env.S3_SECRET_ACCESS_KEY, + }, + }); + } + + public async upload(fileName: string, readStream1: ReadStream): Promise> { + // TODO: Detect width/height of image types + + const readStream2 = await fileType.stream(readStream1); + const { mime } = readStream2.fileType!; + + const handle = uuidv4(); + const data = await this.s3 + .upload({ + Bucket: this.bucket, + ACL: 'public-read', + Body: readStream2, + Key: handle, + ContentType: mime, + }) + .promise(); + const head = await this.head(handle); + return { + fileName, + fileSize: head.ContentLength, + handle, + mimeType: mime, + url: data.Location, + }; + } + + public async delete(fileName: string): Promise { + const data = await this.s3 + .deleteObject({ + Bucket: this.bucket, + Key: fileName, + }) + .promise(); + return data.DeleteMarker || false; + } + + private async head(fileName: string) { + return this.s3 + .headObject({ + Bucket: this.bucket, + Key: fileName, + }) + .promise(); + } +} diff --git a/packages/prime-ui/package.json b/packages/prime-ui/package.json index 5411f4683..0a4ea0944 100644 --- a/packages/prime-ui/package.json +++ b/packages/prime-ui/package.json @@ -31,6 +31,7 @@ "@primecms/field-select": "^0.3.4-beta.0", "@primecms/field-slice": "^0.3.4-beta.0", "@primecms/field-string": "^0.3.4-beta.0", + "@types/apollo-upload-client": "^8.1.1", "@types/graphql": "14.2.0", "@types/jest": "23.3.14", "@types/lodash": "4.14.133", @@ -46,6 +47,7 @@ "apollo-link-context": "1.0.17", "apollo-link-error": "1.1.10", "apollo-link-http": "1.5.14", + "apollo-upload-client": "^10.0.1", "babel-plugin-import": "1.12.0", "braft-editor": "2.2.9", "date-fns": "1.30.1", @@ -80,5 +82,8 @@ "publishConfig": { "access": "public" }, - "gitHead": "f00baf08a686c40cd5cc34fa4facdacf605b7e0c" + "gitHead": "f00baf08a686c40cd5cc34fa4facdacf605b7e0c", + "dependencies": { + "apollo-upload-client": "^10.0.1" + } } diff --git a/packages/prime-ui/src/App.tsx b/packages/prime-ui/src/App.tsx index 35e668d39..3986a09d7 100644 --- a/packages/prime-ui/src/App.tsx +++ b/packages/prime-ui/src/App.tsx @@ -2,6 +2,7 @@ import { observer } from 'mobx-react'; import React from 'react'; import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom'; import { Layout } from './components/layout/Layout'; +import { AssetsList } from './routes/assets/AssetsList'; import { DocumentsDetail } from './routes/documents/DocumentsDetail'; import { DocumentsList } from './routes/documents/DocumentsList'; import { Login } from './routes/login/Login'; @@ -71,6 +72,7 @@ export class App extends React.Component { } /> + { Schemas + + + + Assets + + diff --git a/packages/prime-ui/src/routes/assets/AssetsList.css b/packages/prime-ui/src/routes/assets/AssetsList.css new file mode 100644 index 000000000..4f4673066 --- /dev/null +++ b/packages/prime-ui/src/routes/assets/AssetsList.css @@ -0,0 +1,12 @@ +.ant-upload-list-picture-card .ant-upload-list-item { + margin: 0; + width: auto; + height: auto; + max-height: 100%; +} + +.ant-upload.ant-upload-select-picture-card { + margin: 0; + width: auto; + height: auto; +} diff --git a/packages/prime-ui/src/routes/assets/AssetsList.tsx b/packages/prime-ui/src/routes/assets/AssetsList.tsx new file mode 100644 index 000000000..26a106b6d --- /dev/null +++ b/packages/prime-ui/src/routes/assets/AssetsList.tsx @@ -0,0 +1,218 @@ +import { Avatar, Card, Icon, Layout, Table, Tooltip, Upload } from 'antd'; +import { distanceInWordsToNow } from 'date-fns'; +import gql from 'graphql-tag'; +import { get } from 'lodash'; +import React from 'react'; +import { Query } from 'react-apollo'; +import { Toolbar } from '../../components/toolbar/Toolbar'; +import { Assets } from '../../stores/assets'; +import { ContentReleases } from '../../stores/contentReleases'; +import { client } from '../../utils/client'; +import { fileSizeFormat } from '../../utils/file-size-format'; +import { stringToColor } from '../../utils/stringToColor'; +import './AssetsList.css'; + +interface CustomRequestParam { + action: string; + data: any; + file: File; + filename: string; + headers: any; + onError: (err: Error, ret: any) => void; + onProgress: (e: Event) => void; + onSuccess: (ret: any, xhr: any) => void; + withCredentials: boolean; +} + +interface IOptions { + [key: string]: string | undefined; +} + +const GET_ASSET_ENTRIES = gql` + query allAssets($first: Int = 10, $skip: Int, $order: AssetConnectionOrder!) { + allAssets(first: $first, skip: $skip, order: $order) { + totalCount + edges { + node { + id + fileName + fileSize + mimeType + url + updatedAt + userId + } + cursor + } + } + } +`; + +const PER_PAGE = 30; + +export const AssetsList = ({ match, history }: any) => { + React.useEffect(() => { + ContentReleases.loadAll(); + }, [match.location]); + + let userId: any; + let skip = 0; + + const customRequest = (param: CustomRequestParam) => { + return Assets.create({ upload: param.file }) + .catch(err => param.onError(err, null)) + .then(response => param.onSuccess(response, null)); + }; + + return ( + + {({ loading, error, data, refetch }) => { + if (error) { + return `Error! ${error.message}`; + } + + const pagination = { + total: get(data, 'allAssets.totalCount'), + pageSize: PER_PAGE, + }; + + const onTableChange = async (paging: any, filters: any, sorter: any) => { + userId = filters['user.id'] && filters['user.id'][0]; + + const formatSorterField = (field: string = 'updatedAt') => { + return `${field}_${sorter.order === 'ascend' ? 'ASC' : 'DESC'}`; + }; + + skip = paging.pageSize * (paging.current - 1); + + const variables = { + first: paging.pageSize, + skip, + order: formatSorterField(sorter.field), + }; + refetch(variables); + }; + + const columns = [ + { + title: '', + dataIndex: 'url', + sorter: false, + width: '50px', + render(url: string) { + return ; + }, + }, + { + title: 'Name', + width: '175px', + dataIndex: 'fileName', + filterMultiple: false, + }, + { + title: 'Type', + width: '175px', + dataIndex: 'mimeType', + filterMultiple: false, + }, + { + title: 'Size', + width: '50px', + dataIndex: 'fileSize', + filterMultiple: false, + render(fileSize: number) { + return fileSizeFormat(fileSize); + }, + }, + { + title: 'Updated', + width: '175px', + dataIndex: 'updatedAt', + sorter: true, + defaultSortOrder: 'descend' as any, + render(text: string) { + return distanceInWordsToNow(new Date(text)) + ' ago'; + }, + }, + { + title: 'Author', + dataIndex: 'user.id', + width: '120px', + sorter: true, + filters: get(data, 'allUsers', []).map(({ id, email }: any) => ({ + text: email, + value: id, + })), + filteredValue: userId, + filterMultiple: false, + align: 'center' as any, + render(text: string, record: any) { + if (!record.user) { + return ; + } + const { firstname, lastname, email } = record.user; + return ( + + + {firstname.substring(0, 1)} + {lastname.substring(0, 1)} + + + ); + }, + }, + ]; + + const items = get(data, 'allAssets.edges', []).map(({ node }: any) => node); + + return ( + + +
+

Assets

+
+ +
+ +
Upload assets
+
+
+
+ + + 'prime-row-click'} + onChange={onTableChange} + onRow={record => ({ + onClick: () => { + history.push(`/assets/doc/${record.id}`); + }, + })} + /> + +
+ + + ); + }} + + ); +}; diff --git a/packages/prime-ui/src/stores/assets.ts b/packages/prime-ui/src/stores/assets.ts new file mode 100644 index 000000000..60d599f9c --- /dev/null +++ b/packages/prime-ui/src/stores/assets.ts @@ -0,0 +1,73 @@ +import { destroy, flow, types } from 'mobx-state-tree'; +import { client } from '../utils/client'; +import { Asset } from './models/Asset'; +import { CREATE_ASSET, REMOVE_ASSET } from './mutations'; +import { ALL_ASSETS } from './queries'; + +export const Assets = types + .model('Assets', { + items: types.map(types.late(() => Asset)), + loading: false, + loaded: false, + error: false, + }) + .views(self => ({ + get list() { + return Array.from(self.items.values()); + }, + })) + .actions(self => { + const loadAll = flow(function*(clear = true) { + self.loading = true; + + if (clear) { + self.items.clear(); + } + + try { + const { data } = yield client.query({ + query: ALL_ASSETS, + }); + data.allAssets.edges.forEach((asset: any) => { + const item = Asset.create(asset.node); + self.items.put(item); + }); + self.loaded = true; + } catch (err) { + self.error = true; + } + + self.loading = false; + }); + + const create = flow(function*(input: { upload: File }) { + const { data } = yield client.mutate({ + mutation: CREATE_ASSET, + variables: { + input, + }, + }); + if (data) { + const item = Asset.create(data.createAsset); + self.items.put(item); + return item; + } + }); + + const remove = flow(function*(asset: any) { + const { data } = yield client.mutate({ + mutation: REMOVE_ASSET, + variables: { id: asset.id }, + }); + if (data) { + destroy(asset); + } + }); + + return { + loadAll, + create, + remove, + }; + }) + .create(); diff --git a/packages/prime-ui/src/stores/models/Asset.ts b/packages/prime-ui/src/stores/models/Asset.ts new file mode 100644 index 000000000..ea6117224 --- /dev/null +++ b/packages/prime-ui/src/stores/models/Asset.ts @@ -0,0 +1,17 @@ +import { types } from 'mobx-state-tree'; + +export const Asset = types + .model('Asset', { + id: types.identifier, + fileName: types.string, + fileSize: types.integer, + mimeType: types.string, + url: types.string, + createdAt: types.maybeNull(types.Date), + updatedAt: types.maybeNull(types.Date), + }) + .preProcessSnapshot(snapshot => ({ + ...snapshot, + createdAt: snapshot.createdAt ? new Date(snapshot.createdAt) : null, + updatedAt: snapshot.updatedAt ? new Date(snapshot.updatedAt) : null, + })); diff --git a/packages/prime-ui/src/stores/mutations/createAsset.gql b/packages/prime-ui/src/stores/mutations/createAsset.gql new file mode 100644 index 000000000..e343a960e --- /dev/null +++ b/packages/prime-ui/src/stores/mutations/createAsset.gql @@ -0,0 +1,11 @@ +mutation CreateAsset($input:AssetInput!) { + createAsset(input:$input) { + id + fileName + fileSize + mimeType + url + createdAt + updatedAt + } +} diff --git a/packages/prime-ui/src/stores/mutations/index.ts b/packages/prime-ui/src/stores/mutations/index.ts index 554a6a4ad..f3514d748 100644 --- a/packages/prime-ui/src/stores/mutations/index.ts +++ b/packages/prime-ui/src/stores/mutations/index.ts @@ -1,9 +1,11 @@ +import CREATE_ASSET from './createAsset.gql'; import CREATE_CONTENT_ENTRY from './createContentEntry.gql'; import CREATE_CONTENT_RELEASE from './createContentRelease.gql'; import CREATE_CONTENT_TYPE from './createContentType.gql'; import CREATE_WEBHOOK from './createWebhook.gql'; import PUBLISH_CONTENT_ENTRY from './publishContentEntry.gql'; import PUBLISH_CONTENT_RELEASE from './publishContentRelease.gql'; +import REMOVE_ASSET from './removeAsset.gql'; import REMOVE_CONTENT_ENTRY from './removeContentEntry.gql'; import REMOVE_CONTENT_RELEASE from './removeContentRelease.gql'; import REMOVE_CONTENT_TYPE from './removeContentType.gql'; @@ -17,6 +19,8 @@ import UPDATE_WEBHOOK from './updateWebhook.gql'; export { SAVE_SCHEMA, + CREATE_ASSET, + REMOVE_ASSET, CREATE_CONTENT_TYPE, REMOVE_CONTENT_TYPE, UPDATE_CONTENT_TYPE, diff --git a/packages/prime-ui/src/stores/mutations/removeAsset.gql b/packages/prime-ui/src/stores/mutations/removeAsset.gql new file mode 100644 index 000000000..5b512567f --- /dev/null +++ b/packages/prime-ui/src/stores/mutations/removeAsset.gql @@ -0,0 +1,3 @@ +mutation removeAsset($id: ID!) { + removeAsset(id: $id) +} diff --git a/packages/prime-ui/src/stores/queries/allAssets.gql b/packages/prime-ui/src/stores/queries/allAssets.gql new file mode 100644 index 000000000..6b5949116 --- /dev/null +++ b/packages/prime-ui/src/stores/queries/allAssets.gql @@ -0,0 +1,14 @@ +query allAssets { + allAssets { + edges { + node { + id + fileName + mimeType + url + createdAt + updatedAt + } + } + } +} diff --git a/packages/prime-ui/src/stores/queries/index.ts b/packages/prime-ui/src/stores/queries/index.ts index da1254e1a..5e0d5d611 100644 --- a/packages/prime-ui/src/stores/queries/index.ts +++ b/packages/prime-ui/src/stores/queries/index.ts @@ -1,3 +1,4 @@ +import ALL_ASSETS from './allAssets.gql'; import ALL_CONTENT_RELEASES from './allContentReleases.gql'; import ALL_CONTENT_TYPES from './allContentTypes.gql'; import ALL_FIELDS from './allFields.gql'; @@ -11,6 +12,7 @@ import LOAD_SCHEMA from './loadSchema.gql'; export { LOAD_SCHEMA, + ALL_ASSETS, ALL_FIELDS, ALL_USERS, ALL_CONTENT_RELEASES, diff --git a/packages/prime-ui/src/utils/client.ts b/packages/prime-ui/src/utils/client.ts index 8d8027939..bb0345789 100644 --- a/packages/prime-ui/src/utils/client.ts +++ b/packages/prime-ui/src/utils/client.ts @@ -4,7 +4,7 @@ import { ApolloClient } from 'apollo-client'; import { ApolloLink } from 'apollo-link'; import { setContext } from 'apollo-link-context'; import { onError } from 'apollo-link-error'; -import { HttpLink } from 'apollo-link-http'; +import { createUploadLink } from 'apollo-upload-client'; import { Settings } from '../stores/settings'; import { accountsClient } from './accounts'; @@ -27,7 +27,7 @@ const errorLink = onError(({ graphQLErrors, networkError }) => { } }); -const httpLink = new HttpLink({ +const httpUploadLink = createUploadLink({ uri: `${coreUrl}/prime/graphql`, credentials: 'include', }); @@ -47,7 +47,7 @@ const withToken = setContext(async (input, b) => { }); export const client = new ApolloClient({ - link: ApolloLink.from([withToken, errorLink, httpLink]), + link: ApolloLink.from([withToken, errorLink, httpUploadLink]), cache: new InMemoryCache(), }); diff --git a/packages/prime-ui/src/utils/file-size-format.ts b/packages/prime-ui/src/utils/file-size-format.ts new file mode 100644 index 000000000..8b6736eba --- /dev/null +++ b/packages/prime-ui/src/utils/file-size-format.ts @@ -0,0 +1,12 @@ +const FILESIZE_UNITS = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; + +export function fileSizeFormat(bytes = 0, precision = 0): string { + let unit = 0; + + while (bytes >= 1024) { + bytes /= 1024; + unit++; + } + + return bytes.toFixed(+precision) + FILESIZE_UNITS[unit]; +} diff --git a/yarn.lock b/yarn.lock index 389e9ae89..41b78fc86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2170,6 +2170,15 @@ dependencies: "@types/node" "*" +"@types/apollo-upload-client@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/apollo-upload-client/-/apollo-upload-client-8.1.1.tgz#ea4e015da059ee8afd734cdc30d86146dc2aab50" + integrity sha512-6kVNS8QinfRLre0JimJGQmV2TtY4u5gemVEGsu4GDTs38te7v8wGCGEz32zEZoU1KVdIcQ/+s2xRoL78kemkIw== + dependencies: + "@types/extract-files" "*" + apollo-link "^1.0.0" + apollo-link-http-common "^0.2.4" + "@types/babel__core@^7.1.0": version "7.1.1" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.1.tgz#ce9a9e5d92b7031421e1d0d74ae59f572ba48be6" @@ -2260,6 +2269,11 @@ "@types/express-serve-static-core" "*" "@types/serve-static" "*" +"@types/extract-files@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/extract-files/-/extract-files-3.1.0.tgz#a93ce5b82b81a9b420f3a6d14b9bfc043779fd2b" + integrity sha512-tLNI7qpktX1NYqE4yXSp9sHgBJOH4kO03WAgeZYDC+xhi005ZDEHkHVdy+/zoNEHasu5kJIU0yqECgT7xxANdg== + "@types/fs-extra@^5.0.3": version "5.0.4" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.4.tgz#b971134d162cc0497d221adde3dbb67502225599" @@ -2850,6 +2864,11 @@ ansi-regex@^4.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -3118,7 +3137,7 @@ apollo-link-error@1.1.10: apollo-link-http-common "^0.2.13" tslib "^1.9.3" -apollo-link-http-common@^0.2.13: +apollo-link-http-common@^0.2.13, apollo-link-http-common@^0.2.4: version "0.2.13" resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.13.tgz#c688f6baaffdc7b269b2db7ae89dae7c58b5b350" integrity sha512-Uyg1ECQpTTA691Fwx5e6Rc/6CPSu4TB4pQRTGIpwZ4l5JDOQ+812Wvi/e3IInmzOZpwx5YrrOfXrtN8BrsDXoA== @@ -3230,6 +3249,15 @@ apollo-tracing@0.5.0: apollo-server-env "2.2.0" graphql-extensions "0.5.0" +apollo-upload-client@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-10.0.1.tgz#e8446288d03edb1c582c91c26a18b27533f85013" + integrity sha512-K6WnuYQi0RRTNO+aSPVjoUWXp4QSr+eoKU4fE0OKQp25XRF2oXl2cTLs+Q4Nk0wOIHM76YGdo/IHtzuNR7jO+A== + dependencies: + apollo-link "^1.2.11" + apollo-link-http-common "^0.2.13" + extract-files "^5.0.1" + apollo-utilities@1.3.0, apollo-utilities@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.0.tgz#9803724c07ac94ca11dc26397edb58735d2b0211" @@ -3564,6 +3592,21 @@ autoprefixer@^9.1.5: postcss "^7.0.14" postcss-value-parser "^3.3.1" +aws-sdk@*: + version "2.462.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.462.0.tgz#786606c4787cfa602a0539bf6bd573c3d995961c" + integrity sha512-CSN6wiFKlAqtafKR7EzM31s6GxLAXKv4wBhuXiFvCjc0txYdXEhIsXMRZSOh6daTAjgPOps2IMTK9/adCSe+9g== + dependencies: + buffer "4.9.1" + events "1.1.1" + ieee754 "1.1.8" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" @@ -4301,7 +4344,7 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= -buffer@^4.3.0: +buffer@4.9.1, buffer@^4.3.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= @@ -4763,6 +4806,17 @@ cli-highlight@^1.2.3: parse5 "^3.0.3" yargs "^10.0.3" +cli-highlight@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.1.tgz#2180223d51618b112f4509cf96e4a6c750b07e97" + integrity sha512-0y0VlNmdD99GXZHYnvrQcmHxP8Bi6T00qucGgBgGv4kJ0RyDthNnnFPupHV7PYv/OXSVk+azFbOeaW6+vGmx9A== + dependencies: + chalk "^2.3.0" + highlight.js "^9.6.0" + mz "^2.4.0" + parse5 "^4.0.0" + yargs "^13.0.0" + cli-spinners@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" @@ -4800,6 +4854,15 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + clone-deep@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" @@ -6225,7 +6288,7 @@ dotenv@6.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.0.0.tgz#24e37c041741c5f4b25324958ebbc34bca965935" integrity sha512-FlWbnhgjtwD+uNLUGHbMykMOYQaTivdHEmYwAKFjn6GKe/CqY0fNae93ZHTd20snh9ZLr8mTzIL9m0APQ1pjQg== -dotenv@6.2.0: +dotenv@6.2.0, dotenv@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w== @@ -6354,6 +6417,11 @@ emoji-regex@^6.5.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2" integrity sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ== +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -6701,6 +6769,11 @@ eventlistener@0.0.1: resolved "https://registry.yarnpkg.com/eventlistener/-/eventlistener-0.0.1.tgz#ed2baabb852227af2bcf889152c72c63ca532eb8" integrity sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg= +events@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + events@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" @@ -6921,6 +6994,11 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extract-files@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-5.0.1.tgz#c9492a8410be643e260a376f0151361993d5f659" + integrity sha512-qRW6y9eKF0VbCyOoOEtFhzJ3uykAw8GKwQVXyAIqwocyEWW4m+v+evec34RwtUkkxxHh7NKBLJ6AnXM8W4dH5w== + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -7048,6 +7126,11 @@ file-loader@2.0.0: loader-utils "^1.0.2" schema-utils "^1.0.0" +file-type@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-11.0.0.tgz#576ca9ec099925b0c4df7e75d3be52696b62fb52" + integrity sha512-ixd0mHkDO8KJ1S+ANTM+cZoZgL+TB0txLMm9KjTndfOjFYuRmrUcOtmSEm+e9s7wrynZOvvRD/8LwMQ6a24Irg== + file-uri-to-path@1: version "1.0.0" resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -7562,6 +7645,11 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-own-enumerable-property-symbols@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" @@ -8525,6 +8613,11 @@ identity-obj-proxy@3.0.0: dependencies: harmony-reflect "^1.4.6" +ieee754@1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + integrity sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q= + ieee754@^1.1.4: version "1.1.12" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" @@ -10147,6 +10240,11 @@ jest@24.8.0: import-local "^2.0.0" jest-cli "^24.8.0" +jmespath@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" + integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc= + joi@^11.1.1: version "11.4.0" resolved "https://registry.yarnpkg.com/joi/-/joi-11.4.0.tgz#f674897537b625e9ac3d0b7e1604c828ad913ccb" @@ -10171,18 +10269,18 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@^3.11.0, js-yaml@^3.12.0, js-yaml@^3.6.1, js-yaml@^3.7.0, js-yaml@^3.9.0: - version "3.12.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" - integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA== +js-yaml@^3.11.0, js-yaml@^3.13.0, js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== dependencies: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.13.0, js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== +js-yaml@^3.12.0, js-yaml@^3.6.1, js-yaml@^3.7.0, js-yaml@^3.9.0: + version "3.12.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" + integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -12694,7 +12792,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-locale@^3.0.0: +os-locale@^3.0.0, os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== @@ -13022,7 +13120,7 @@ parse-url@^5.0.0: parse-path "^4.0.0" protocols "^1.4.0" -parse5@4.0.0: +parse5@4.0.0, parse5@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== @@ -15635,6 +15733,11 @@ require-main-filename@^1.0.1: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -15895,6 +15998,11 @@ sass-loader@7.1.0: pify "^3.0.0" semver "^5.5.0" +sax@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" + integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= + sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -16651,6 +16759,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" @@ -16710,6 +16827,13 @@ strip-ansi@^5.0.0: dependencies: ansi-regex "^4.0.0" +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-bom@3.0.0, strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -17514,7 +17638,7 @@ typeorm-typedi-extensions@0.2.3: resolved "https://registry.yarnpkg.com/typeorm-typedi-extensions/-/typeorm-typedi-extensions-0.2.3.tgz#94fca2656206d771bf6d2242f5aab570511188e8" integrity sha512-T9i1NvRZNjPn9Jb8oT772ihfn6PwdqDVpzPCtKSqjkZGOgXrCkdyD3dDrzfMaoWJ1afU58bVx2CMb95FzT42Ow== -typeorm@0.2.13, typeorm@^0.2.11: +typeorm@0.2.13: version "0.2.13" resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.13.tgz#d6d49cd83aba5709134b99cdaca0b0f1b5002543" integrity sha512-SfRHZt6un1rCsTtHpBSgG5kh2jWznzrBex1Dfxbnji0nlrrNQ+ET4uxIhq3herk0TE0ETx3R+UjU0MGv8DB/3g== @@ -17534,6 +17658,26 @@ typeorm@0.2.13, typeorm@^0.2.11: yargonaut "^1.1.2" yargs "^12.0.5" +typeorm@^0.2.11: + version "0.2.17" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.17.tgz#eb98e9eeb2ce0dfc884620f49de0aeca3dc4e027" + integrity sha512-a2Yi6aG7qcSQNyYHjAZtRwhuMKt/ZPmNQg8PvpgF52Z3AgJ4LL4T5mtpfTzKgNzM4o4wP0JQcZNoGGlaRovKpw== + dependencies: + app-root-path "^2.0.1" + buffer "^5.1.0" + chalk "^2.4.2" + cli-highlight "^2.0.0" + debug "^4.1.1" + dotenv "^6.2.0" + glob "^7.1.2" + js-yaml "^3.13.1" + mkdirp "^0.5.1" + reflect-metadata "^0.1.13" + tslib "^1.9.0" + xml2js "^0.4.17" + yargonaut "^1.1.2" + yargs "^13.2.1" + typescript@3.2.x, typescript@3.3.1, typescript@^3.2.2: version "3.3.1" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.1.tgz#6de14e1db4b8a006ac535e482c8ba018c55f750b" @@ -17767,6 +17911,14 @@ url-template@^2.0.8: resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= +url@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" + integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -18396,6 +18548,15 @@ wrap-ansi@^3.0.1: string-width "^2.1.1" strip-ansi "^4.0.0" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrappy@1, wrappy@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -18479,7 +18640,7 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xml2js@^0.4.17: +xml2js@0.4.19, xml2js@^0.4.17: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== @@ -18569,6 +18730,14 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.0.tgz#7016b6dd03e28e1418a510e258be4bff5a31138f" + integrity sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" @@ -18655,6 +18824,23 @@ yargs@^12.0.1, yargs@^12.0.2, yargs@^12.0.4, yargs@^12.0.5: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" +yargs@^13.0.0, yargs@^13.2.1: + version "13.2.4" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" + integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.0" + yn@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/yn/-/yn-3.0.0.tgz#0073c6b56e92aed652fbdfd62431f2d6b9a7a091"