@things-factory/shell 8.0.0-beta.0 → 8.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +6 -6
  2. package/server/graphql-local-client.ts +0 -59
  3. package/server/index.ts +0 -13
  4. package/server/initializers/database.ts +0 -96
  5. package/server/initializers/naming-strategy.ts +0 -14
  6. package/server/middlewares/domain-middleware.ts +0 -60
  7. package/server/middlewares/index.ts +0 -43
  8. package/server/migrations/1000000000000-SeedDomain.ts +0 -37
  9. package/server/migrations/index.ts +0 -9
  10. package/server/pubsub-log-transport.ts +0 -59
  11. package/server/pubsub.ts +0 -84
  12. package/server/routers/domain-router.ts +0 -13
  13. package/server/routers/global-router.ts +0 -76
  14. package/server/routers/graphql-router.ts +0 -3
  15. package/server/routers/index.ts +0 -3
  16. package/server/schema.ts +0 -163
  17. package/server/server-dev.ts +0 -305
  18. package/server/server.ts +0 -296
  19. package/server/service/attribute-set/attribute-set-item-type.ts +0 -65
  20. package/server/service/attribute-set/attribute-set-mutation.ts +0 -125
  21. package/server/service/attribute-set/attribute-set-query.ts +0 -36
  22. package/server/service/attribute-set/attribute-set-type.ts +0 -46
  23. package/server/service/attribute-set/attribute-set.ts +0 -35
  24. package/server/service/attribute-set/index.ts +0 -6
  25. package/server/service/common-types/index.ts +0 -6
  26. package/server/service/common-types/list-param.ts +0 -61
  27. package/server/service/common-types/log.ts +0 -17
  28. package/server/service/common-types/object-ref.ts +0 -13
  29. package/server/service/common-types/scalar-any.ts +0 -44
  30. package/server/service/common-types/scalar-date.ts +0 -22
  31. package/server/service/common-types/scalar-object.ts +0 -15
  32. package/server/service/directive-transaction/index.ts +0 -1
  33. package/server/service/directive-transaction/transaction.ts +0 -40
  34. package/server/service/domain/domain-mutation.ts +0 -120
  35. package/server/service/domain/domain-query.ts +0 -48
  36. package/server/service/domain/domain-types.ts +0 -63
  37. package/server/service/domain/domain.ts +0 -147
  38. package/server/service/domain/index.ts +0 -6
  39. package/server/service/index.ts +0 -32
  40. package/server/service/subscription-data/data-resolver.ts +0 -37
  41. package/server/service/subscription-data/data-types.ts +0 -16
  42. package/server/service/subscription-data/index.ts +0 -4
  43. package/server/typeorm/encrypt-transform.ts +0 -70
  44. package/server/typeorm/get-data-encryption-key.ts +0 -13
  45. package/server/typeorm/json5-transform.ts +0 -26
  46. package/server/typeorm/round-transform.ts +0 -20
  47. package/server/utils/condition-builder.ts +0 -145
  48. package/server/utils/get-domain.ts +0 -226
  49. package/server/utils/get-query-builder-from-list-params.ts +0 -469
  50. package/server/utils/get-times-for-period.ts +0 -60
  51. package/server/utils/index.ts +0 -8
  52. package/server/utils/list-param-adjuster.ts +0 -21
  53. package/server/utils/list-params-converter.ts +0 -200
  54. package/server/utils/list-query-builder.ts +0 -120
  55. package/server/utils/publish-progress.ts +0 -23
