wabe 0.6.9 → 0.6.11

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 (162) hide show
  1. package/README.md +156 -50
  2. package/bucket/b.txt +1 -0
  3. package/dev/index.ts +215 -0
  4. package/dist/authentication/Session.d.ts +4 -1
  5. package/dist/authentication/interface.d.ts +16 -0
  6. package/dist/cron/index.d.ts +0 -1
  7. package/dist/database/DatabaseController.d.ts +41 -13
  8. package/dist/database/interface.d.ts +1 -0
  9. package/dist/email/DevAdapter.d.ts +0 -1
  10. package/dist/email/interface.d.ts +1 -1
  11. package/dist/graphql/resolvers.d.ts +4 -2
  12. package/dist/hooks/index.d.ts +8 -2
  13. package/dist/index.d.ts +0 -1
  14. package/dist/index.js +32144 -32058
  15. package/dist/schema/Schema.d.ts +2 -1
  16. package/dist/server/index.d.ts +4 -2
  17. package/dist/utils/crypto.d.ts +7 -0
  18. package/dist/utils/helper.d.ts +5 -1
  19. package/generated/schema.graphql +22 -14
  20. package/generated/wabe.ts +4 -4
  21. package/package.json +23 -23
  22. package/src/authentication/OTP.test.ts +69 -0
  23. package/src/authentication/OTP.ts +64 -0
  24. package/src/authentication/Session.test.ts +629 -0
  25. package/src/authentication/Session.ts +493 -0
  26. package/src/authentication/defaultAuthentication.ts +209 -0
  27. package/src/authentication/index.ts +3 -0
  28. package/src/authentication/interface.ts +155 -0
  29. package/src/authentication/oauth/GitHub.test.ts +91 -0
  30. package/src/authentication/oauth/GitHub.ts +121 -0
  31. package/src/authentication/oauth/Google.test.ts +91 -0
  32. package/src/authentication/oauth/Google.ts +101 -0
  33. package/src/authentication/oauth/Oauth2Client.test.ts +219 -0
  34. package/src/authentication/oauth/Oauth2Client.ts +135 -0
  35. package/src/authentication/oauth/index.ts +2 -0
  36. package/src/authentication/oauth/utils.test.ts +33 -0
  37. package/src/authentication/oauth/utils.ts +27 -0
  38. package/src/authentication/providers/EmailOTP.test.ts +127 -0
  39. package/src/authentication/providers/EmailOTP.ts +84 -0
  40. package/src/authentication/providers/EmailPassword.test.ts +176 -0
  41. package/src/authentication/providers/EmailPassword.ts +116 -0
  42. package/src/authentication/providers/EmailPasswordSRP.test.ts +208 -0
  43. package/src/authentication/providers/EmailPasswordSRP.ts +179 -0
  44. package/src/authentication/providers/GitHub.ts +24 -0
  45. package/src/authentication/providers/Google.ts +24 -0
  46. package/src/authentication/providers/OAuth.test.ts +185 -0
  47. package/src/authentication/providers/OAuth.ts +106 -0
  48. package/src/authentication/providers/PhonePassword.test.ts +176 -0
  49. package/src/authentication/providers/PhonePassword.ts +115 -0
  50. package/src/authentication/providers/QRCodeOTP.test.ts +77 -0
  51. package/src/authentication/providers/QRCodeOTP.ts +58 -0
  52. package/src/authentication/providers/index.ts +6 -0
  53. package/src/authentication/resolvers/refreshResolver.test.ts +30 -0
  54. package/src/authentication/resolvers/refreshResolver.ts +19 -0
  55. package/src/authentication/resolvers/signInWithResolver.inte.test.ts +59 -0
  56. package/src/authentication/resolvers/signInWithResolver.test.ts +293 -0
  57. package/src/authentication/resolvers/signInWithResolver.ts +92 -0
  58. package/src/authentication/resolvers/signOutResolver.test.ts +38 -0
  59. package/src/authentication/resolvers/signOutResolver.ts +18 -0
  60. package/src/authentication/resolvers/signUpWithResolver.test.ts +180 -0
  61. package/src/authentication/resolvers/signUpWithResolver.ts +65 -0
  62. package/src/authentication/resolvers/verifyChallenge.test.ts +133 -0
  63. package/src/authentication/resolvers/verifyChallenge.ts +62 -0
  64. package/src/authentication/roles.test.ts +49 -0
  65. package/src/authentication/roles.ts +40 -0
  66. package/src/authentication/utils.test.ts +97 -0
  67. package/src/authentication/utils.ts +39 -0
  68. package/src/cache/InMemoryCache.test.ts +62 -0
  69. package/src/cache/InMemoryCache.ts +45 -0
  70. package/src/cron/index.test.ts +17 -0
  71. package/src/cron/index.ts +43 -0
  72. package/src/database/DatabaseController.test.ts +613 -0
  73. package/src/database/DatabaseController.ts +1007 -0
  74. package/src/database/index.test.ts +1372 -0
  75. package/src/database/index.ts +9 -0
  76. package/src/database/interface.ts +302 -0
  77. package/src/email/DevAdapter.ts +7 -0
  78. package/src/email/EmailController.test.ts +29 -0
  79. package/src/email/EmailController.ts +13 -0
  80. package/src/email/index.ts +2 -0
  81. package/src/email/interface.ts +36 -0
  82. package/src/email/templates/sendOtpCode.ts +120 -0
  83. package/src/file/FileController.ts +28 -0
  84. package/src/file/FileDevAdapter.ts +51 -0
  85. package/src/file/hookDeleteFile.ts +25 -0
  86. package/src/file/hookReadFile.ts +66 -0
  87. package/src/file/hookUploadFile.ts +50 -0
  88. package/src/file/index.test.ts +932 -0
  89. package/src/file/index.ts +2 -0
  90. package/src/file/interface.ts +39 -0
  91. package/src/graphql/GraphQLSchema.test.ts +4408 -0
  92. package/src/graphql/GraphQLSchema.ts +880 -0
  93. package/src/graphql/index.ts +2 -0
  94. package/src/graphql/parseGraphqlSchema.ts +85 -0
  95. package/src/graphql/parser.test.ts +203 -0
  96. package/src/graphql/parser.ts +542 -0
  97. package/src/graphql/pointerAndRelationFunction.ts +191 -0
  98. package/src/graphql/resolvers.ts +442 -0
  99. package/src/graphql/tests/aggregation.test.ts +1115 -0
  100. package/src/graphql/tests/e2e.test.ts +590 -0
  101. package/src/graphql/tests/scalars.test.ts +250 -0
  102. package/src/graphql/types.ts +227 -0
  103. package/src/hooks/HookObject.test.ts +122 -0
  104. package/src/hooks/HookObject.ts +165 -0
  105. package/src/hooks/authentication.ts +67 -0
  106. package/src/hooks/createUser.test.ts +77 -0
  107. package/src/hooks/createUser.ts +10 -0
  108. package/src/hooks/defaultFields.test.ts +176 -0
  109. package/src/hooks/defaultFields.ts +32 -0
  110. package/src/hooks/deleteSession.test.ts +181 -0
  111. package/src/hooks/deleteSession.ts +20 -0
  112. package/src/hooks/hashFieldHook.test.ts +152 -0
  113. package/src/hooks/hashFieldHook.ts +89 -0
  114. package/src/hooks/index.test.ts +258 -0
  115. package/src/hooks/index.ts +414 -0
  116. package/src/hooks/permissions.test.ts +412 -0
  117. package/src/hooks/permissions.ts +93 -0
  118. package/src/hooks/protected.test.ts +551 -0
  119. package/src/hooks/protected.ts +60 -0
  120. package/src/hooks/searchableFields.test.ts +147 -0
  121. package/src/hooks/searchableFields.ts +86 -0
  122. package/src/hooks/session.test.ts +134 -0
  123. package/src/hooks/session.ts +76 -0
  124. package/src/hooks/setEmail.test.ts +216 -0
  125. package/src/hooks/setEmail.ts +33 -0
  126. package/src/hooks/setupAcl.test.ts +618 -0
  127. package/src/hooks/setupAcl.ts +25 -0
  128. package/src/index.ts +9 -0
  129. package/src/schema/Schema.test.ts +482 -0
  130. package/src/schema/Schema.ts +757 -0
  131. package/src/schema/defaultResolvers.ts +93 -0
  132. package/src/schema/index.ts +1 -0
  133. package/src/schema/resolvers/meResolver.test.ts +62 -0
  134. package/src/schema/resolvers/meResolver.ts +10 -0
  135. package/src/schema/resolvers/resetPassword.test.ts +341 -0
  136. package/src/schema/resolvers/resetPassword.ts +63 -0
  137. package/src/schema/resolvers/sendEmail.test.ts +118 -0
  138. package/src/schema/resolvers/sendEmail.ts +21 -0
  139. package/src/schema/resolvers/sendOtpCode.test.ts +141 -0
  140. package/src/schema/resolvers/sendOtpCode.ts +52 -0
  141. package/src/security.test.ts +3434 -0
  142. package/src/server/defaultSessionHandler.test.ts +62 -0
  143. package/src/server/defaultSessionHandler.ts +105 -0
  144. package/src/server/generateCodegen.ts +433 -0
  145. package/src/server/index.test.ts +532 -0
  146. package/src/server/index.ts +334 -0
  147. package/src/server/interface.ts +11 -0
  148. package/src/server/routes/authHandler.ts +169 -0
  149. package/src/server/routes/index.ts +39 -0
  150. package/src/utils/crypto.test.ts +41 -0
  151. package/src/utils/crypto.ts +105 -0
  152. package/src/utils/export.ts +11 -0
  153. package/src/utils/helper.ts +204 -0
  154. package/src/utils/index.test.ts +11 -0
  155. package/src/utils/index.ts +189 -0
  156. package/src/utils/preload.ts +8 -0
  157. package/src/utils/testHelper.ts +116 -0
  158. package/tsconfig.json +32 -0
  159. package/bunfig.toml +0 -4
  160. package/dist/ai/index.d.ts +0 -1
  161. package/dist/ai/interface.d.ts +0 -9
  162. /package/dist/server/{defaultHandlers.d.ts → defaultSessionHandler.d.ts} +0 -0
