@typetron/framework 0.5.3 → 0.5.4

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 (195) hide show
  1. package/.eslintrc-old.js +208 -0
  2. package/Cache/Cache.ts +13 -0
  3. package/Cache/Stores/DatabaseStore.ts +120 -0
  4. package/Cache/Stores/FileStore.ts +69 -0
  5. package/Cache/Stores/MemoryStore.ts +71 -0
  6. package/Cache/index.ts +5 -0
  7. package/Cache/types.ts +4 -0
  8. package/Container/ClassResolver.ts +106 -0
  9. package/Container/Container.ts +144 -0
  10. package/Container/Contracts.ts +3 -0
  11. package/Container/Decorators.ts +20 -0
  12. package/Container/Metadata.ts +16 -0
  13. package/Container/Resolver.ts +27 -0
  14. package/Container/index.ts +5 -0
  15. package/Database/Clauses/Where.ts +0 -0
  16. package/Database/Connection.ts +52 -0
  17. package/Database/Decorators.ts +142 -0
  18. package/Database/Drivers/DatabaseDriver.ts +37 -0
  19. package/Database/Drivers/MySQL/Alter/index.ts +55 -0
  20. package/Database/Drivers/MySQL/ColumnDefinition.ts +16 -0
  21. package/Database/Drivers/MySQL/Create.ts +47 -0
  22. package/Database/Drivers/MySQL/MysqlDriver.ts +123 -0
  23. package/Database/Drivers/MySQL/Schema.ts +82 -0
  24. package/Database/Drivers/MySQL/index.ts +13 -0
  25. package/Database/Drivers/SQL/Schema.ts +73 -0
  26. package/Database/Drivers/SQL/Statements/Alter.ts +22 -0
  27. package/Database/Drivers/SQL/Statements/BaseStatement.ts +55 -0
  28. package/Database/Drivers/SQL/Statements/Delete.ts +20 -0
  29. package/Database/Drivers/SQL/Statements/Insert.ts +24 -0
  30. package/Database/Drivers/SQL/Statements/Select.ts +55 -0
  31. package/Database/Drivers/SQL/Statements/Update.ts +33 -0
  32. package/Database/Drivers/SQL/index.ts +8 -0
  33. package/Database/Drivers/SQLite/Create.ts +45 -0
  34. package/Database/Drivers/SQLite/Schema.ts +54 -0
  35. package/Database/Drivers/SQLite/SqliteDriver.ts +144 -0
  36. package/Database/Drivers/SQLite/index.ts +15 -0
  37. package/Database/Drivers/SchemaContract.ts +11 -0
  38. package/Database/Drivers/Statement.ts +16 -0
  39. package/Database/Drivers/index.ts +4 -0
  40. package/Database/Entity.ts +377 -0
  41. package/Database/EntityNotFoundError.ts +5 -0
  42. package/Database/EntityProxyHandler.ts +43 -0
  43. package/Database/EntityQuery.ts +197 -0
  44. package/Database/Expression.ts +3 -0
  45. package/Database/Fields.ts +816 -0
  46. package/Database/Helpers.ts +12 -0
  47. package/Database/List.ts +71 -0
  48. package/Database/Migrations/Migration.ts +10 -0
  49. package/Database/Migrations/MigrationHistory.ts +20 -0
  50. package/Database/Migrations/Migrator.ts +122 -0
  51. package/Database/Migrations/index.ts +3 -0
  52. package/Database/ORM/BaseRelationship.ts +10 -0
  53. package/Database/Query.ts +374 -0
  54. package/Database/Seeders/Seeder.ts +3 -0
  55. package/Database/Seeders/SeederManager.ts +27 -0
  56. package/Database/Seeders/index.ts +2 -0
  57. package/Database/StringExpression.ts +9 -0
  58. package/Database/Types.ts +165 -0
  59. package/Database/index.ts +23 -0
  60. package/Encryption/index.ts +51 -0
  61. package/Forms/Decorators.ts +29 -0
  62. package/Forms/Form.ts +70 -0
  63. package/Forms/FormFields.ts +36 -0
  64. package/Forms/index.ts +3 -0
  65. package/Framework/App.ts +10 -0
  66. package/Framework/Application.ts +118 -0
  67. package/Framework/Auth/Auth.ts +122 -0
  68. package/Framework/Auth/Authenticatable.ts +9 -0
  69. package/Framework/Auth/User.ts +27 -0
  70. package/Framework/Auth/index.ts +29 -0
  71. package/Framework/Config/AppConfig.ts +25 -0
  72. package/Framework/Config/AuthConfig.ts +9 -0
  73. package/Framework/Config/BaseConfig.ts +9 -0
  74. package/Framework/Config/CacheConfig.ts +38 -0
  75. package/Framework/Config/DatabaseConfig.ts +21 -0
  76. package/Framework/Config/MailConfig.ts +30 -0
  77. package/Framework/Config/index.ts +6 -0
  78. package/Framework/Middleware/AuthMiddleware.ts +31 -0
  79. package/Framework/Middleware/CorsMiddleware.ts +32 -0
  80. package/Framework/Middleware/StaticAssetsMiddleware.ts +76 -0
  81. package/Framework/Middleware/index.ts +2 -0
  82. package/Framework/Provider.ts +9 -0
  83. package/Framework/Providers/CacheProvider.ts +28 -0
  84. package/Framework/Providers/DatabaseProvider.ts +36 -0
  85. package/Framework/Providers/MailProvider.ts +31 -0
  86. package/Framework/Providers/WebsocketsProvider.ts +120 -0
  87. package/Framework/Resolvers/AuthResolver.ts +23 -0
  88. package/Framework/Resolvers/EntityResolver.ts +41 -0
  89. package/Framework/Resolvers/FormResolver.ts +37 -0
  90. package/Framework/RootDir.ts +1 -0
  91. package/Framework/index.ts +8 -0
  92. package/Frontend/Angular/index.ts +24 -0
  93. package/Frontend/Websockets/index.ts +86 -0
  94. package/Mail/MailAddress.ts +4 -0
  95. package/Mail/MailTransport.ts +6 -0
  96. package/Mail/Mailable.ts +16 -0
  97. package/Mail/Mailer.ts +27 -0
  98. package/Mail/PendingMail.ts +68 -0
  99. package/Mail/SentMessage.ts +20 -0
  100. package/Mail/Transports/MemoryTransport.ts +13 -0
  101. package/Mail/Transports/SendGridTransport.ts +95 -0
  102. package/Mail/index.ts +3 -0
  103. package/Models/Model.ts +41 -0
  104. package/Models/index.ts +54 -0
  105. package/Router/BaseController.ts +7 -0
  106. package/Router/Decorators.ts +224 -0
  107. package/Router/Guard.ts +10 -0
  108. package/Router/Http/Contracts.ts +4 -0
  109. package/Router/Http/ErrorHandler.ts +45 -0
  110. package/Router/Http/ErrorHandlerInterface.ts +6 -0
  111. package/Router/Http/Errors/HttpError.ts +15 -0
  112. package/Router/Http/Handler.ts +183 -0
  113. package/Router/Http/HttpRoute.ts +110 -0
  114. package/Router/Http/Middleware.ts +7 -0
  115. package/Router/Http/Request.ts +225 -0
  116. package/Router/Http/Response.ts +35 -0
  117. package/Router/Http/index.ts +85 -0
  118. package/Router/Metadata.ts +34 -0
  119. package/Router/Middleware.ts +16 -0
  120. package/Router/Request.ts +65 -0
  121. package/Router/Route.ts +16 -0
  122. package/Router/RouteNotFoundError.ts +5 -0
  123. package/Router/Router.ts +35 -0
  124. package/Router/Servers/index.ts +6 -0
  125. package/Router/Servers/node.ts +49 -0
  126. package/Router/Servers/uNetworking.ts +151 -0
  127. package/Router/Websockets/Handler.ts +82 -0
  128. package/Router/Websockets/Middleware.ts +7 -0
  129. package/Router/Websockets/Request.ts +3 -0
  130. package/Router/Websockets/WebsocketRoute.ts +61 -0
  131. package/Router/Websockets/index.ts +57 -0
  132. package/Router/Websockets/types.ts +23 -0
  133. package/Router/index.ts +6 -0
  134. package/Storage/File.ts +30 -0
  135. package/Storage/Image.ts +19 -0
  136. package/Storage/InvalidImage.ts +3 -0
  137. package/Storage/Storage.ts +98 -0
  138. package/Storage/index.ts +4 -0
  139. package/Storage/utils.ts +18 -0
  140. package/Support/Array.ts +184 -0
  141. package/Support/Math.ts +12 -0
  142. package/Support/Metadata.ts +31 -0
  143. package/Support/String.ts +38 -0
  144. package/Support/index.ts +19 -0
  145. package/Support/utils.ts +7 -0
  146. package/Testing/TestCase.ts +193 -0
  147. package/Validation/Rule.ts +9 -0
  148. package/Validation/RuleInterface.ts +10 -0
  149. package/Validation/Rules/Email.ts +20 -0
  150. package/Validation/Rules/FileExtension.ts +21 -0
  151. package/Validation/Rules/MaxLength.ts +17 -0
  152. package/Validation/Rules/MinLength.ts +18 -0
  153. package/Validation/Rules/Optional.ts +18 -0
  154. package/Validation/Rules/Required.ts +29 -0
  155. package/Validation/Validator.ts +7 -0
  156. package/Validation/index.ts +12 -0
  157. package/benchmark-index.js +20 -0
  158. package/benchmark.ts +47 -0
  159. package/package.json +7 -3
  160. package/tests/Cache/DatabaseStoreTest.ts +110 -0
  161. package/tests/Cache/FileStoreTest.ts +93 -0
  162. package/tests/Cache/MemoryStoreTest.ts +92 -0
  163. package/tests/Container/ContainerTest.ts +336 -0
  164. package/tests/Database/Drivers/MySQL/AlterTest.ts +100 -0
  165. package/tests/Database/Drivers/MySQL/CreateTest.ts +39 -0
  166. package/tests/Database/Drivers/MysqlDriverTest.ts +140 -0
  167. package/tests/Database/Drivers/SqliteDriverTest.ts +126 -0
  168. package/tests/Database/Entities/Article.ts +21 -0
  169. package/tests/Database/Entities/Profile.ts +21 -0
  170. package/tests/Database/Entities/Role.ts +15 -0
  171. package/tests/Database/Entities/User.ts +35 -0
  172. package/tests/Database/EntityRelationshipsTest.ts +475 -0
  173. package/tests/Database/EntityTest.ts +202 -0
  174. package/tests/Database/Migrations/RunnerTest.ts +96 -0
  175. package/tests/Database/Migrations/migrations/1.createUserTable.ts +12 -0
  176. package/tests/Database/Migrations/migrations/2.createArticlesTable.ts +12 -0
  177. package/tests/Database/QueryTest.ts +573 -0
  178. package/tests/Database/SchemaTest.ts +32 -0
  179. package/tests/Database/Seeders/RunnerTest.ts +30 -0
  180. package/tests/Database/Seeders/seeders/RandomSeeder.ts +10 -0
  181. package/tests/Database/utils.ts +16 -0
  182. package/tests/Forms/FormsTest.ts +59 -0
  183. package/tests/Framework/Middleware/StaticAssetsMiddlewareTest.ts +129 -0
  184. package/tests/Framework/Resolvers/EntityResolverTest.ts +48 -0
  185. package/tests/Framework/Router/RouterTest.ts +33 -0
  186. package/tests/Mail/MailerTest.ts +76 -0
  187. package/tests/Model/ModelTest.ts +183 -0
  188. package/tests/Router/HttpHandlerTest.ts +72 -0
  189. package/tests/Router/RequestTest.ts +77 -0
  190. package/tests/Router/WebSocketsHandlerTest.ts +51 -0
  191. package/tests/Storage/StorageTest.ts +97 -0
  192. package/tests/Support/ArrayTest.ts +167 -0
  193. package/tests/Support/StringTest.ts +18 -0
  194. package/tests/Validation/RulesTest.ts +54 -0
  195. package/types.d.ts +8 -0