@@ -1,13 +0,0 @@
1
- import { InputType, Field, ID } from 'type-graphql'
2
-
3
- @InputType()
4
- export class ObjectRef {
5
- @Field(() => ID, { description: 'Field id' })
6
- id: string
7
-
8
- @Field({ nullable: true, description: 'Field name' })
9
- name?: string
10
-
11
- @Field({ nullable: true, description: 'Field description' })
12
- description?: string
13
- }
@@ -1,44 +0,0 @@
1
- import { GraphQLScalarType, Kind } from 'graphql'
2
-
3
- function parseObject(ast) {
4
- const value = Object.create(null)
5
- ast.fields.forEach(field => {
6
- value[field.name.value] = parseAst(field.value)
7
- })
8
- return value
9
- }
10
-
11
- function parseAst(ast) {
12
- switch (ast.kind) {
13
- case Kind.INT:
14
- return parseInt(ast.value)
15
- case Kind.FLOAT:
16
- return parseFloat(ast.value)
17
- case Kind.BOOLEAN:
18
- return ast.value
19
- case Kind.STRING:
20
- return ast.value
21
- case Kind.LIST:
22
- return ast.values.map(parseAst)
23
- case Kind.OBJECT:
24
- return parseObject(ast)
25
- default:
26
- return null
27
- }
28
- }
29
-
30
- export const ScalarAny = new GraphQLScalarType({
31
- name: 'Any',
32
- description: 'Any Scalar type (String, Boolean, Int, Float, Object, List)',
33
- serialize(value) {
34
- // Implement your own behavior here by setting the 'result' variable
35
- return value
36
- },
37
- parseValue(value) {
38
- // Implement your own behavior here by setting the 'result' variable
39
- return value
40
- },
41
- parseLiteral(ast) {
42
- return parseAst(ast)
43
- }
44
- })
@@ -1,22 +0,0 @@
1
- import { GraphQLScalarType, Kind } from 'graphql'
2
-
3
- export const ScalarDate = new GraphQLScalarType({
4
- name: 'Date',
5
- description: 'Date custom scalar type',
6
- parseValue(value) {
7
- return new Date(value as string | number) // value from the client
8
- },
9
- serialize(value) {
10
- /**
11
- * Note: Allow value to be date only like "2021-01-31" to be serialize before passing data to clientside for TypeGraphql.
12
- * Usage: When database column datatype is "date" and data do not contain any time component.
13
- */
14
- return new Date(value as any).getTime() // value sent to the client
15
- },
16
- parseLiteral(ast) {
17
- if (ast.kind === Kind.INT) {
18
- return new Date(+ast.value) // ast value is always in string format
19
- }
20
- return null
21
- }
22
- })
@@ -1,15 +0,0 @@
1
- const { GraphQLScalarType } = require('graphql')
2
-
3
- export const ScalarObject = new GraphQLScalarType({
4
- name: 'Object',
5
- description: 'Can be anything',
6
- parseValue(value) {
7
- return value
8
- },
9
- serialize(value) {
10
- return value
11
- },
12
- parseLiteral(ast) {
13
- return ast
14
- }
15
- })
@@ -1 +0,0 @@
1
- export * from './transaction'
@@ -1,40 +0,0 @@
1
- import { defaultFieldResolver, GraphQLSchema } from 'graphql'
2
- import gql from 'graphql-tag'
3
-
4
- import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
5
-
6
- import { getDataSource } from '../../initializers/database'
7
-
8
- const DIRECTIVE = 'transaction'
9
-
10
- export const transactionDirectiveTypeDefs = gql`
11
- directive @${DIRECTIVE} on FIELD_DEFINITION
12
- `
13
- export const transactionDirectiveResolver = (schema: GraphQLSchema) =>
14
- mapSchema(schema, {
15
- [MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName) => {
16
- const transactionDirective = getDirective(schema, fieldConfig, DIRECTIVE)?.[0]
17
- if (transactionDirective) {
18
- const { resolve = defaultFieldResolver } = fieldConfig
19
-
20
- fieldConfig.resolve = async function (source, args, context, info) {
21
- return await getDataSource('tx').transaction(async tx => {
22
- /* local-graphql-client로부터 invoke인 경우에는 context.req, context.res 가 없으므로, 빈 오브젝트로 대체해준다. */
23
- let wrap = context.app.createContext(context.req || {}, context.res || {})
24
-
25
- wrap.state = {
26
- ...context.state,
27
- tx
28
- }
29
- wrap.t = context.t
30
-
31
- let result = await resolve.call(this, source, args, wrap, info)
32
-
33
- return result
34
- })
35
- }
36
-
37
- return fieldConfig
38
- }
39
- }
40
- })
@@ -1,120 +0,0 @@
1
- import { Arg, Args, Ctx, Directive, Mutation, Query, Resolver, Root } from 'type-graphql'
2
- import { In, Repository } from 'typeorm'
3
-
4
- import { slugger } from '@things-factory/utils'
5
-
6
- import { getRepository } from '../../initializers/database'
7
-
8
- import { Domain, IPList } from './domain'
9
- import { DomainPatch } from './domain-types'
10
- import { ScalarObject } from '../common-types'
11
-
12
- @Resolver(Domain)
13
- export class DomainMutation {
14
- @Directive('@transaction')
15
- @Directive('@privilege(superUserGranted: true)')
16
- @Mutation(returns => Domain, { description: 'To create domain (Only superuser is granted this privilege.)' })
17
- async createDomain(@Arg('domainInput') domainInput: DomainPatch) {
18
- const { name, description } = domainInput
19
- const domainRepo: Repository<Domain> = getRepository(Domain)
20
- const subdomain: string = slugger(name)
21
-
22
- const domain: Domain = await domainRepo.findOneBy({ subdomain })
23
- if (domain) {
24
- throw new Error('domain is duplicated')
25
- }
26
-
27
- return await domainRepo.save({ name, description, subdomain })
28
- }
29
-
30
- @Directive('@transaction')
31
- @Directive('@privilege(superUserGranted: true)')
32
- @Mutation(returns => Domain, { description: 'To delete domain (Only superuser is granted this privilege.)' })
33
- async deleteDomain(@Arg('name') name: string) {
34
- return await getRepository(Domain).delete({ name })
35
- }
36
-
37
- @Directive('@transaction')
38
- @Directive('@privilege(superUserGranted: true)')
39
- @Mutation(returns => Boolean, {
40
- description: 'To delete multiple domains (Only superuser is granted this privilege.)'
41
- })
42
- async deleteDomains(@Arg('names', () => [String]) names: string[]) {
43
- const domains: Domain[] = await getRepository(Domain).find({ where: { name: In(names) } })
44
- const domainIds: string[] = domains.map(domain => domain.id)
45
-
46
- await getRepository(Domain).delete({ id: In(domainIds) })
47
- }
48
-
49
- @Directive('@transaction')
50
- @Directive('@privilege(superUserGranted: true)')
51
- @Mutation(returns => Domain, {
52
- description: 'To update domain (Only superuser is granted this privilege.)'
53
- })
54
- async updateDomain(@Arg('name') name: string, @Arg('patch', () => DomainPatch) patch: DomainPatch) {
55
- const repository = getRepository(Domain)
56
- const domain: Domain = await repository.findOneBy({ name })
57
-
58
- if (patch.parent && patch.parent.id == domain.id) {
59
- delete patch.parent
60
- }
61
-
62
- return await repository.save({
63
- ...domain,
64
- ...patch
65
- } as any)
66
- }
67
-
68
- @Directive('@transaction')
69
- @Directive('@privilege(superUserGranted: true)')
70
- @Mutation(returns => Boolean, {
71
- description: 'To update multiple domains (Only superuser is granted this privilege.)'
72
- })
73
- async updateDomains(@Arg('patches', () => [DomainPatch]) patches: DomainPatch[]): Promise<boolean> {
74
- const domainRepo: Repository<Domain> = getRepository(Domain)
75
-
76
- const patchIds = patches.filter((patch: any) => patch.id)
77
-
78
- if (patchIds.length > 0) {
79
- patchIds.forEach(async updateRecord => {
80
- const domain: Domain = await domainRepo.findOne({ where: { id: updateRecord.id } })
81
-
82
- if (updateRecord.name) {
83
- updateRecord.subdomain = slugger(updateRecord.name)
84
- }
85
-
86
- if (updateRecord.parent && updateRecord.parent.id == domain.id) {
87
- delete updateRecord.parent
88
- }
89
-
90
- await domainRepo.save({
91
- ...domain,
92
- ...updateRecord
93
- } as any)
94
- })
95
- }
96
-
97
- return true
98
- }
99
-
100
- @Directive('@transaction')
101
- @Directive(
102
- '@privilege(category: "security", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'
103
- )
104
- @Mutation(returns => ScalarObject, { nullable: true, description: 'To update secure IP list for domain' })
105
- async updateSecureIPList(
106
- @Arg('iplist', type => ScalarObject) iplist: IPList,
107
- @Ctx() context: any
108
- ): Promise<IPList | null> {
109
- const { domain } = context.state
110
- const repository = getRepository(Domain)
111
- // const domain: Domain = await repository.findOneBy({ id })
112
-
113
- const { iplist: result } = await repository.save({
114
- ...domain,
115
- iplist
116
- } as any)
117
-
118
- return result
119
- }
120
- }
@@ -1,48 +0,0 @@
1
- import { Arg, Args, Ctx, Directive, Mutation, Query, Resolver, FieldResolver, Root } from 'type-graphql'
2
- import { In, Repository } from 'typeorm'
3
-
4
- import { getRepository } from '../../initializers/database'
5
- import { getQueryBuilderFromListParams } from '../../utils/get-query-builder-from-list-params'
6
-
7
- import { ListParam } from '../common-types/list-param'
8
- import { Domain, IPList } from './domain'
9
- import { DomainList } from './domain-types'
10
- import { ScalarObject } from '../common-types'
11
-
12
- @Resolver(Domain)
13
- export class DomainQuery {
14
- @Directive('@privilege(superUserGranted: true)')
15
- @Query(returns => Domain, { description: 'To fetch domain' })
16
- async domain(@Arg('id') id: string, @Ctx() context: any): Promise<Domain> {
17
- const repository = getRepository(Domain)
18
-
19
- return await repository.findOneBy({ id })
20
- }
21
-
22
- @Directive('@privilege(superUserGranted: true)')
23
- @Query(returns => DomainList, { description: 'To fetch all domains (Only superuser is granted this privilege.)' })
24
- async domains(@Args(type => ListParam) params: ListParam, @Ctx() context: any): Promise<DomainList> {
25
- const queryBuilder = await getQueryBuilderFromListParams({
26
- repository: getRepository(Domain),
27
- alias: 'ContactPoint',
28
- params,
29
- searchables: ['name', 'description', 'subdomain']
30
- })
31
-
32
- const [items, total] = await queryBuilder.getManyAndCount()
33
-
34
- return { items, total }
35
- }
36
-
37
- @Directive('@privilege(category: "security", privilege: "query", domainOwnerGranted: true, superUserGranted: true)')
38
- @Query(returns => ScalarObject, { nullable: true, description: 'To fetch domain' })
39
- async secureIPList(@Ctx() context: any): Promise<IPList | null> {
40
- const { domain } = context.state
41
- return domain.iplist
42
- }
43
-
44
- @FieldResolver(type => Domain)
45
- async parent(@Root() domain: Domain): Promise<Domain> {
46
- return domain.parentId && (await getRepository(Domain).findOneBy({ id: domain.parentId }))
47
- }
48
- }
@@ -1,63 +0,0 @@
1
- import { ObjectType, InputType, Field, Int } from 'type-graphql'
2
- import { Domain, IPList } from './domain'
3
- import { ObjectRef, ScalarObject } from '../common-types'
4
-
5
- @InputType()
6
- export class DomainInput {
7
- @Field()
8
- name: string
9
-
10
- @Field({ nullable: true })
11
- description?: string
12
- }
13
-
14
- @InputType()
15
- export class DomainPatch {
16
- @Field({ nullable: true })
17
- id?: string
18
-
19
- @Field({ nullable: true })
20
- name?: string
21
-
22
- @Field({ nullable: true })
23
- description?: string
24
-
25
- @Field({ nullable: true })
26
- timezone?: string
27
-
28
- @Field({ nullable: true })
29
- systemFlag?: Boolean
30
-
31
- @Field({ nullable: true })
32
- subdomain?: string
33
-
34
- @Field({ nullable: true })
35
- owner?: string
36
-
37
- @Field(type => ObjectRef, { nullable: true })
38
- parent?: ObjectRef
39
-
40
- @Field({ nullable: true })
41
- brandName?: string
42
-
43
- @Field({ nullable: true })
44
- brandImage?: string
45
-
46
- @Field({ nullable: true })
47
- contentImage?: string
48
-
49
- @Field(type => ScalarObject, { nullable: true })
50
- attributes?: any
51
-
52
- @Field({ nullable: true })
53
- theme?: string
54
- }
55
-
56
- @ObjectType()
57
- export class DomainList {
58
- @Field(type => [Domain], { nullable: true })
59
- items: Domain[]
60
-
61
- @Field(type => Int, { nullable: true })
62
- total: number
63
- }
@@ -1,147 +0,0 @@
1
- import {
2
- Column,
3
- CreateDateColumn,
4
- ManyToOne,
5
- OneToMany,
6
- RelationId,
7
- Entity,
8
- Index,
9
- UpdateDateColumn,
10
- DeleteDateColumn
11
- } from 'typeorm'
12
- import { ObjectType, Directive, Field, ID } from 'type-graphql'
13
- import { config } from '@things-factory/env'
14
- import { ScalarObject } from '../common-types'
15
-
16
- const numericTypes = ['int', 'int2', 'int4', 'int8', 'integer', 'tinyint', 'smallint', 'mediumint', 'bigint']
17
- const generatedStrategy = ['uuid', 'rowid', 'increment', 'identity']
18
- const domainPrimaryOption = config.get('domainPrimaryOption')
19
- const domainPrimaryType = domainPrimaryOption?.type
20
- const domainPrimaryStrategy = domainPrimaryOption?.strategy
21
-
22
- export type IPList = {
23
- whitelist?: string[]
24
- blacklist?: string[]
25
- protectedlist?: string[]
26
- privileges?: {
27
- category: string
28
- privilege: string
29
- }[]
30
- }
31
-
32
- @Entity()
33
- @Index('ix_domain_0', (domain: Domain) => [domain.subdomain, domain.deletedAt], {
34
- unique: true,
35
- where: '"deleted_at" IS NULL'
36
- })
37
- @ObjectType()
38
- export class Domain {
39
- @Field(type => ID)
40
- @Column(
41
- domainPrimaryOption
42
- ? {
43
- type: domainPrimaryType,
44
- primary: true,
45
- transformer: {
46
- //from(value: DatabaseType): EntityType
47
- from: value => {
48
- return value
49
- },
50
- //to(value: EntityType): DatabaseType
51
- to: value => {
52
- if (!value) {
53
- value = 0
54
- }
55
- if (numericTypes.indexOf(domainPrimaryType) >= 0) {
56
- return parseInt(value)
57
- } else {
58
- return value
59
- }
60
- }
61
- },
62
- generated: generatedStrategy.indexOf(domainPrimaryStrategy) >= 0 ? domainPrimaryStrategy : false
63
- }
64
- : {
65
- type: 'uuid',
66
- primary: true,
67
- generated: 'uuid'
68
- }
69
- )
70
- readonly id: string
71
-
72
- @Field()
73
- @Column({ unique: true })
74
- name: string
75
-
76
- @Field({ nullable: true })
77
- @Column({ nullable: true })
78
- description: string
79
-
80
- @Field({ nullable: true })
81
- @Column({ nullable: true })
82
- extType: string
83
-
84
- @Field({ nullable: true })
85
- @Column({ nullable: true })
86
- timezone: string
87
-
88
- @Directive('@deprecated(reason: "Use `parent`")')
89
- @Field({ nullable: true })
90
- @Column({ default: false })
91
- systemFlag: boolean
92
-
93
- @Field({ nullable: true })
94
- @Column({ nullable: true })
95
- subdomain: string
96
-
97
- @Field({ nullable: true })
98
- @ManyToOne(type => Domain, { nullable: true })
99
- parent: Domain
100
-
101
- @RelationId((domain: Domain) => domain.parent)
102
- parentId?: string
103
-
104
- @OneToMany(type => Domain, domain => domain.parent)
105
- @Field(type => Domain, { nullable: true })
106
- children: Domain[]
107
-
108
- @Field({ nullable: true })
109
- @Column({ nullable: true })
110
- brandName: string
111
-
112
- @Field({ nullable: true })
113
- @Column({ nullable: true })
114
- brandImage: string
115
-
116
- @Field({ nullable: true })
117
- @Column({ nullable: true })
118
- contentImage: string
119
-
120
- @Field({ nullable: true })
121
- @Column({ nullable: true })
122
- owner: string
123
-
124
- @Field({ nullable: true })
125
- @Column({ nullable: true })
126
- theme: string
127
-
128
- @Column('simple-json', { nullable: true })
129
- @Field(type => ScalarObject, { nullable: true })
130
- iplist?: IPList
131
-
132
- @Column('simple-json', { nullable: true })
133
- @Field(type => ScalarObject, { nullable: true })
134
- attributes?: any
135
-
136
- @Field({ nullable: true })
137
- @CreateDateColumn()
138
- createdAt: Date
139
-
140
- @Field({ nullable: true })
141
- @UpdateDateColumn()
142
- updatedAt: Date
143
-
144
- @DeleteDateColumn()
145
- @Field({ nullable: true })
146
- deletedAt?: Date
147
- }
@@ -1,6 +0,0 @@
1
- import { Domain } from './domain'
2
- import { DomainQuery } from './domain-query'
3
- import { DomainMutation } from './domain-mutation'
4
-
5
- export const entities = [Domain]
6
- export const resolvers = [DomainQuery, DomainMutation]
@@ -1,32 +0,0 @@
1
- import { transactionDirectiveResolver, transactionDirectiveTypeDefs } from './directive-transaction'
2
- import { entities as DomainEntities, resolvers as DomainResolvers } from './domain'
3
- import { entities as AttributeEntities, resolvers as AttributeResolvers } from './attribute-set'
4
- import { resolvers as SubscriptionDataResolvers } from './subscription-data'
5
-
6
- export * from './common-types'
7
- export * from './domain/domain'
8
- export * from './domain/domain'
9
-
10
- /* EXPORT TYPES */
11
- export * from './domain/domain-types'
12
- export * from './subscription-data/data-types'
13
-
14
- export const entities = [
15
- /* Entities */
16
- ...AttributeEntities,
17
- ...DomainEntities
18
- ]
19
- export const schema = {
20
- typeDefs: {
21
- transactionDirectiveTypeDefs
22
- },
23
- resolverClasses: [
24
- /* Resolvers */
25
- ...AttributeResolvers,
26
- ...DomainResolvers,
27
- ...SubscriptionDataResolvers
28
- ],
29
- directives: {
30
- transaction: transactionDirectiveResolver
31
- }
32
- }
@@ -1,37 +0,0 @@
1
- import { filter, pipe } from 'graphql-yoga'
2
- import { Arg, Resolver, Root, Subscription } from 'type-graphql'
3
-
4
- import { pubsub } from '../../pubsub'
5
- import { Data } from './data-types'
6
-
7
- /* 이 Resolver는 @things-factory/integration-base 에서 Overide 된다. (state-register를 사용하기 위해서) */
8
- @Resolver()
9
- export class DataResolver {
10
- @Subscription({
11
- subscribe: ({ args, context, info }) => {
12
- const { domain, user } = context.state
13
- const { tag } = args
14
- const subdomain = domain?.subdomain
15
-
16
- if (!domain || !tag) {
17
- throw new Error('domain and tag required')
18
- }
19
-
20
- //@ts-ignore
21
- if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
22
- throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
23
- }
24
-
25
- return pipe(
26
- pubsub.subscribe('data'),
27
- filter((payload: { data: Data }) => {
28
- const { domain: pdomain, tag: ptag, data } = payload.data
29
- return tag === ptag && subdomain === pdomain?.subdomain
30
- })
31
- )
32
- }
33
- })
34
- data(@Root() payload: { data: Data }, @Arg('tag') tag: string): Data {
35
- return payload.data
36
- }
37
- }
@@ -1,16 +0,0 @@
1
- import { Field, ObjectType } from 'type-graphql'
2
-
3
- import { ScalarObject } from '../common-types/scalar-object'
4
- import { Domain } from '../domain/domain'
5
-
6
- @ObjectType()
7
- export class Data {
8
- @Field(type => Domain, { nullable: true, description: 'The domain where the data originated' })
9
- domain?: Domain
10
-
11
- @Field({ description: 'Tag name attached to data' })
12
- tag: string
13
-
14
- @Field(type => ScalarObject, { nullable: true, description: 'Data delivered by subscription' })
15
- data?: Object
16
- }
@@ -1,4 +0,0 @@
1
- import { DataResolver } from './data-resolver'
2
-
3
- export const entities = []
4
- export const resolvers = [DataResolver]