@@ -0,0 +1,442 @@
1
+ import type {
2
+ GraphQLResolveInfo,
3
+ SelectionSetNode,
4
+ FragmentSpreadNode,
5
+ FragmentDefinitionNode,
6
+ } from 'graphql'
7
+ import type { WabeTypes } from '..'
8
+ import type { WabeContext } from '../server/interface'
9
+ import { contextWithoutGraphQLCall, firstLetterInLowerCase } from '../utils'
10
+ import {
11
+ type InputFields,
12
+ type TypeOfExecution,
13
+ add,
14
+ createAndAdd,
15
+ createAndLink,
16
+ remove,
17
+ } from './pointerAndRelationFunction'
18
+
19
+ const expandFragmentSpread = (
20
+ fragmentSpread: FragmentSpreadNode,
21
+ fragments: Record<string, FragmentDefinitionNode>,
22
+ className: string,
23
+ ): Record<string, any> => {
24
+ const fragmentName = fragmentSpread.name.value
25
+ const fragmentDef = fragments[fragmentName]
26
+
27
+ if (!fragmentDef) {
28
+ throw new Error(`Fragment "${fragmentName}" not found`)
29
+ }
30
+
31
+ return extractFieldsFromSetNode(fragmentDef.selectionSet, className, fragments)
32
+ }
33
+
34
+ export const extractFieldsFromSetNode = (
35
+ selectionSet: SelectionSetNode,
36
+ className: string,
37
+ fragments?: Record<string, FragmentDefinitionNode>,
38
+ options?: { ignoreClassField?: boolean },
39
+ ): Record<string, any> => {
40
+ const ignoredFields = ['edges', 'node', 'clientMutationId', 'ok']
41
+ const shouldIgnoreClassField = options?.ignoreClassField ?? true
42
+
43
+ if (shouldIgnoreClassField && className) ignoredFields.push(firstLetterInLowerCase(className))
44
+
45
+ return selectionSet.selections?.reduce(
46
+ (acc, selection) => {
47
+ // Handle fragment spreads
48
+ if (selection.kind === 'FragmentSpread') {
49
+ if (!fragments) {
50
+ throw new Error('Fragment spreads require fragments to be provided')
51
+ }
52
+ const fragmentFields = expandFragmentSpread(
53
+ selection as FragmentSpreadNode,
54
+ fragments,
55
+ className,
56
+ )
57
+ return { ...acc, ...fragmentFields }
58
+ }
59
+
60
+ //@ts-expect-error
61
+ const currentValue = selection.name.value
62
+
63
+ if (selection.selectionSet?.selections && selection.selectionSet?.selections?.length > 0) {
64
+ const res = extractFieldsFromSetNode(selection.selectionSet, className, fragments, {
65
+ ignoreClassField: false,
66
+ })
67
+
68
+ if (ignoredFields.indexOf(currentValue) === -1)
69
+ return {
70
+ ...acc,
71
+ [currentValue]: res,
72
+ }
73
+
74
+ return {
75
+ ...acc,
76
+ ...res,
77
+ }
78
+ }
79
+
80
+ if (ignoredFields.indexOf(currentValue) === -1) acc[currentValue] = true
81
+
82
+ return acc
83
+ },
84
+ {} as Record<string, any>,
85
+ )
86
+ }
87
+
88
+ const getFieldsFromInfo = (info: GraphQLResolveInfo, className: string) => {
89
+ const selectionSet = info.fieldNodes[0]?.selectionSet
90
+
91
+ if (!selectionSet) throw new Error('No output fields provided')
92
+
93
+ const fields = extractFieldsFromSetNode(selectionSet, className, info.fragments)
94
+
95
+ if (!fields) throw new Error('No fields provided')
96
+
97
+ return fields
98
+ }
99
+
100
+ export const getFieldsOfClassName = ({
101
+ fields,
102
+ className,
103
+ context,
104
+ }: {
105
+ fields: string[]
106
+ className: string
107
+ context: WabeContext<any>
108
+ }): {
109
+ classFields: string[]
110
+ othersFields: string[]
111
+ } => {
112
+ const classFields = context.wabe.config.schema?.classes?.find(
113
+ (schemaClass) => schemaClass.name === className,
114
+ )?.fields
115
+
116
+ if (!classFields) return { classFields: [], othersFields: fields }
117
+
118
+ const sameFieldsAsClass = fields.filter((field) => {
119
+ // If the field exist in the class
120
+ // id is automatically include in a class but not provided in fields
121
+ if (classFields[field] || field === 'id') return true
122
+
123
+ // If the name of the field is include in the field provided
124
+ // For example if a pointer field name "Role" is include in the field "role.name"
125
+ if (Object.keys(classFields).find((classField) => field.includes(classField))) return true
126
+
127
+ return false
128
+ })
129
+
130
+ const othersFields = fields.filter((field) => !sameFieldsAsClass.includes(field))
131
+
132
+ return { classFields: sameFieldsAsClass, othersFields }
133
+ }
134
+
135
+ export const executeRelationOnFields = ({
136
+ className,
137
+ fields,
138
+ context,
139
+ id,
140
+ typeOfExecution,
141
+ where,
142
+ }: {
143
+ className: string
144
+ fields: InputFields
145
+ context: WabeContext<any>
146
+ id?: string
147
+ where?: any
148
+ typeOfExecution?: TypeOfExecution
149
+ }) => {
150
+ const entries = Object.entries(fields)
151
+
152
+ return entries.reduce(
153
+ async (acc, [fieldName, value]) => {
154
+ const newAcc = await acc
155
+
156
+ if (value instanceof File) {
157
+ newAcc[fieldName] = value
158
+ } else if (typeof value === 'object' && value?.createAndLink) {
159
+ newAcc[fieldName] = await createAndLink({
160
+ createAndLink: value.createAndLink,
161
+ fieldName,
162
+ context: contextWithoutGraphQLCall(context),
163
+ className,
164
+ })
165
+ } else if (typeof value === 'object' && value?.link) {
166
+ newAcc[fieldName] = value.link
167
+ } else if (typeof value === 'object' && value.unlink) {
168
+ newAcc[fieldName] = null
169
+ } else if (typeof value === 'object' && value?.createAndAdd) {
170
+ newAcc[fieldName] = await createAndAdd({
171
+ createAndAdd: value.createAndAdd,
172
+ fieldName,
173
+ context: contextWithoutGraphQLCall(context),
174
+ className,
175
+ })
176
+ } else if (typeof value === 'object' && value?.add) {
177
+ const addValue = await add({
178
+ add: value.add,
179
+ context: contextWithoutGraphQLCall(context),
180
+ fieldName,
181
+ typeOfExecution: typeOfExecution || 'create',
182
+ id,
183
+ className,
184
+ where,
185
+ })
186
+
187
+ if (addValue) newAcc[fieldName] = addValue
188
+ } else if (typeof value === 'object' && value?.remove) {
189
+ const removeValue = await remove({
190
+ remove: value.remove,
191
+ context: contextWithoutGraphQLCall(context),
192
+ fieldName,
193
+ typeOfExecution: typeOfExecution || 'create',
194
+ id,
195
+ className,
196
+ where,
197
+ })
198
+
199
+ if (removeValue) newAcc[fieldName] = removeValue
200
+ } else {
201
+ newAcc[fieldName] = value
202
+ }
203
+
204
+ return newAcc
205
+ },
206
+ Promise.resolve({}) as Promise<Record<string, any>>,
207
+ )
208
+ }
209
+
210
+ const transformOrder = (order?: Array<string>): Record<string, 'ASC' | 'DESC'> =>
211
+ order?.reduce(
212
+ (acc, currentOrder) => {
213
+ const result = Object.entries(currentOrder)[0]
214
+
215
+ if (!result || !result[0] || !result[1]) return acc
216
+
217
+ // @ts-expect-error
218
+ acc[result[0]] = result[1]
219
+
220
+ return acc
221
+ },
222
+ {} as Record<string, 'ASC' | 'DESC'>,
223
+ ) || {}
224
+
225
+ export const queryForOneObject = (
226
+ _: any,
227
+ { id }: any,
228
+ context: WabeContext<any>,
229
+ info: GraphQLResolveInfo,
230
+ className: keyof WabeTypes['types'],
231
+ ) => {
232
+ const select = getFieldsFromInfo(info, className)
233
+
234
+ return context.wabe.controllers.database.getObject({
235
+ className,
236
+ id,
237
+ select,
238
+ context,
239
+ })
240
+ }
241
+
242
+ export const queryForMultipleObject = async (
243
+ _: any,
244
+ { where, offset, first, order }: any,
245
+ context: WabeContext<any>,
246
+ info: GraphQLResolveInfo,
247
+ className: keyof WabeTypes['types'],
248
+ ) => {
249
+ const select = getFieldsFromInfo(info, className)
250
+
251
+ const { totalCount, ...selectWithoutTotalCount } = select
252
+
253
+ const objects = await context.wabe.controllers.database.getObjects({
254
+ className,
255
+ where,
256
+ select: selectWithoutTotalCount,
257
+ offset,
258
+ first,
259
+ context,
260
+ order: transformOrder(order),
261
+ })
262
+
263
+ return {
264
+ totalCount: totalCount
265
+ ? await context.wabe.controllers.database.count({
266
+ className,
267
+ where,
268
+ context,
269
+ })
270
+ : undefined,
271
+ edges: objects.map((object: any) => ({
272
+ node: object,
273
+ })),
274
+ }
275
+ }
276
+
277
+ export const mutationToCreateObject = async (
278
+ _: any,
279
+ args: any,
280
+ context: WabeContext<any>,
281
+ info: GraphQLResolveInfo,
282
+ className: keyof WabeTypes['types'],
283
+ ) => {
284
+ const select = getFieldsFromInfo(info, className)
285
+
286
+ const updatedFieldsToCreate = await executeRelationOnFields({
287
+ className,
288
+ fields: args.input?.fields,
289
+ context,
290
+ })
291
+
292
+ return {
293
+ [firstLetterInLowerCase(className)]: await context.wabe.controllers.database.createObject({
294
+ className,
295
+ data: updatedFieldsToCreate,
296
+ select,
297
+ context,
298
+ }),
299
+ ok: true,
300
+ }
301
+ }
302
+
303
+ export const mutationToCreateMultipleObjects = async (
304
+ _: any,
305
+ { input: { fields, offset, first, order } }: any,
306
+ context: WabeContext<any>,
307
+ info: GraphQLResolveInfo,
308
+ className: keyof WabeTypes['types'],
309
+ ) => {
310
+ const select = getFieldsFromInfo(info, className)
311
+ const inputFields = fields as Array<any>
312
+
313
+ const updatedFieldsToCreate = await Promise.all(
314
+ inputFields.map((inputField) =>
315
+ executeRelationOnFields({
316
+ className,
317
+ fields: inputField,
318
+ context,
319
+ }),
320
+ ),
321
+ )
322
+
323
+ const objects = await context.wabe.controllers.database.createObjects({
324
+ className,
325
+ data: updatedFieldsToCreate,
326
+ select,
327
+ offset,
328
+ first,
329
+ context,
330
+ order: transformOrder(order),
331
+ })
332
+
333
+ return {
334
+ edges: objects.map((object: any) => ({ node: object })),
335
+ }
336
+ }
337
+
338
+ export const mutationToUpdateObject = async (
339
+ _: any,
340
+ args: any,
341
+ context: WabeContext<any>,
342
+ info: GraphQLResolveInfo,
343
+ className: keyof WabeTypes['types'],
344
+ ) => {
345
+ const select = getFieldsFromInfo(info, className)
346
+
347
+ const updatedFields = await executeRelationOnFields({
348
+ className,
349
+ fields: args.input?.fields,
350
+ context,
351
+ id: args.input?.id,
352
+ typeOfExecution: 'update',
353
+ })
354
+
355
+ return {
356
+ [firstLetterInLowerCase(className)]: await context.wabe.controllers.database.updateObject({
357
+ className,
358
+ id: args.input?.id,
359
+ data: updatedFields,
360
+ select,
361
+ context,
362
+ }),
363
+ ok: true,
364
+ }
365
+ }
366
+
367
+ export const mutationToUpdateMultipleObjects = async (
368
+ _: any,
369
+ { input: { fields, where, offset, first, order } }: any,
370
+ context: WabeContext<any>,
371
+ info: GraphQLResolveInfo,
372
+ className: keyof WabeTypes['types'],
373
+ ) => {
374
+ const select = getFieldsFromInfo(info, className)
375
+
376
+ const updatedFields = await executeRelationOnFields({
377
+ className,
378
+ fields,
379
+ context,
380
+ typeOfExecution: 'updateMany',
381
+ where,
382
+ })
383
+
384
+ const objects = await context.wabe.controllers.database.updateObjects({
385
+ className,
386
+ where,
387
+ data: updatedFields,
388
+ select,
389
+ offset,
390
+ first,
391
+ context,
392
+ order,
393
+ })
394
+
395
+ return {
396
+ edges: objects.map((object: any) => ({ node: object })),
397
+ }
398
+ }
399
+
400
+ export const mutationToDeleteObject = async (
401
+ _: any,
402
+ args: any,
403
+ context: WabeContext<any>,
404
+ info: GraphQLResolveInfo,
405
+ className: keyof WabeTypes['types'],
406
+ ) => {
407
+ const select = getFieldsFromInfo(info, className)
408
+
409
+ return {
410
+ [firstLetterInLowerCase(className)]: await context.wabe.controllers.database.deleteObject({
411
+ className,
412
+ id: args.input?.id,
413
+ select,
414
+ context,
415
+ }),
416
+ ok: true,
417
+ }
418
+ }
419
+
420
+ export const mutationToDeleteMultipleObjects = async (
421
+ _: any,
422
+ { input: { where, offset, first, order } }: any,
423
+ context: WabeContext<any>,
424
+ info: GraphQLResolveInfo,
425
+ className: keyof WabeTypes['types'],
426
+ ) => {
427
+ const select = getFieldsFromInfo(info, className)
428
+
429
+ const objects = await context.wabe.controllers.database.deleteObjects({
430
+ className,
431
+ where,
432
+ select,
433
+ offset,
434
+ first,
435
+ context,
436
+ order,
437
+ })
438
+
439
+ return {
440
+ edges: objects.map((object: any) => ({ node: object })),
441
+ }
442
+ }