wabe 0.6.9 → 0.6.10
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.
- package/README.md +138 -32
- package/bucket/b.txt +1 -0
- package/dev/index.ts +215 -0
- package/dist/authentication/Session.d.ts +4 -1
- package/dist/authentication/interface.d.ts +16 -0
- package/dist/email/interface.d.ts +1 -1
- package/dist/graphql/resolvers.d.ts +4 -2
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +8713 -8867
- package/dist/server/index.d.ts +4 -2
- package/dist/utils/crypto.d.ts +7 -0
- package/dist/utils/helper.d.ts +4 -1
- package/generated/schema.graphql +16 -14
- package/generated/wabe.ts +4 -4
- package/package.json +15 -15
- package/src/authentication/OTP.test.ts +69 -0
- package/src/authentication/OTP.ts +66 -0
- package/src/authentication/Session.test.ts +665 -0
- package/src/authentication/Session.ts +529 -0
- package/src/authentication/defaultAuthentication.ts +214 -0
- package/src/authentication/index.ts +3 -0
- package/src/authentication/interface.ts +157 -0
- package/src/authentication/oauth/GitHub.test.ts +105 -0
- package/src/authentication/oauth/GitHub.ts +133 -0
- package/src/authentication/oauth/Google.test.ts +105 -0
- package/src/authentication/oauth/Google.ts +110 -0
- package/src/authentication/oauth/Oauth2Client.test.ts +225 -0
- package/src/authentication/oauth/Oauth2Client.ts +140 -0
- package/src/authentication/oauth/index.ts +2 -0
- package/src/authentication/oauth/utils.test.ts +35 -0
- package/src/authentication/oauth/utils.ts +28 -0
- package/src/authentication/providers/EmailOTP.test.ts +138 -0
- package/src/authentication/providers/EmailOTP.ts +93 -0
- package/src/authentication/providers/EmailPassword.test.ts +187 -0
- package/src/authentication/providers/EmailPassword.ts +130 -0
- package/src/authentication/providers/EmailPasswordSRP.test.ts +206 -0
- package/src/authentication/providers/EmailPasswordSRP.ts +184 -0
- package/src/authentication/providers/GitHub.ts +30 -0
- package/src/authentication/providers/Google.ts +30 -0
- package/src/authentication/providers/OAuth.test.ts +185 -0
- package/src/authentication/providers/OAuth.ts +112 -0
- package/src/authentication/providers/PhonePassword.test.ts +187 -0
- package/src/authentication/providers/PhonePassword.ts +129 -0
- package/src/authentication/providers/QRCodeOTP.test.ts +79 -0
- package/src/authentication/providers/QRCodeOTP.ts +65 -0
- package/src/authentication/providers/index.ts +6 -0
- package/src/authentication/resolvers/refreshResolver.test.ts +37 -0
- package/src/authentication/resolvers/refreshResolver.ts +20 -0
- package/src/authentication/resolvers/signInWithResolver.inte.test.ts +59 -0
- package/src/authentication/resolvers/signInWithResolver.test.ts +307 -0
- package/src/authentication/resolvers/signInWithResolver.ts +102 -0
- package/src/authentication/resolvers/signOutResolver.test.ts +41 -0
- package/src/authentication/resolvers/signOutResolver.ts +22 -0
- package/src/authentication/resolvers/signUpWithResolver.test.ts +186 -0
- package/src/authentication/resolvers/signUpWithResolver.ts +69 -0
- package/src/authentication/resolvers/verifyChallenge.test.ts +136 -0
- package/src/authentication/resolvers/verifyChallenge.ts +69 -0
- package/src/authentication/roles.test.ts +59 -0
- package/src/authentication/roles.ts +40 -0
- package/src/authentication/utils.test.ts +99 -0
- package/src/authentication/utils.ts +43 -0
- package/src/cache/InMemoryCache.test.ts +62 -0
- package/src/cache/InMemoryCache.ts +45 -0
- package/src/cron/index.test.ts +17 -0
- package/src/cron/index.ts +46 -0
- package/src/database/DatabaseController.test.ts +625 -0
- package/src/database/DatabaseController.ts +983 -0
- package/src/database/index.test.ts +1230 -0
- package/src/database/index.ts +9 -0
- package/src/database/interface.ts +312 -0
- package/src/email/DevAdapter.ts +8 -0
- package/src/email/EmailController.test.ts +29 -0
- package/src/email/EmailController.ts +13 -0
- package/src/email/index.ts +2 -0
- package/src/email/interface.ts +36 -0
- package/src/email/templates/sendOtpCode.ts +120 -0
- package/src/file/FileController.ts +28 -0
- package/src/file/FileDevAdapter.ts +54 -0
- package/src/file/hookDeleteFile.ts +27 -0
- package/src/file/hookReadFile.ts +70 -0
- package/src/file/hookUploadFile.ts +53 -0
- package/src/file/index.test.ts +979 -0
- package/src/file/index.ts +2 -0
- package/src/file/interface.ts +42 -0
- package/src/graphql/GraphQLSchema.test.ts +4399 -0
- package/src/graphql/GraphQLSchema.ts +928 -0
- package/src/graphql/index.ts +2 -0
- package/src/graphql/parseGraphqlSchema.ts +94 -0
- package/src/graphql/parser.test.ts +217 -0
- package/src/graphql/parser.ts +566 -0
- package/src/graphql/pointerAndRelationFunction.ts +200 -0
- package/src/graphql/resolvers.ts +467 -0
- package/src/graphql/tests/aggregation.test.ts +1123 -0
- package/src/graphql/tests/e2e.test.ts +596 -0
- package/src/graphql/tests/scalars.test.ts +250 -0
- package/src/graphql/types.ts +219 -0
- package/src/hooks/HookObject.test.ts +122 -0
- package/src/hooks/HookObject.ts +168 -0
- package/src/hooks/authentication.ts +76 -0
- package/src/hooks/createUser.test.ts +77 -0
- package/src/hooks/createUser.ts +10 -0
- package/src/hooks/defaultFields.test.ts +187 -0
- package/src/hooks/defaultFields.ts +40 -0
- package/src/hooks/deleteSession.test.ts +181 -0
- package/src/hooks/deleteSession.ts +20 -0
- package/src/hooks/hashFieldHook.test.ts +163 -0
- package/src/hooks/hashFieldHook.ts +97 -0
- package/src/hooks/index.test.ts +207 -0
- package/src/hooks/index.ts +430 -0
- package/src/hooks/permissions.test.ts +424 -0
- package/src/hooks/permissions.ts +113 -0
- package/src/hooks/protected.test.ts +551 -0
- package/src/hooks/protected.ts +72 -0
- package/src/hooks/searchableFields.test.ts +166 -0
- package/src/hooks/searchableFields.ts +98 -0
- package/src/hooks/session.test.ts +138 -0
- package/src/hooks/session.ts +78 -0
- package/src/hooks/setEmail.test.ts +216 -0
- package/src/hooks/setEmail.ts +35 -0
- package/src/hooks/setupAcl.test.ts +589 -0
- package/src/hooks/setupAcl.ts +29 -0
- package/src/index.ts +9 -0
- package/src/schema/Schema.test.ts +484 -0
- package/src/schema/Schema.ts +795 -0
- package/src/schema/defaultResolvers.ts +94 -0
- package/src/schema/index.ts +1 -0
- package/src/schema/resolvers/meResolver.test.ts +62 -0
- package/src/schema/resolvers/meResolver.ts +14 -0
- package/src/schema/resolvers/newFile.ts +0 -0
- package/src/schema/resolvers/resetPassword.test.ts +345 -0
- package/src/schema/resolvers/resetPassword.ts +64 -0
- package/src/schema/resolvers/sendEmail.test.ts +118 -0
- package/src/schema/resolvers/sendEmail.ts +21 -0
- package/src/schema/resolvers/sendOtpCode.test.ts +153 -0
- package/src/schema/resolvers/sendOtpCode.ts +52 -0
- package/src/security.test.ts +3461 -0
- package/src/server/defaultSessionHandler.test.ts +66 -0
- package/src/server/defaultSessionHandler.ts +115 -0
- package/src/server/generateCodegen.ts +476 -0
- package/src/server/index.test.ts +552 -0
- package/src/server/index.ts +354 -0
- package/src/server/interface.ts +11 -0
- package/src/server/routes/authHandler.ts +187 -0
- package/src/server/routes/index.ts +40 -0
- package/src/utils/crypto.test.ts +41 -0
- package/src/utils/crypto.ts +121 -0
- package/src/utils/export.ts +13 -0
- package/src/utils/helper.ts +195 -0
- package/src/utils/index.test.ts +11 -0
- package/src/utils/index.ts +201 -0
- package/src/utils/preload.ts +8 -0
- package/src/utils/testHelper.ts +117 -0
- package/tsconfig.json +32 -0
- package/bunfig.toml +0 -4
- package/dist/ai/index.d.ts +0 -1
- package/dist/ai/interface.d.ts +0 -9
- /package/dist/server/{defaultHandlers.d.ts → defaultSessionHandler.d.ts} +0 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import type { WabeContext } from '../server/interface'
|
|
2
|
+
import type { WabeTypes } from '../server'
|
|
3
|
+
import type { SchemaInterface } from '../schema'
|
|
4
|
+
|
|
5
|
+
type IsScalar<T> = T extends string | number | boolean | Date ? true : false
|
|
6
|
+
|
|
7
|
+
type IsArray<T> = T extends Array<any> ? true : false
|
|
8
|
+
|
|
9
|
+
type IsObject<T, K extends WabeTypes> = T extends object
|
|
10
|
+
? T extends K['types'][keyof K['types']]
|
|
11
|
+
? false
|
|
12
|
+
: true
|
|
13
|
+
: false
|
|
14
|
+
|
|
15
|
+
type ExtractType<
|
|
16
|
+
T extends WabeTypes,
|
|
17
|
+
ClassName extends keyof T['types'],
|
|
18
|
+
FieldName extends keyof T['types'][ClassName],
|
|
19
|
+
> = T['types'][ClassName][FieldName]
|
|
20
|
+
|
|
21
|
+
type ExtractWhereType<
|
|
22
|
+
T extends WabeTypes,
|
|
23
|
+
ClassName extends keyof T['where'],
|
|
24
|
+
FieldName extends keyof T['where'][ClassName],
|
|
25
|
+
> = T['where'][ClassName][FieldName]
|
|
26
|
+
|
|
27
|
+
type WhereScalar<T> = {
|
|
28
|
+
equalTo?: T
|
|
29
|
+
notEqualTo?: T
|
|
30
|
+
greaterThan?: T
|
|
31
|
+
lessThan?: T
|
|
32
|
+
greaterThanOrEqualTo?: T
|
|
33
|
+
lessThanOrEqualTo?: T
|
|
34
|
+
in?: T[]
|
|
35
|
+
notIn?: T[]
|
|
36
|
+
contains?: T
|
|
37
|
+
notContains?: T
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type WhereObject<T> = {
|
|
41
|
+
[P in keyof T]: IsScalar<T[P]> extends false
|
|
42
|
+
? WhereObject<Partial<T[P]>>
|
|
43
|
+
: WhereScalar<T[P]>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
type WhereAggregation<T extends WabeTypes, K = keyof T['where']> = {
|
|
47
|
+
[P in keyof T['where'][K]]: IsScalar<ExtractWhereType<T, K, P>> extends false
|
|
48
|
+
? WhereObject<Partial<ExtractWhereType<T, K, P>>>
|
|
49
|
+
: WhereScalar<ExtractWhereType<T, K, P>>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type WhereConditional<T extends WabeTypes, K = keyof T['where']> = {
|
|
53
|
+
OR?: Array<WhereType<T, K>>
|
|
54
|
+
AND?: Array<WhereType<T, K>>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export type WhereType<T extends WabeTypes, K = keyof T['where']> = Partial<
|
|
58
|
+
WhereAggregation<T, K>
|
|
59
|
+
> &
|
|
60
|
+
WhereConditional<T, K>
|
|
61
|
+
|
|
62
|
+
type SelectObject<T, K extends WabeTypes, Depth extends number = 3> = {
|
|
63
|
+
[P in keyof T]: IsScalar<T[P]> extends true
|
|
64
|
+
? boolean
|
|
65
|
+
: IsArray<T[P]> extends true
|
|
66
|
+
? T[P] extends Array<infer Item>
|
|
67
|
+
?
|
|
68
|
+
| (Depth extends 0
|
|
69
|
+
? boolean
|
|
70
|
+
: SelectObject<Partial<Item>, K, Decrement<Depth>>)
|
|
71
|
+
| boolean
|
|
72
|
+
: boolean
|
|
73
|
+
: IsObject<[P], K> extends true
|
|
74
|
+
?
|
|
75
|
+
| (Depth extends 0
|
|
76
|
+
? boolean
|
|
77
|
+
: SelectObject<Partial<T[P]>, K, Decrement<Depth>>)
|
|
78
|
+
| boolean
|
|
79
|
+
: boolean
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type Decrement<N extends number> = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10][N]
|
|
83
|
+
|
|
84
|
+
export type SelectType<
|
|
85
|
+
T extends WabeTypes,
|
|
86
|
+
K extends keyof T['types'],
|
|
87
|
+
U extends keyof T['types'][K],
|
|
88
|
+
Depth extends number = 3,
|
|
89
|
+
> = Partial<{
|
|
90
|
+
[P in U]: IsScalar<ExtractType<T, K, P>> extends true
|
|
91
|
+
? boolean
|
|
92
|
+
: IsArray<ExtractType<T, K, P>> extends true
|
|
93
|
+
? ExtractType<T, K, P> extends Array<infer Item>
|
|
94
|
+
?
|
|
95
|
+
| (Depth extends 0
|
|
96
|
+
? boolean
|
|
97
|
+
: SelectObject<Partial<Item>, T, Decrement<Depth>>)
|
|
98
|
+
| boolean
|
|
99
|
+
: boolean
|
|
100
|
+
: ExtractType<T, K, P> extends object
|
|
101
|
+
?
|
|
102
|
+
| (Depth extends 0
|
|
103
|
+
? boolean
|
|
104
|
+
: SelectObject<
|
|
105
|
+
Partial<ExtractType<T, K, P>>,
|
|
106
|
+
T,
|
|
107
|
+
Decrement<Depth>
|
|
108
|
+
>)
|
|
109
|
+
| boolean
|
|
110
|
+
: boolean
|
|
111
|
+
}>
|
|
112
|
+
|
|
113
|
+
export type OrderType<
|
|
114
|
+
T extends WabeTypes,
|
|
115
|
+
K extends keyof T['types'],
|
|
116
|
+
U extends keyof T['types'][K],
|
|
117
|
+
> = Record<U, 'ASC' | 'DESC'>
|
|
118
|
+
|
|
119
|
+
export type OutputType<
|
|
120
|
+
T extends WabeTypes,
|
|
121
|
+
K extends keyof T['types'],
|
|
122
|
+
U extends keyof T['types'][K],
|
|
123
|
+
> = (Pick<T['types'][K], U> & { id: string }) | null
|
|
124
|
+
|
|
125
|
+
export interface AdapterOptions {
|
|
126
|
+
databaseUrl: string
|
|
127
|
+
databaseName: string
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type MutationData<
|
|
131
|
+
T extends WabeTypes,
|
|
132
|
+
K extends keyof T['types'],
|
|
133
|
+
U extends keyof T['types'][K],
|
|
134
|
+
> = Record<U, any>
|
|
135
|
+
|
|
136
|
+
export interface CountOptions<T extends WabeTypes, K extends keyof T['types']> {
|
|
137
|
+
className: K
|
|
138
|
+
where?: WhereType<T, K>
|
|
139
|
+
context: WabeContext<T>
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface GetObjectOptions<
|
|
143
|
+
T extends WabeTypes,
|
|
144
|
+
K extends keyof T['types'],
|
|
145
|
+
U extends keyof T['types'][K],
|
|
146
|
+
> {
|
|
147
|
+
className: K
|
|
148
|
+
id: string
|
|
149
|
+
where?: WhereType<T, K>
|
|
150
|
+
context: WabeContext<T>
|
|
151
|
+
_skipHooks?: boolean
|
|
152
|
+
select?: SelectType<T, K, U>
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface GetObjectsOptions<
|
|
156
|
+
T extends WabeTypes,
|
|
157
|
+
K extends keyof T['types'],
|
|
158
|
+
U extends keyof T['types'][K],
|
|
159
|
+
W extends keyof T['types'][K],
|
|
160
|
+
> {
|
|
161
|
+
className: K
|
|
162
|
+
where?: WhereType<T, K>
|
|
163
|
+
order?: OrderType<T, K, U>
|
|
164
|
+
offset?: number
|
|
165
|
+
first?: number
|
|
166
|
+
context: WabeContext<T>
|
|
167
|
+
_skipHooks?: boolean
|
|
168
|
+
select?: SelectType<T, K, W>
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface CreateObjectOptions<
|
|
172
|
+
T extends WabeTypes,
|
|
173
|
+
K extends keyof T['types'],
|
|
174
|
+
U extends keyof T['types'][K],
|
|
175
|
+
W extends keyof T['types'][K],
|
|
176
|
+
> {
|
|
177
|
+
className: K
|
|
178
|
+
data: MutationData<T, K, U>
|
|
179
|
+
context: WabeContext<T>
|
|
180
|
+
select?: SelectType<T, K, W>
|
|
181
|
+
}
|
|
182
|
+
export interface CreateObjectsOptions<
|
|
183
|
+
T extends WabeTypes,
|
|
184
|
+
K extends keyof T['types'],
|
|
185
|
+
U extends keyof T['types'][K],
|
|
186
|
+
W extends keyof T['types'][K],
|
|
187
|
+
X extends keyof T['types'][K],
|
|
188
|
+
> {
|
|
189
|
+
className: K
|
|
190
|
+
data: Array<MutationData<T, K, U>>
|
|
191
|
+
offset?: number
|
|
192
|
+
first?: number
|
|
193
|
+
order?: OrderType<T, U, X>
|
|
194
|
+
context: WabeContext<T>
|
|
195
|
+
select?: SelectType<T, K, W>
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface UpdateObjectOptions<
|
|
199
|
+
T extends WabeTypes,
|
|
200
|
+
K extends keyof T['types'],
|
|
201
|
+
U extends keyof T['types'][K],
|
|
202
|
+
W extends keyof T['types'][K],
|
|
203
|
+
> {
|
|
204
|
+
className: K
|
|
205
|
+
id: string
|
|
206
|
+
where?: WhereType<T, K>
|
|
207
|
+
data: MutationData<T, K, U>
|
|
208
|
+
context: WabeContext<T>
|
|
209
|
+
_skipHooks?: boolean
|
|
210
|
+
select?: SelectType<T, K, W>
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface UpdateObjectsOptions<
|
|
214
|
+
T extends WabeTypes,
|
|
215
|
+
K extends keyof T['types'],
|
|
216
|
+
U extends keyof T['types'][K],
|
|
217
|
+
W extends keyof T['types'][K],
|
|
218
|
+
X extends keyof T['types'][K],
|
|
219
|
+
> {
|
|
220
|
+
className: K
|
|
221
|
+
where: WhereType<T, K>
|
|
222
|
+
order?: OrderType<T, K, X>
|
|
223
|
+
data: MutationData<T, K, U>
|
|
224
|
+
offset?: number
|
|
225
|
+
first?: number
|
|
226
|
+
context: WabeContext<T>
|
|
227
|
+
_skipHooks?: boolean
|
|
228
|
+
select?: SelectType<T, K, W>
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface DeleteObjectOptions<
|
|
232
|
+
T extends WabeTypes,
|
|
233
|
+
K extends keyof T['types'],
|
|
234
|
+
U extends keyof T['types'][K],
|
|
235
|
+
> {
|
|
236
|
+
className: K
|
|
237
|
+
id: string
|
|
238
|
+
where?: WhereType<T, K>
|
|
239
|
+
context: WabeContext<T>
|
|
240
|
+
select?: SelectType<T, K, U>
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface DeleteObjectsOptions<
|
|
244
|
+
T extends WabeTypes,
|
|
245
|
+
K extends keyof T['types'],
|
|
246
|
+
U extends keyof T['types'][K],
|
|
247
|
+
W extends keyof T['types'][K],
|
|
248
|
+
> {
|
|
249
|
+
className: K
|
|
250
|
+
where: WhereType<T, K>
|
|
251
|
+
order?: OrderType<T, K, U>
|
|
252
|
+
offset?: number
|
|
253
|
+
first?: number
|
|
254
|
+
context: WabeContext<T>
|
|
255
|
+
select?: SelectType<T, K, W>
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface DatabaseAdapter<T extends WabeTypes> {
|
|
259
|
+
close(): Promise<void>
|
|
260
|
+
|
|
261
|
+
createClassIfNotExist(
|
|
262
|
+
className: string,
|
|
263
|
+
schema: SchemaInterface<T>,
|
|
264
|
+
): Promise<any> | any
|
|
265
|
+
|
|
266
|
+
initializeDatabase(schema: SchemaInterface<T>): Promise<void>
|
|
267
|
+
clearDatabase(): Promise<void>
|
|
268
|
+
|
|
269
|
+
count<K extends keyof T['types']>(params: CountOptions<T, K>): Promise<number>
|
|
270
|
+
|
|
271
|
+
getObject<K extends keyof T['types'], U extends keyof T['types'][K]>(
|
|
272
|
+
params: GetObjectOptions<T, K, U>,
|
|
273
|
+
): Promise<OutputType<T, K, U>>
|
|
274
|
+
getObjects<
|
|
275
|
+
K extends keyof T['types'],
|
|
276
|
+
U extends keyof T['types'][K],
|
|
277
|
+
W extends keyof T['types'][K],
|
|
278
|
+
>(params: GetObjectsOptions<T, K, U, W>): Promise<OutputType<T, K, W>[]>
|
|
279
|
+
|
|
280
|
+
createObject<
|
|
281
|
+
K extends keyof T['types'],
|
|
282
|
+
U extends keyof T['types'][K],
|
|
283
|
+
W extends keyof T['types'][K],
|
|
284
|
+
>(params: CreateObjectOptions<T, K, U, W>): Promise<{ id: string }>
|
|
285
|
+
createObjects<
|
|
286
|
+
K extends keyof T['types'],
|
|
287
|
+
U extends keyof T['types'][K],
|
|
288
|
+
W extends keyof T['types'][K],
|
|
289
|
+
X extends keyof T['types'][K],
|
|
290
|
+
>(params: CreateObjectsOptions<T, K, U, W, X>): Promise<Array<{ id: string }>>
|
|
291
|
+
|
|
292
|
+
updateObject<
|
|
293
|
+
K extends keyof T['types'],
|
|
294
|
+
U extends keyof T['types'][K],
|
|
295
|
+
W extends keyof T['types'][K],
|
|
296
|
+
>(params: UpdateObjectOptions<T, K, U, W>): Promise<{ id: string }>
|
|
297
|
+
updateObjects<
|
|
298
|
+
K extends keyof T['types'],
|
|
299
|
+
U extends keyof T['types'][K],
|
|
300
|
+
W extends keyof T['types'][K],
|
|
301
|
+
X extends keyof T['types'][K],
|
|
302
|
+
>(params: UpdateObjectsOptions<T, K, U, W, X>): Promise<Array<{ id: string }>>
|
|
303
|
+
|
|
304
|
+
deleteObject<K extends keyof T['types'], U extends keyof T['types'][K]>(
|
|
305
|
+
params: DeleteObjectOptions<T, K, U>,
|
|
306
|
+
): Promise<void>
|
|
307
|
+
deleteObjects<
|
|
308
|
+
K extends keyof T['types'],
|
|
309
|
+
U extends keyof T['types'][K],
|
|
310
|
+
W extends keyof T['types'][K],
|
|
311
|
+
>(params: DeleteObjectsOptions<T, K, U, W>): Promise<void>
|
|
312
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, it, mock } from 'bun:test'
|
|
2
|
+
import { EmailController } from './EmailController'
|
|
3
|
+
|
|
4
|
+
describe('EmailController', () => {
|
|
5
|
+
it('should send email using correct adapter', async () => {
|
|
6
|
+
const mockSend = mock(() => {})
|
|
7
|
+
const dummyAdapter = {
|
|
8
|
+
send: mockSend,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// @ts-expect-error
|
|
12
|
+
const controller = new EmailController(dummyAdapter)
|
|
13
|
+
|
|
14
|
+
await controller.send({
|
|
15
|
+
from: 'from',
|
|
16
|
+
to: ['to'],
|
|
17
|
+
subject: 'subject',
|
|
18
|
+
text: 'text',
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
expect(mockSend).toHaveBeenCalledTimes(1)
|
|
22
|
+
expect(mockSend).toHaveBeenCalledWith({
|
|
23
|
+
from: 'from',
|
|
24
|
+
to: ['to'],
|
|
25
|
+
subject: 'subject',
|
|
26
|
+
text: 'text',
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EmailAdapter, EmailSendOptions } from './interface'
|
|
2
|
+
|
|
3
|
+
export class EmailController implements EmailAdapter {
|
|
4
|
+
public adapter: EmailAdapter
|
|
5
|
+
|
|
6
|
+
constructor(adapter: EmailAdapter) {
|
|
7
|
+
this.adapter = adapter
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
send(options: EmailSendOptions) {
|
|
11
|
+
return this.adapter.send(options)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type HtmlTemplates = {
|
|
2
|
+
sendOTPCode: {
|
|
3
|
+
fn: (options: { otp: string }) => string | Promise<string>
|
|
4
|
+
subject: string
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface EmailSendOptions {
|
|
9
|
+
from: string
|
|
10
|
+
to: Array<string>
|
|
11
|
+
subject: string
|
|
12
|
+
node?: any
|
|
13
|
+
html?: string
|
|
14
|
+
text?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface EmailAdapter {
|
|
18
|
+
/**
|
|
19
|
+
* Send an email using the provided adapter
|
|
20
|
+
* @param options Mail options (expeditor, recipient, subject ...)
|
|
21
|
+
* @return The id of the email sended, throw an error if something wrong
|
|
22
|
+
*/
|
|
23
|
+
send(options: EmailSendOptions): Promise<string>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Configuration for the email in Wabe
|
|
28
|
+
* @property adapter The adapter to use to send emails
|
|
29
|
+
* @property mainEmail The email to use as sender for emails sent by Wabe
|
|
30
|
+
* @property templates The html templates to use for a specific email. If not provided, Wabe will use the default templates
|
|
31
|
+
*/
|
|
32
|
+
export interface EmailConfig {
|
|
33
|
+
adapter: EmailAdapter
|
|
34
|
+
mainEmail?: string
|
|
35
|
+
htmlTemplates?: HtmlTemplates
|
|
36
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export const sendOtpCodeTemplate = (otp: string) => `
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="UTF-8">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
9
|
+
<title>Password Reset</title>
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
font-family: 'Arial', sans-serif;
|
|
13
|
+
margin: 0;
|
|
14
|
+
padding: 0;
|
|
15
|
+
background-color: #f4f4f4;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.email-container {
|
|
19
|
+
max-width: 600px;
|
|
20
|
+
margin: 0 auto;
|
|
21
|
+
background-color: #ffffff;
|
|
22
|
+
border-radius: 8px;
|
|
23
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header {
|
|
28
|
+
background-color: #4CAF50;
|
|
29
|
+
padding: 20px;
|
|
30
|
+
text-align: center;
|
|
31
|
+
color: white;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.header h1 {
|
|
35
|
+
margin: 0;
|
|
36
|
+
font-size: 24px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.content {
|
|
40
|
+
padding: 20px;
|
|
41
|
+
font-size: 16px;
|
|
42
|
+
line-height: 1.6;
|
|
43
|
+
color: #333333;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.content p {
|
|
47
|
+
margin-bottom: 20px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.otp-code {
|
|
51
|
+
display: inline-block;
|
|
52
|
+
padding: 10px 20px;
|
|
53
|
+
background-color: #4CAF50;
|
|
54
|
+
color: white;
|
|
55
|
+
font-size: 18px;
|
|
56
|
+
font-weight: bold;
|
|
57
|
+
border-radius: 5px;
|
|
58
|
+
letter-spacing: 2px;
|
|
59
|
+
text-align: center;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.footer {
|
|
63
|
+
background-color: #f4f4f4;
|
|
64
|
+
text-align: center;
|
|
65
|
+
padding: 10px;
|
|
66
|
+
font-size: 14px;
|
|
67
|
+
color: #888888;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.footer p {
|
|
71
|
+
margin: 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Responsive Design */
|
|
75
|
+
@media screen and (max-width: 600px) {
|
|
76
|
+
.email-container {
|
|
77
|
+
width: 100%;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.header h1 {
|
|
81
|
+
font-size: 20px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.content {
|
|
85
|
+
padding: 15px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.otp-code {
|
|
89
|
+
font-size: 16px;
|
|
90
|
+
padding: 8px 16px;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
</style>
|
|
94
|
+
</head>
|
|
95
|
+
|
|
96
|
+
<body>
|
|
97
|
+
<div class="email-container">
|
|
98
|
+
<!-- Email Header -->
|
|
99
|
+
<div class="header">
|
|
100
|
+
<h1>Confirmation code</h1>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<!-- Email Content -->
|
|
104
|
+
<div class="content">
|
|
105
|
+
<p>Hello,</p>
|
|
106
|
+
<p>Here is your confirmation code. Please use the OTP code (valid for 5 minutes) below to proceed the action:</p>
|
|
107
|
+
<p class="otp-code">${otp}</p>
|
|
108
|
+
<p>If you did not request this code, please ignore this email.</p>
|
|
109
|
+
<p>Thank you</p>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- Email Footer -->
|
|
113
|
+
<div class="footer">
|
|
114
|
+
<p>Powered by Wabe</p>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</body>
|
|
118
|
+
|
|
119
|
+
</html>
|
|
120
|
+
`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Wabe } from '../server'
|
|
2
|
+
import type { DevWabeTypes } from '../utils/helper'
|
|
3
|
+
import type { FileAdapter, ReadFileOptions } from './interface'
|
|
4
|
+
|
|
5
|
+
export class FileController implements FileAdapter {
|
|
6
|
+
public adapter: FileAdapter
|
|
7
|
+
private wabe: Wabe<DevWabeTypes>
|
|
8
|
+
|
|
9
|
+
constructor(adapter: FileAdapter, wabe: Wabe<any>) {
|
|
10
|
+
this.adapter = adapter
|
|
11
|
+
this.wabe = wabe
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
uploadFile(file: File) {
|
|
15
|
+
return this.adapter.uploadFile(file)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
readFile(fileName: string, options?: ReadFileOptions) {
|
|
19
|
+
return this.adapter.readFile(fileName, {
|
|
20
|
+
...options,
|
|
21
|
+
port: this.wabe.config.port,
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
deleteFile(fileName: string) {
|
|
26
|
+
return this.adapter.deleteFile(fileName)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { writeFile, mkdir, rm, access, constants } from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import type { FileAdapter, ReadFileOptions } from '.'
|
|
4
|
+
|
|
5
|
+
export class FileDevAdapter implements FileAdapter {
|
|
6
|
+
private basePath = 'bucket'
|
|
7
|
+
private rootPath = process.cwd()
|
|
8
|
+
|
|
9
|
+
async uploadFile(file: File): Promise<void> {
|
|
10
|
+
const fullPath = path.join(this.rootPath, this.basePath)
|
|
11
|
+
|
|
12
|
+
await mkdir(fullPath, { recursive: true })
|
|
13
|
+
|
|
14
|
+
const fileType = file.type
|
|
15
|
+
|
|
16
|
+
let fileContent: Buffer
|
|
17
|
+
|
|
18
|
+
if (fileType.startsWith('text') || fileType.includes('json')) {
|
|
19
|
+
const textContent = await file.text()
|
|
20
|
+
fileContent = Buffer.from(textContent, 'utf-8')
|
|
21
|
+
} else {
|
|
22
|
+
const arrayBuffer = await file.arrayBuffer()
|
|
23
|
+
fileContent = Buffer.from(arrayBuffer)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
await writeFile(path.join(fullPath, file.name), fileContent)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async readFile(
|
|
30
|
+
fileName: string,
|
|
31
|
+
options?: ReadFileOptions,
|
|
32
|
+
): Promise<string | null> {
|
|
33
|
+
const filePath = path.join(this.rootPath, this.basePath, fileName)
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
await access(filePath, constants.F_OK)
|
|
37
|
+
return `http://127.0.0.1:${options?.port || 3001}/${this.basePath}/${fileName}`
|
|
38
|
+
} catch {
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async deleteFile(fileName: string): Promise<void> {
|
|
44
|
+
const filePath = path.join(this.rootPath, this.basePath, fileName)
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await access(filePath, constants.F_OK)
|
|
48
|
+
|
|
49
|
+
await rm(filePath)
|
|
50
|
+
} catch {
|
|
51
|
+
// Do nothing
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { HookObject } from '../hooks/HookObject'
|
|
2
|
+
|
|
3
|
+
const deleteFile = async (hookObject: HookObject<any, any>) => {
|
|
4
|
+
const schema = hookObject.context.wabe.config.schema?.classes?.find(
|
|
5
|
+
(currentClass) => currentClass.name === hookObject.className,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
if (!schema) return
|
|
9
|
+
|
|
10
|
+
await Promise.all(
|
|
11
|
+
Object.entries(schema.fields)
|
|
12
|
+
.filter(([_, value]) => value.type === 'File')
|
|
13
|
+
.map(([fieldName]) => {
|
|
14
|
+
const fileName = hookObject.originalObject?.[fieldName]?.name as string
|
|
15
|
+
|
|
16
|
+
if (!fileName) return Promise.resolve()
|
|
17
|
+
|
|
18
|
+
if (!hookObject.context.wabe.controllers.file)
|
|
19
|
+
throw new Error('No file adapter found')
|
|
20
|
+
|
|
21
|
+
return hookObject.context.wabe.controllers.file?.deleteFile(fileName)
|
|
22
|
+
}),
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const defaultAfterDeleteFile = (hookObject: HookObject<any, any>) =>
|
|
27
|
+
deleteFile(hookObject)
|