@@ -0,0 +1,24 @@
1
+ import type { AbstractControl, ValidatorFn } from '@angular/forms'
2
+ import { FormControl, FormGroup } from '@angular/forms'
3
+ import type { Form, FormField } from '@Typetron/Forms'
4
+ import { Constructor } from '@Typetron/Support'
5
+
6
+ export class FormBuilder {
7
+ static build<T extends Form>(form: typeof Form & Constructor<T>): FormGroup {
8
+ const controls: Record<string, AbstractControl> = {}
9
+ const formFields = Object.values(form.fields()) as FormField[]
10
+ const instance = new (form as unknown as Constructor<T>)()
11
+ Object.values(formFields).forEach(field => {
12
+ controls[field.name] = new FormControl(
13
+ instance[field.name as keyof Form],
14
+ {validators: this.getValidators(field)}
15
+ )
16
+ })
17
+ return new FormGroup(controls)
18
+ }
19
+
20
+ private static getValidators(field: FormField): ValidatorFn {
21
+ return control => field.validate(control.value) as unknown as ValidatorFn
22
+ }
23
+ }
24
+
@@ -0,0 +1,86 @@
1
+ import { Observable, of, ReplaySubject, Subject, throwError } from 'rxjs'
2
+ import { filter, map, switchMap, take } from 'rxjs/operators'
3
+ import { ActionErrorResponse, ActionRequest, ActionResponse, WebsocketMessageStatus } from '@typetron/framework/Router/Websockets/types'
4
+
5
+ export class Websocket {
6
+ socket?: WebSocket
7
+
8
+ actionMessages$ = new Subject<ActionResponse<unknown>>()
9
+ queuedActions$ = new ReplaySubject<ActionRequest>()
10
+ errors$ = new Subject<ActionErrorResponse>()
11
+ onConnectCallback: () => void
12
+
13
+ constructor(public url: string, public protocols?: string | string[]) {
14
+ this.connect(url, protocols)
15
+ }
16
+
17
+ get isConnected() {
18
+ return this.socket?.readyState === WebSocket.OPEN
19
+ }
20
+
21
+ connect(url?: string, protocols?: string | string[]): void {
22
+ const socket = new WebSocket(url ?? this.url, protocols ?? this.protocols)
23
+ this.socket = socket
24
+
25
+ socket.onmessage = (action) => {
26
+ const message = JSON.parse(action.data)
27
+ this.actionMessages$.next(message)
28
+ }
29
+ socket.onopen = () => {
30
+ this.onConnectCallback?.()
31
+ this.queuedActions$.subscribe(message => {
32
+ socket.send(JSON.stringify(message))
33
+ })
34
+ }
35
+
36
+ socket.onclose = (action) => {
37
+ this.queuedActions$ = new ReplaySubject<ActionRequest>()
38
+ this.reconnect()
39
+ }
40
+ }
41
+
42
+ onConnect(callback: () => void) {
43
+ this.onConnectCallback = callback
44
+ }
45
+
46
+ reconnect(): void {
47
+ if (this.socket?.readyState === WebSocket.CLOSED) {
48
+ window.setTimeout(() => {
49
+ this.connect(this.url, this.protocols)
50
+ }, 1000)
51
+ }
52
+ }
53
+
54
+ emit<T>(action: string, request?: ActionRequest['message']): void {
55
+ const actionMessage: ActionRequest = {action, message: request}
56
+ this.queuedActions$.next(actionMessage)
57
+ }
58
+
59
+ on<T>(action: string): Observable<T> {
60
+ return this.actionMessages$.pipe(
61
+ filter(actionMessage => actionMessage.action === action),
62
+ switchMap(actionMessage => {
63
+ if (actionMessage.status === WebsocketMessageStatus.Error) {
64
+ this.errors$.next(actionMessage as ActionErrorResponse)
65
+ return throwError(actionMessage)
66
+ }
67
+ return of(actionMessage)
68
+ }),
69
+ map(actionMessage => actionMessage.message)
70
+ ) as Observable<T>
71
+ }
72
+
73
+ onError({except}: {except?: string[]}): Observable<ActionResponse<unknown>> {
74
+ return this.errors$.pipe(filter(actionMessage => !(except || []).includes(actionMessage.action)))
75
+ }
76
+
77
+ async request<T>(action: string, message?: ActionRequest['message']): Promise<T> {
78
+ this.emit(action, message)
79
+ return new Promise((resolve, reject) => {
80
+ this.on<T>(action).pipe(take(1)).subscribe({
81
+ next: resolve,
82
+ error: reject
83
+ })
84
+ })
85
+ }
86
+ }
@@ -0,0 +1,4 @@
1
+ export interface MailAddress {
2
+ email: string
3
+ name?: string
4
+ }
@@ -0,0 +1,6 @@
1
+ import { Mailable } from './Mailable'
2
+ import { SentMessage } from './SentMessage'
3
+
4
+ export abstract class MailTransport {
5
+ abstract send(message: Mailable): Promise<SentMessage>
6
+ }
@@ -0,0 +1,16 @@
1
+ import { MailAddress } from '@Typetron/Mail/MailAddress'
2
+
3
+ export class Mailable {
4
+
5
+ from: string | MailAddress
6
+ subject?: string
7
+ body?: string | {html: string, text: string}
8
+ to?: string | MailAddress | (string | MailAddress)[]
9
+ replyTo?: string | MailAddress | (string | MailAddress)[]
10
+ cc?: string | MailAddress | (string | MailAddress)[]
11
+ bcc?: string | MailAddress | (string | MailAddress)[]
12
+
13
+ content(): string | {html: string, text: string} | undefined {
14
+ return
15
+ }
16
+ }
package/Mail/Mailer.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { MailTransport } from './MailTransport'
2
+ import { PendingMail } from './PendingMail'
3
+ import { Mailable } from './Mailable'
4
+ import { MailAddress } from '@Typetron/Mail/MailAddress'
5
+
6
+ export class Mailer {
7
+ transport: MailTransport
8
+
9
+ constructor(public from: MailAddress, transport?: MailTransport) {
10
+ if (!transport) {
11
+ throw new Error('Please add the MailProvider in your app in order to use the Mailing feature, ' +
12
+ 'or manually add a Mailer instance in the app container ')
13
+ }
14
+ this.transport = transport
15
+ }
16
+
17
+ to(email: string) {
18
+ const mail = new PendingMail(this)
19
+ mail.from(this.from)
20
+ mail.to(email)
21
+ return mail
22
+ }
23
+
24
+ async send(message: Mailable) {
25
+ return await this.transport.send(message)
26
+ }
27
+ }
@@ -0,0 +1,68 @@
1
+ import { Mailer } from './index'
2
+ import { Mailable } from './Mailable'
3
+ import { MailAddress } from '@Typetron/Mail/MailAddress'
4
+
5
+ export class PendingMail {
6
+
7
+ details: {
8
+ subject?: string
9
+ from: string | MailAddress
10
+ to?: string | MailAddress
11
+ replyTo?: string | MailAddress
12
+ cc?: string | MailAddress
13
+ bcc?: string | MailAddress
14
+ body?: string | {html: string, text: string}
15
+ } = {from: ''}
16
+
17
+ constructor(private mailer: Mailer) {
18
+ }
19
+
20
+ subject(subject: string) {
21
+ this.details.subject = subject
22
+ return this
23
+ }
24
+
25
+ from(email: string | MailAddress) {
26
+ this.details.from = email
27
+ return this
28
+ }
29
+
30
+ to(email: string | MailAddress) {
31
+ this.details.to = email
32
+ return this
33
+ }
34
+
35
+ replyTo(email: string | MailAddress) {
36
+ this.details.replyTo = email
37
+ return this
38
+ }
39
+
40
+ cc(email: string | MailAddress) {
41
+ this.details.cc = email
42
+ return this
43
+ }
44
+
45
+ bcc(email: string | MailAddress) {
46
+ this.details.bcc = email
47
+ return this
48
+ }
49
+
50
+ async send(body: string | {html: string, text: string} | Mailable) {
51
+ let mail
52
+ if (body instanceof Mailable) {
53
+ mail = body
54
+ } else {
55
+ mail = new Mailable()
56
+ mail.body = body
57
+ }
58
+
59
+ mail.subject = this.details.subject
60
+ mail.from = this.details.from
61
+ mail.to = this.details.to
62
+ mail.replyTo = this.details.replyTo
63
+ mail.cc = this.details.cc
64
+ mail.bcc = this.details.bcc
65
+
66
+ return this.mailer.send(mail)
67
+ }
68
+ }
@@ -0,0 +1,20 @@
1
+ import { MailAddress } from './MailAddress'
2
+ import { Mailable } from '@Typetron/Mail/Mailable'
3
+
4
+ export class SentMessage {
5
+ readonly from: string | MailAddress
6
+ readonly subject?: string
7
+ readonly body?: string | {html: string, text: string}
8
+ readonly to?: string | MailAddress | (string | MailAddress)[]
9
+ readonly replyTo?: string | MailAddress | (string | MailAddress)[]
10
+ readonly cc?: string | MailAddress | (string | MailAddress)[]
11
+ readonly bcc?: string | MailAddress | (string | MailAddress)[]
12
+
13
+ constructor(mail: Mailable) {
14
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
15
+ const {content, ...mailDetails} = mail
16
+ Object.assign(this, mailDetails)
17
+ this.body = mail.content() ?? mail.body
18
+ }
19
+
20
+ }
@@ -0,0 +1,13 @@
1
+ import { MailTransport } from '../MailTransport'
2
+ import { SentMessage } from '../SentMessage'
3
+ import { Mailable } from '../Mailable'
4
+
5
+ export class MemoryTransport extends MailTransport {
6
+ messages: SentMessage[] = []
7
+
8
+ async send(message: Mailable) {
9
+ const sentMessage = new SentMessage(message)
10
+ this.messages.push(sentMessage)
11
+ return sentMessage
12
+ }
13
+ }
@@ -0,0 +1,95 @@
1
+ import { MailTransport } from '../MailTransport'
2
+ import { SentMessage } from '../SentMessage'
3
+ import { Mailable } from '../Mailable'
4
+ import { Inject } from '../../Container'
5
+ import { MailConfig } from '../../Framework'
6
+ import client from '@sendgrid/mail'
7
+ import { HttpError } from '@Typetron/Router/Http'
8
+
9
+ export class SendGridTransport extends MailTransport {
10
+ messages: SentMessage[] = []
11
+
12
+ @Inject()
13
+ config: MailConfig
14
+
15
+ constructor(key: string) {
16
+ super()
17
+
18
+ client.setApiKey(key)
19
+ }
20
+
21
+ async send(message: Mailable) {
22
+ const sentMessage = new SentMessage(message)
23
+
24
+ const sendGridMessage = {
25
+ personalizations: [
26
+ {
27
+ to: sentMessage.to,
28
+ cc: sentMessage.cc,
29
+ bcc: sentMessage.bcc
30
+ },
31
+ ],
32
+ from: sentMessage.from,
33
+ replyTo: sentMessage.replyTo,
34
+ subject: sentMessage.subject,
35
+ content: [
36
+ {
37
+ type: 'text/html',
38
+ value: sentMessage.body
39
+ }
40
+ ],
41
+ // attachments: [
42
+ // {
43
+ // content: 'PCFET0NUdGxlPkRvY3VtZW50PC90aXRsZT4KICAgIDwvaGVhZD4KCiAgICA8Ym9keT4KCiAgICA8L2JvZHk+Cgo8L2h0bWw+Cg==',
44
+ // filename: 'index.html',
45
+ // type: 'text/html',
46
+ // disposition: 'attachment'
47
+ // }
48
+ // ],
49
+ // categories: [
50
+ // 'cake',
51
+ // 'pie',
52
+ // 'baking'
53
+ // ],
54
+ // sendAt: 1617260400,
55
+ // batchId: 'AsdFgHjklQweRTYuIopzXcVBNm0aSDfGHjklmZcVbNMqWert1znmOP2asDFjkl',
56
+ // asm: {
57
+ // groupId: 12345,
58
+ // groupsToDisplay: [
59
+ // 12345
60
+ // ]
61
+ // },
62
+ // ipPoolName: 'transactional email',
63
+ // mailSettings: {
64
+ // bypassListManagement: {
65
+ // enable: false
66
+ // },
67
+ // footer: {
68
+ // enable: false
69
+ // },
70
+ // sandboxMode: {
71
+ // enable: false
72
+ // }
73
+ // },
74
+ // trackingSettings: {
75
+ // clickTracking: {
76
+ // enable: true,
77
+ // enableText: false
78
+ // },
79
+ // openTracking: {
80
+ // enable: true,
81
+ // substitutionTag: '%open-track%'
82
+ // },
83
+ // subscriptionTracking: {
84
+ // enable: false
85
+ // }
86
+ // }
87
+ }
88
+
89
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
90
+ /* @ts-ignore */ // SendGrid has TS issues
91
+ await client.send(sendGridMessage).catch(error => {throw new HttpError(error.response.body.errors, error.code)})
92
+
93
+ return sentMessage
94
+ }
95
+ }
package/Mail/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './Transports/MemoryTransport'
2
+ export * from './Mailer'
3
+ export * from './Mailable'
@@ -0,0 +1,41 @@
1
+ import { Constructor } from '../Support'
2
+ import { ModelField, ModelMetadataKey, ModelTypeInterface } from './index'
3
+
4
+ export class Model {
5
+ static async from<T extends Model, Q extends object>(this: Constructor<T> & typeof Model, entity: Promise<Iterable<Q>>): Promise<T[]>;
6
+ static async from<T extends Model, Q extends object>(this: Constructor<T> & typeof Model, entity: Promise<Q>): Promise<T>;
7
+ static from<T extends Model, Q extends object>(this: Constructor<T> & typeof Model, entity: Iterable<Q>): T[];
8
+ static from<T extends Model, Q extends object>(this: Constructor<T> & typeof Model, entity: Q): T;
9
+ static from<T extends Model, Q extends object>(
10
+ this: Constructor<T> & typeof Model,
11
+ entity: Q | Iterable<Q> | Promise<Q | Iterable<Q>>
12
+ ): T | T[] | Promise<T | T[]> {
13
+ if (entity instanceof Promise) {
14
+ return entity.then(value => this.from(value))
15
+ }
16
+ if (Symbol.iterator in Object(entity)) {
17
+ return Array.from(entity as Iterable<Q>).map(item => this.from<T, Q>(item))
18
+ }
19
+ const fields: Record<string, ModelField> = Reflect.getMetadata(ModelMetadataKey, this) || {}
20
+
21
+ return this.transform<T, Q>(fields, entity as Q)
22
+ }
23
+
24
+ protected static transform<T, Q extends object>(fields: Record<string, ModelField>, entity: Q): T {
25
+ const data: Partial<Record<keyof T, Q[keyof Q]>> = new this
26
+ Object.values(fields).forEach(field => {
27
+ if (!entity || !entity.hasOwnProperty(field.name)) {
28
+ return
29
+ }
30
+ const value = entity[field.name as keyof Q]
31
+ if (field.type instanceof ModelTypeInterface && value) {
32
+ // @ts-ignore
33
+ const jsonValue = value['toJSON' as keyof object] ? value?.toJSON() : value
34
+ data[field.name as keyof T] = jsonValue ? field.type.transform(jsonValue) as Q[keyof Q] : undefined
35
+ } else {
36
+ data[field.name as keyof T] = value
37
+ }
38
+ })
39
+ return data as T
40
+ }
41
+ }
@@ -0,0 +1,54 @@
1
+ import { Model } from './Model'
2
+ import { Constructor } from '../Support'
3
+
4
+ export const ModelMetadataKey = 'model:fields'
5
+
6
+ export interface ModelField {
7
+ name: string;
8
+ type: Function | ModelTypeInterface<{}>;
9
+ }
10
+
11
+ export function Field(name?: string) {
12
+ return function(target: Object, property: string) {
13
+ const fields: Record<string, ModelField> = Reflect.getMetadata(ModelMetadataKey, target.constructor) || {}
14
+ let type = Reflect.getMetadata('design:type', target, property)
15
+ if (type.prototype instanceof Model) {
16
+ type = new ModelType(type)
17
+ }
18
+ fields[property] = fields[property] || {name: name || property, type} as ModelField
19
+ Reflect.defineMetadata(ModelMetadataKey, fields, target.constructor)
20
+ }
21
+ }
22
+
23
+ export abstract class ModelTypeInterface<T extends Model, Q = T> {
24
+ constructor(public model: Constructor<T> & typeof Model) {}
25
+
26
+ abstract transform(value: Q): Q;
27
+ }
28
+
29
+ export class ModelType<T extends Model> extends ModelTypeInterface<T> {
30
+
31
+ transform(value: T) {
32
+ return this.model.from(value)
33
+ }
34
+ }
35
+
36
+ export class ArrayType<T extends Model> extends ModelTypeInterface<T, T[]> {
37
+ transform(value: T[]) {
38
+ return Array.from(value).map(item => {
39
+ return this.model.from(item)
40
+ })
41
+ }
42
+ }
43
+
44
+ export function FieldMany(type: typeof Model) {
45
+ return function(target: Object, property: string) {
46
+ const fields: Record<string, ModelField> = Reflect.getMetadata(ModelMetadataKey, target.constructor) || {}
47
+ const field = fields[property] || {name: property, type: new ArrayType(type)} as ModelField
48
+ field.type = new ArrayType(type)
49
+ fields[property] = field
50
+ Reflect.defineMetadata(ModelMetadataKey, fields, target.constructor)
51
+ }
52
+ }
53
+
54
+ export * from './Model'
@@ -0,0 +1,7 @@
1
+ import { Container, Inject } from '../Container'
2
+
3
+ export class BaseController {
4
+
5
+ @Inject()
6
+ protected app: Container
7
+ }