vona-cli-set-api 1.0.172 → 1.0.176

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 (39) hide show
  1. package/cli/templates/create/project/basic/boilerplate/_.gitignore +0 -1
  2. package/cli/templates/create/project/basic/boilerplate/env/.env +1 -1
  3. package/cli/templates/create/project/basic/boilerplate/package.original.json +3 -3
  4. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-base/src/.metadata/index.ts +3 -0
  5. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-base/src/main.ts +16 -0
  6. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/.metadata/index.ts +135 -2
  7. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.activate.ts +28 -0
  8. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.emailConfirmCallback.ts +24 -0
  9. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.passwordResetCallback.ts +22 -0
  10. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.register.ts +23 -0
  11. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/meta.version.ts +9 -10
  12. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.emailUnique.ts +20 -0
  13. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.passwordConfirm.ts +20 -0
  14. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.usernameUnique.ts +20 -0
  15. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/config.ts +3 -0
  16. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/locale/en-us.ts +9 -0
  17. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/locale/zh-cn.ts +9 -0
  18. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/controller/passport.ts +19 -8
  19. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/auth.ts +1 -1
  20. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/login.ts +18 -0
  21. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/register.ts +26 -0
  22. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/entity/roleUser.ts +2 -1
  23. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/entity/user.ts +9 -0
  24. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/lib/authAdapter.ts +1 -1
  25. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/lib/roleAdapter.ts +1 -1
  26. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/lib/userAdapter.ts +14 -2
  27. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/service/userInnerAdapter.ts +16 -6
  28. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/types/passport.ts +1 -1
  29. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/types/user.ts +3 -0
  30. package/cli/templates/tools/crud/boilerplate/src/controller/{{resourceName}}.ts_ +2 -4
  31. package/cli/templates/tools/crud/boilerplate/src/dto/{{resourceName}}Query.ts_ +4 -2
  32. package/cli/templates/tools/crud/boilerplate/src/service/{{resourceName}}.ts_ +2 -1
  33. package/dist/lib/bean/cli.tools.metadata.js +1 -0
  34. package/dist/lib/bean/toolsBin/generateEntryFiles.js +3 -0
  35. package/dist/lib/bean/toolsBin/generateZod.d.ts +2 -0
  36. package/dist/lib/bean/toolsBin/generateZod.js +48 -0
  37. package/dist/lib/utils.d.ts +1 -0
  38. package/dist/lib/utils.js +5 -0
  39. package/package.json +2 -2
@@ -32,7 +32,6 @@ src/backend/typing/mine.d.ts
32
32
  # auto created
33
33
  .rollup.cache
34
34
  .temp-dynamic-*
35
- /cabloy.json
36
35
  /package.json
37
36
 
38
37
  /docker-compose
@@ -40,7 +40,7 @@ BUILD_COPY_RELEASE =
40
40
  TEST_CONCURRENCY = true
41
41
  TEST_ONLY = false
42
42
  TEST_WHYISNODERUNNING = false
43
- TEST_PATTERNS_IGNORE = '**/test-vona/test/cache/cacheMem.test.ts,**/test-vona/test/cache/cacheRedis.test.ts,**/test-vona/test/cache/summer.test.ts'
43
+ TEST_PATTERNS_IGNORE = '**/test-vona/test/cache/cacheMem.test.ts,**/test-vona/test/cache/cacheRedis.test.ts,**/test-vona/test/cache/summer.test.ts,**/test-vona/test/mail.test.ts'
44
44
 
45
45
  # database
46
46
 
@@ -22,7 +22,7 @@
22
22
  "node": ">=24.1.0"
23
23
  },
24
24
  "scripts": {
25
- "init": "pnpm install --no-frozen-lockfile && npm run prerun && pnpm install --no-frozen-lockfile",
25
+ "init": "pnpm install --no-frozen-lockfile && npm run prerun && pnpm install --no-frozen-lockfile && pnpm dedupe",
26
26
  "demo": "vona :bin:demo --flavor=normal",
27
27
  "db:reset": "npm run prerun && vona :bin:dbReset --flavor=normal",
28
28
  "dev": "npm run prerun && vona :bin:dev --workers=2 --flavor=normal",
@@ -45,10 +45,10 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "vona": "^5.0.102"
48
+ "vona": "^5.0.104"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@cabloy/lint": "^5.0.16",
52
- "eslint": "^9.20.1"
52
+ "eslint": "^9.35.0"
53
53
  }
54
54
  }
@@ -81,6 +81,9 @@ declare module 'vona-module-a-web' {
81
81
 
82
82
  }
83
83
  /** controller: end */
84
+ /** main: begin */
85
+ export * from '../main.ts';
86
+ /** main: end */
84
87
  /** scope: begin */
85
88
  import { BeanScopeBase, type BeanScopeUtil } from 'vona';
86
89
  import { Scope } from 'vona-module-a-bean';
@@ -0,0 +1,16 @@
1
+ import type { IModuleMain } from 'vona';
2
+ import { BeanSimple } from 'vona';
3
+ import { en, zhCN } from 'zod/locales';
4
+
5
+ export class Main extends BeanSimple implements IModuleMain {
6
+ async moduleLoading() {}
7
+ async moduleLoaded() {
8
+ const localeErrors = {
9
+ 'en-us': en,
10
+ 'zh-cn': zhCN,
11
+ };
12
+ this.app.util.setLocaleErrors(localeErrors, this.bean.scope('a-i18n').config.i18n.defaultLocale);
13
+ }
14
+
15
+ async configLoaded(_config: any) {}
16
+ }
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable */
2
2
  import type { TypeEntityMeta,TypeModelsClassLikeGeneral,TypeSymbolKeyFieldsMore,IModelRelationBelongsToMany } from 'vona-module-a-orm';
3
3
  import type { TypeEntityOptionsFields,TypeControllerOptionsActions } from 'vona-module-a-openapi';
4
+ import type { TableIdentity } from 'table-identity';
4
5
  /** entity: begin */
5
6
  export * from '../entity/role.ts';
6
7
  export * from '../entity/roleUser.ts';
@@ -135,7 +136,7 @@ declare module 'vona' {
135
136
  }
136
137
  /** model: end */
137
138
  /** model: begin */
138
- import type { IModelGetOptions, IModelMethodOptions, IModelSelectParams, TableIdentity, TypeModelRelationResult, TypeModelWhere, IModelInsertOptions, TypeModelMutateRelationData, IModelDeleteOptions, IModelUpdateOptions, IModelMutateOptions, IModelSelectCountParams, IModelSelectAggrParams, TypeModelAggrRelationResult, IModelSelectGroupParams, TypeModelGroupRelationResult } from 'vona-module-a-orm';
139
+ import type { IModelGetOptions, IModelMethodOptions, IModelSelectParams, TypeModelSelectAndCount, TypeModelRelationResult, TypeModelWhere, IModelInsertOptions, TypeModelMutateRelationData, IModelDeleteOptions, IModelUpdateOptions, IModelMutateOptions, IModelSelectCountParams, IModelSelectAggrParams, TypeModelAggrRelationResult, IModelSelectGroupParams, TypeModelGroupRelationResult } from 'vona-module-a-orm';
139
140
  import { SymbolKeyEntity, SymbolKeyEntityMeta, SymbolKeyModelOptions } from 'vona-module-a-orm';
140
141
  declare module 'vona-module-home-user' {
141
142
  export interface IModelOptionsUser {
@@ -149,6 +150,7 @@ declare module 'vona-module-home-user' {
149
150
  [SymbolKeyModelOptions]: IModelOptionsRole;
150
151
  get<T extends IModelGetOptions<EntityRole,ModelRole>>(where: TypeModelWhere<EntityRole>, options?: T): Promise<TypeModelRelationResult<EntityRole, ModelRole, T> | undefined>;
151
152
  mget<T extends IModelGetOptions<EntityRole,ModelRole>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityRole, ModelRole, T>[]>;
153
+ selectAndCount<T extends IModelSelectParams<EntityRole,ModelRole,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityRole, ModelRole, T>>;
152
154
  select<T extends IModelSelectParams<EntityRole,ModelRole,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityRole, ModelRole, T>[]>;
153
155
  insert<T extends IModelInsertOptions<EntityRole,ModelRole>>(data?: TypeModelMutateRelationData<EntityRole,ModelRole, T>, options?: T): Promise<TypeModelMutateRelationData<EntityRole,ModelRole, T, true>>;
154
156
  insertBulk<T extends IModelInsertOptions<EntityRole,ModelRole>>(items: TypeModelMutateRelationData<EntityRole,ModelRole, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityRole,ModelRole, T, true>[]>;
@@ -168,6 +170,7 @@ export interface ModelRoleUser {
168
170
  [SymbolKeyModelOptions]: IModelOptionsRoleUser;
169
171
  get<T extends IModelGetOptions<EntityRoleUser,ModelRoleUser>>(where: TypeModelWhere<EntityRoleUser>, options?: T): Promise<TypeModelRelationResult<EntityRoleUser, ModelRoleUser, T> | undefined>;
170
172
  mget<T extends IModelGetOptions<EntityRoleUser,ModelRoleUser>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityRoleUser, ModelRoleUser, T>[]>;
173
+ selectAndCount<T extends IModelSelectParams<EntityRoleUser,ModelRoleUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityRoleUser, ModelRoleUser, T>>;
171
174
  select<T extends IModelSelectParams<EntityRoleUser,ModelRoleUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityRoleUser, ModelRoleUser, T>[]>;
172
175
  insert<T extends IModelInsertOptions<EntityRoleUser,ModelRoleUser>>(data?: TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T>, options?: T): Promise<TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T, true>>;
173
176
  insertBulk<T extends IModelInsertOptions<EntityRoleUser,ModelRoleUser>>(items: TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityRoleUser,ModelRoleUser, T, true>[]>;
@@ -187,6 +190,7 @@ export interface ModelUser {
187
190
  [SymbolKeyModelOptions]: IModelOptionsUser;
188
191
  get<T extends IModelGetOptions<EntityUser,ModelUser>>(where: TypeModelWhere<EntityUser>, options?: T): Promise<TypeModelRelationResult<EntityUser, ModelUser, T> | undefined>;
189
192
  mget<T extends IModelGetOptions<EntityUser,ModelUser>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityUser, ModelUser, T>[]>;
193
+ selectAndCount<T extends IModelSelectParams<EntityUser,ModelUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityUser, ModelUser, T>>;
190
194
  select<T extends IModelSelectParams<EntityUser,ModelUser,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityUser, ModelUser, T>[]>;
191
195
  insert<T extends IModelInsertOptions<EntityUser,ModelUser>>(data?: TypeModelMutateRelationData<EntityUser,ModelUser, T>, options?: T): Promise<TypeModelMutateRelationData<EntityUser,ModelUser, T, true>>;
192
196
  insertBulk<T extends IModelInsertOptions<EntityUser,ModelUser>>(items: TypeModelMutateRelationData<EntityUser,ModelUser, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityUser,ModelUser, T, true>[]>;
@@ -294,6 +298,67 @@ declare module 'vona' {
294
298
  }
295
299
  }
296
300
  /** service: end */
301
+ /** eventListener: begin */
302
+ export * from '../bean/eventListener.activate.ts';
303
+ export * from '../bean/eventListener.emailConfirmCallback.ts';
304
+ export * from '../bean/eventListener.passwordResetCallback.ts';
305
+ export * from '../bean/eventListener.register.ts';
306
+
307
+ import { type IDecoratorEventListenerOptions } from 'vona-module-a-event';
308
+ declare module 'vona-module-a-event' {
309
+
310
+ export interface IEventListenerRecord {
311
+ 'home-user:activate': IDecoratorEventListenerOptions;
312
+ 'home-user:emailConfirmCallback': IDecoratorEventListenerOptions;
313
+ 'home-user:passwordResetCallback': IDecoratorEventListenerOptions;
314
+ 'home-user:register': IDecoratorEventListenerOptions;
315
+ }
316
+
317
+
318
+ }
319
+ declare module 'vona-module-home-user' {
320
+
321
+ export interface EventListenerActivate {
322
+ /** @internal */
323
+ get scope(): ScopeModuleHomeUser;
324
+ }
325
+
326
+ export interface EventListenerActivate {
327
+ get $beanFullName(): 'home-user.eventListener.activate';
328
+ get $onionName(): 'home-user:activate';
329
+ }
330
+
331
+ export interface EventListenerEmailConfirmCallback {
332
+ /** @internal */
333
+ get scope(): ScopeModuleHomeUser;
334
+ }
335
+
336
+ export interface EventListenerEmailConfirmCallback {
337
+ get $beanFullName(): 'home-user.eventListener.emailConfirmCallback';
338
+ get $onionName(): 'home-user:emailConfirmCallback';
339
+ }
340
+
341
+ export interface EventListenerPasswordResetCallback {
342
+ /** @internal */
343
+ get scope(): ScopeModuleHomeUser;
344
+ }
345
+
346
+ export interface EventListenerPasswordResetCallback {
347
+ get $beanFullName(): 'home-user.eventListener.passwordResetCallback';
348
+ get $onionName(): 'home-user:passwordResetCallback';
349
+ }
350
+
351
+ export interface EventListenerRegister {
352
+ /** @internal */
353
+ get scope(): ScopeModuleHomeUser;
354
+ }
355
+
356
+ export interface EventListenerRegister {
357
+ get $beanFullName(): 'home-user.eventListener.register';
358
+ get $onionName(): 'home-user:register';
359
+ }
360
+ }
361
+ /** eventListener: end */
297
362
  /** meta: begin */
298
363
  export * from '../bean/meta.index.ts';
299
364
  export * from '../bean/meta.version.ts';
@@ -333,18 +398,24 @@ declare module 'vona-module-home-user' {
333
398
  /** meta: end */
334
399
  /** dto: begin */
335
400
  export * from '../dto/auth.ts';
401
+ export * from '../dto/login.ts';
336
402
  export * from '../dto/passport.ts';
337
403
  export * from '../dto/passportJwt.ts';
404
+ export * from '../dto/register.ts';
338
405
  import type { IDtoOptionsAuth } from '../dto/auth.ts';
406
+ import type { IDtoOptionsLogin } from '../dto/login.ts';
339
407
  import type { IDtoOptionsPassport } from '../dto/passport.ts';
340
408
  import type { IDtoOptionsPassportJwt } from '../dto/passportJwt.ts';
409
+ import type { IDtoOptionsRegister } from '../dto/register.ts';
341
410
  import 'vona';
342
411
  declare module 'vona-module-a-web' {
343
412
 
344
413
  export interface IDtoRecord {
345
414
  'home-user:auth': IDtoOptionsAuth;
415
+ 'home-user:login': IDtoOptionsLogin;
346
416
  'home-user:passport': IDtoOptionsPassport;
347
417
  'home-user:passportJwt': IDtoOptionsPassportJwt;
418
+ 'home-user:register': IDtoOptionsRegister;
348
419
  }
349
420
 
350
421
 
@@ -355,14 +426,20 @@ declare module 'vona-module-home-user' {
355
426
  /** dto: end */
356
427
  /** dto: begin */
357
428
  import type { DtoAuth } from '../dto/auth.ts';
429
+ import type { DtoLogin } from '../dto/login.ts';
358
430
  import type { DtoPassport } from '../dto/passport.ts';
359
- import type { DtoPassportJwt } from '../dto/passportJwt.ts';
431
+ import type { DtoPassportJwt } from '../dto/passportJwt.ts';
432
+ import type { DtoRegister } from '../dto/register.ts';
360
433
  declare module 'vona-module-home-user' {
361
434
 
362
435
  export interface IDtoOptionsAuth {
363
436
  fields?: TypeEntityOptionsFields<DtoAuth, IDtoOptionsAuth[TypeSymbolKeyFieldsMore]>;
364
437
  }
365
438
 
439
+ export interface IDtoOptionsLogin {
440
+ fields?: TypeEntityOptionsFields<DtoLogin, IDtoOptionsLogin[TypeSymbolKeyFieldsMore]>;
441
+ }
442
+
366
443
  export interface IDtoOptionsPassport {
367
444
  fields?: TypeEntityOptionsFields<DtoPassport, IDtoOptionsPassport[TypeSymbolKeyFieldsMore]>;
368
445
  }
@@ -370,6 +447,10 @@ declare module 'vona-module-home-user' {
370
447
  export interface IDtoOptionsPassportJwt {
371
448
  fields?: TypeEntityOptionsFields<DtoPassportJwt, IDtoOptionsPassportJwt[TypeSymbolKeyFieldsMore]>;
372
449
  }
450
+
451
+ export interface IDtoOptionsRegister {
452
+ fields?: TypeEntityOptionsFields<DtoRegister, IDtoOptionsRegister[TypeSymbolKeyFieldsMore]>;
453
+ }
373
454
  }
374
455
  /** dto: end */
375
456
  /** controller: begin */
@@ -415,6 +496,7 @@ declare module 'vona-module-a-web' {
415
496
  }
416
497
  export interface IApiPathPostRecord{
417
498
  '/home/user/passport/logout': undefined;
499
+ '/home/user/passport/register': undefined;
418
500
  '/home/user/passport/login': undefined;
419
501
  '/home/user/passport/refreshAuthToken': undefined;
420
502
  '/home/user/passport/createPassportJwtFromOauthCode': undefined;
@@ -423,6 +505,57 @@ export interface IApiPathPostRecord{
423
505
 
424
506
  }
425
507
  /** controller: end */
508
+ /** zodRefine: begin */
509
+ export * from '../bean/zodRefine.emailUnique.ts';
510
+ export * from '../bean/zodRefine.passwordConfirm.ts';
511
+ export * from '../bean/zodRefine.usernameUnique.ts';
512
+ import type { IZodRefineOptionsEmailUnique } from '../bean/zodRefine.emailUnique.ts';
513
+ import type { IZodRefineOptionsPasswordConfirm } from '../bean/zodRefine.passwordConfirm.ts';
514
+ import type { IZodRefineOptionsUsernameUnique } from '../bean/zodRefine.usernameUnique.ts';
515
+ import 'vona';
516
+ declare module 'vona-module-a-zod' {
517
+
518
+ export interface IZodRefineRecord {
519
+ 'home-user:emailUnique': IZodRefineOptionsEmailUnique;
520
+ 'home-user:passwordConfirm': IZodRefineOptionsPasswordConfirm;
521
+ 'home-user:usernameUnique': IZodRefineOptionsUsernameUnique;
522
+ }
523
+
524
+
525
+ }
526
+ declare module 'vona-module-home-user' {
527
+
528
+ export interface ZodRefineEmailUnique {
529
+ /** @internal */
530
+ get scope(): ScopeModuleHomeUser;
531
+ }
532
+
533
+ export interface ZodRefineEmailUnique {
534
+ get $beanFullName(): 'home-user.zodRefine.emailUnique';
535
+ get $onionName(): 'home-user:emailUnique';
536
+ }
537
+
538
+ export interface ZodRefinePasswordConfirm {
539
+ /** @internal */
540
+ get scope(): ScopeModuleHomeUser;
541
+ }
542
+
543
+ export interface ZodRefinePasswordConfirm {
544
+ get $beanFullName(): 'home-user.zodRefine.passwordConfirm';
545
+ get $onionName(): 'home-user:passwordConfirm';
546
+ }
547
+
548
+ export interface ZodRefineUsernameUnique {
549
+ /** @internal */
550
+ get scope(): ScopeModuleHomeUser;
551
+ }
552
+
553
+ export interface ZodRefineUsernameUnique {
554
+ get $beanFullName(): 'home-user.zodRefine.usernameUnique';
555
+ get $onionName(): 'home-user:usernameUnique';
556
+ }
557
+ }
558
+ /** zodRefine: end */
426
559
  /** config: begin */
427
560
  export * from '../config/config.ts';
428
561
  import type { config } from '../config/config.ts';
@@ -0,0 +1,28 @@
1
+ import type { IEventExecute, NextEvent } from 'vona-module-a-event';
2
+ import type { TypeEventActivateData, TypeEventActivateResult } from 'vona-module-a-user';
3
+ import type { IUser } from '../types/user.ts';
4
+ import { BeanBase } from 'vona';
5
+ import { EventListener } from 'vona-module-a-event';
6
+
7
+ type TypeEventData = TypeEventActivateData;
8
+ type TypeEventResult = TypeEventActivateResult;
9
+
10
+ @EventListener({ match: 'a-user:activate' })
11
+ export class EventListenerActivate
12
+ extends BeanBase
13
+ implements IEventExecute<TypeEventData, TypeEventResult> {
14
+ async execute(data: TypeEventData, next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
15
+ const user = data as IUser;
16
+ if (user.name === 'admin') {
17
+ // role: admin
18
+ const roleAdmin = await this.scope.model.role.get({ name: 'admin' });
19
+ // userRole: admin
20
+ await this.scope.model.roleUser.insert({
21
+ userId: user.id,
22
+ roleId: roleAdmin!.id,
23
+ });
24
+ }
25
+ // next
26
+ return next();
27
+ }
28
+ }
@@ -0,0 +1,24 @@
1
+ import type { IEventExecute, NextEvent } from 'vona-module-a-event';
2
+ import type { TypeEventEmailConfirmCallbackData, TypeEventEmailConfirmCallbackResult } from 'vona-module-a-mailconfirm';
3
+ import { BeanBase } from 'vona';
4
+ import { EventListener } from 'vona-module-a-event';
5
+
6
+ type TypeEventData = TypeEventEmailConfirmCallbackData;
7
+ type TypeEventResult = TypeEventEmailConfirmCallbackResult;
8
+
9
+ @EventListener({ match: 'a-mailconfirm:emailConfirmCallback' })
10
+ export class EventListenerEmailConfirmCallback
11
+ extends BeanBase
12
+ implements IEventExecute<TypeEventData, TypeEventResult> {
13
+ async execute(data: TypeEventData, _next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
14
+ // check cache
15
+ if (!data) {
16
+ return this.scope.locale.ConfirmationEmailExpired();
17
+ }
18
+ // activate
19
+ const user = await this.bean.userInner.findOne({ id: data.userId });
20
+ await this.bean.userInner.activate(user!);
21
+ // ok
22
+ return this.scope.locale.ConfirmationEmailSucceeded();
23
+ }
24
+ }
@@ -0,0 +1,22 @@
1
+ import type { IEventExecute, NextEvent } from 'vona-module-a-event';
2
+ import type { TypeEventPasswordResetCallbackData, TypeEventPasswordResetCallbackResult } from 'vona-module-a-mailconfirm';
3
+ import { BeanBase } from 'vona';
4
+ import { EventListener } from 'vona-module-a-event';
5
+
6
+ type TypeEventData = TypeEventPasswordResetCallbackData;
7
+ type TypeEventResult = TypeEventPasswordResetCallbackResult;
8
+
9
+ @EventListener({ match: 'a-mailconfirm:passwordResetCallback' })
10
+ export class EventListenerPasswordResetCallback
11
+ extends BeanBase
12
+ implements IEventExecute<TypeEventData, TypeEventResult> {
13
+ async execute(data: TypeEventData, _next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
14
+ // check cache
15
+ if (!data) {
16
+ return this.scope.locale.PasswordResetEmailExpired();
17
+ }
18
+ // maybe mock captcha token2 to do secendary verify
19
+ // todo: redirect to frontend
20
+ throw new Error('Not Implemented');
21
+ }
22
+ }
@@ -0,0 +1,23 @@
1
+ import type { IEventExecute, NextEvent } from 'vona-module-a-event';
2
+ import type { TypeEventRegisterData, TypeEventRegisterResult } from 'vona-module-a-user';
3
+ import type { IUser } from '../types/user.ts';
4
+ import { BeanBase } from 'vona';
5
+ import { EventListener } from 'vona-module-a-event';
6
+
7
+ type TypeEventData = TypeEventRegisterData;
8
+ type TypeEventResult = TypeEventRegisterResult;
9
+
10
+ @EventListener({ match: 'a-user:register' })
11
+ export class EventListenerRegister
12
+ extends BeanBase
13
+ implements IEventExecute<TypeEventData, TypeEventResult> {
14
+ async execute(data: TypeEventData, next: NextEvent<TypeEventData, TypeEventResult>): Promise<TypeEventResult> {
15
+ // next: registered
16
+ const user = await next() as IUser;
17
+ // mail: activate
18
+ if (!data.autoActivate && user.email) {
19
+ await this.$scope.mailconfirm.service.mail.emailConfirm(user);
20
+ }
21
+ return user;
22
+ }
23
+ }
@@ -20,6 +20,9 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate, IMetaVe
20
20
  table.basicFields();
21
21
  table.string(entityUser.name, 255).comment(entityUser.$comment.name);
22
22
  table.string(entityUser.avatar, 255).comment(entityUser.$comment.avatar);
23
+ table.string(entityUser.email, 255).comment(entityUser.$comment.email);
24
+ table.string(entityUser.mobile, 255).comment(entityUser.$comment.mobile);
25
+ table.boolean(entityUser.activated).defaultTo(entityUser.$default.activated).comment(entityUser.$comment.activated);
23
26
  table.string(entityUser.locale, 255).comment(entityUser.$comment.locale);
24
27
  });
25
28
  // homeRoleUser
@@ -35,20 +38,16 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate, IMetaVe
35
38
  async init(options: IMetaVersionInitOptions) {
36
39
  if (options.version === 1) {
37
40
  // role: admin
38
- const roleAdmin = await this.scope.model.role.insert({
41
+ await this.scope.model.role.insert({
39
42
  name: 'admin',
40
43
  });
41
44
  // user: admin
42
- const userAdmin = await this.scope.model.user.insert({
43
- name: 'admin',
45
+ await this.bean.authSimple.authenticate({
46
+ username: 'admin',
47
+ password: options.password || this.scope.config.passwordDefault.admin,
44
48
  avatar: ':emoji:flower',
45
- locale: undefined,
46
- });
47
- // userRole: admin
48
- await this.scope.model.roleUser.insert({
49
- userId: userAdmin.id,
50
- roleId: roleAdmin.id,
51
- });
49
+ confirmed: true,
50
+ }, 'register', 'default');
52
51
  }
53
52
  }
54
53
  }
@@ -0,0 +1,20 @@
1
+ import type { IDecoratorZodRefineOptions, IZodRefineExecute, TypeRefinementCtx } from 'vona-module-a-zod';
2
+ import { BeanBase } from 'vona';
3
+ import { ZodRefine } from 'vona-module-a-zod';
4
+
5
+ export type TypeZodRefineEmailUniqueData = string;
6
+
7
+ export interface IZodRefineOptionsEmailUnique extends IDecoratorZodRefineOptions {}
8
+
9
+ @ZodRefine<IZodRefineOptionsEmailUnique>()
10
+ export class ZodRefineEmailUnique extends BeanBase implements IZodRefineExecute<TypeZodRefineEmailUniqueData> {
11
+ async execute(value: TypeZodRefineEmailUniqueData, refinementCtx: TypeRefinementCtx, _options: IZodRefineOptionsEmailUnique) {
12
+ const user = await this.scope.model.user.get({ email: { _eqI_: value } });
13
+ if (user) {
14
+ refinementCtx.addIssue({
15
+ code: 'custom',
16
+ message: this.scope.locale.EmailExists(),
17
+ });
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ import type { IDecoratorZodRefineOptions, IZodRefineExecute, TypeRefinementCtx } from 'vona-module-a-zod';
2
+ import { BeanBase } from 'vona';
3
+ import { ZodRefine } from 'vona-module-a-zod';
4
+
5
+ export interface TypeZodRefinePasswordConfirmData { password: string; passwordConfirm: string }
6
+
7
+ export interface IZodRefineOptionsPasswordConfirm extends IDecoratorZodRefineOptions {}
8
+
9
+ @ZodRefine<IZodRefineOptionsPasswordConfirm>()
10
+ export class ZodRefinePasswordConfirm extends BeanBase implements IZodRefineExecute<TypeZodRefinePasswordConfirmData> {
11
+ async execute(value: TypeZodRefinePasswordConfirmData, refinementCtx: TypeRefinementCtx, _options: IZodRefineOptionsPasswordConfirm) {
12
+ if (value.password !== value.passwordConfirm) {
13
+ refinementCtx.addIssue({
14
+ code: 'custom',
15
+ message: this.scope.locale.PasswordsNotMatch(),
16
+ path: ['passwordConfirm'],
17
+ });
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ import type { IDecoratorZodRefineOptions, IZodRefineExecute, TypeRefinementCtx } from 'vona-module-a-zod';
2
+ import { BeanBase } from 'vona';
3
+ import { ZodRefine } from 'vona-module-a-zod';
4
+
5
+ export type TypeZodRefineUsernameUniqueData = string;
6
+
7
+ export interface IZodRefineOptionsUsernameUnique extends IDecoratorZodRefineOptions {}
8
+
9
+ @ZodRefine<IZodRefineOptionsUsernameUnique>()
10
+ export class ZodRefineUsernameUnique extends BeanBase implements IZodRefineExecute<TypeZodRefineUsernameUniqueData> {
11
+ async execute(value: TypeZodRefineUsernameUniqueData, refinementCtx: TypeRefinementCtx, _options: IZodRefineOptionsUsernameUnique) {
12
+ const user = await this.bean.userInner.findOneByName(value);
13
+ if (user) {
14
+ refinementCtx.addIssue({
15
+ code: 'custom',
16
+ message: this.scope.locale.UsernameExists(),
17
+ });
18
+ }
19
+ }
20
+ }
@@ -3,6 +3,9 @@ import type { IServiceRecord } from 'vona-module-a-bean';
3
3
 
4
4
  export function config(_app: VonaApplication) {
5
5
  return {
6
+ passwordDefault: {
7
+ admin: '123456',
8
+ },
6
9
  adapter: {
7
10
  authInner: 'a-auth:authInnerAdapter' as keyof IServiceRecord,
8
11
  },
@@ -1,8 +1,17 @@
1
1
  export default {
2
+ ConfirmationEmailExpired: 'This email confirmation link has expired',
3
+ ConfirmationEmailSucceeded: 'Your email address has been confirmed',
4
+ PasswordResetEmailExpired: 'This password reset link has expired',
2
5
  Role: 'Role',
3
6
  RoleName: 'Role Name',
4
7
  User: 'User',
5
8
  UserName: 'User Name',
6
9
  UserAvatar: 'Avatar',
10
+ UserEmail: 'Email',
11
+ UserMobile: 'Mobile',
12
+ UserActivated: 'Activated',
7
13
  UserLocale: 'Language',
14
+ UsernameExists: 'Username Exists',
15
+ EmailExists: 'Email Exists',
16
+ PasswordsNotMatch: 'Passwords do not match',
8
17
  };
@@ -1,8 +1,17 @@
1
1
  export default {
2
+ ConfirmationEmailExpired: '确认邮件链接已经过期',
3
+ ConfirmationEmailSucceeded: '您的邮件地址已经确认',
4
+ PasswordResetEmailExpired: '重置密码链接已经过期',
2
5
  Role: '角色',
3
6
  RoleName: '角色名',
4
7
  User: '用户',
5
8
  UserName: '用户名',
6
9
  UserAvatar: '头像',
10
+ UserEmail: '电子邮件',
11
+ UserMobile: '手机号',
12
+ UserActivated: '已激活',
7
13
  UserLocale: '语言',
14
+ UsernameExists: '用户名已存在',
15
+ EmailExists: '电子邮件已存在',
16
+ PasswordsNotMatch: '密码不一致',
8
17
  };
@@ -4,14 +4,16 @@ import type { IDecoratorControllerOptions } from 'vona-module-a-web';
4
4
  import type { EntityRole } from '../entity/role.ts';
5
5
  import type { EntityUser } from '../entity/user.ts';
6
6
  import { BeanBase } from 'vona';
7
- import { DtoAuthSimple } from 'vona-module-a-authsimple';
7
+ import { Captcha } from 'vona-module-a-captcha';
8
8
  import { DtoJwtToken } from 'vona-module-a-jwt';
9
9
  import { Api, v } from 'vona-module-a-openapi';
10
10
  import { Passport } from 'vona-module-a-user';
11
11
  import { Arg, Controller, Web } from 'vona-module-a-web';
12
12
  import { z } from 'zod';
13
+ import { DtoLogin } from '../dto/login.ts';
13
14
  import { DtoPassport } from '../dto/passport.ts';
14
15
  import { DtoPassportJwt } from '../dto/passportJwt.ts';
16
+ import { DtoRegister } from '../dto/register.ts';
15
17
 
16
18
  export interface IControllerOptionsPassport extends IDecoratorControllerOptions {}
17
19
 
@@ -29,28 +31,37 @@ export class ControllerPassport extends BeanBase {
29
31
  return await this.bean.passport.signout();
30
32
  }
31
33
 
34
+ @Web.post('register')
35
+ @Passport.public()
36
+ @Captcha.verify({ scene: 'a-captchasimple:simple' })
37
+ @Api.body(v.object(DtoPassportJwt))
38
+ async register(@Arg.body() data: DtoRegister) {
39
+ const jwt = await this.bean.authSimple.authenticate(data, 'register', 'default');
40
+ return this._combineDtoPassportJwt(jwt);
41
+ }
42
+
32
43
  @Web.post('login')
33
44
  @Passport.public()
45
+ @Captcha.verify({ scene: 'a-captchasimple:simple' })
34
46
  @Api.body(v.object(DtoPassportJwt))
35
- async loginSimple(@Arg.body() clientOptions: DtoAuthSimple): Promise<DtoPassportJwt> {
36
- const jwt = await this.bean.authSimple.authenticate(clientOptions, 'default');
47
+ async login(@Arg.body() data: DtoLogin): Promise<DtoPassportJwt> {
48
+ const jwt = await this.bean.authSimple.authenticate(data, 'login', 'default');
37
49
  return this._combineDtoPassportJwt(jwt);
38
50
  }
39
51
 
40
52
  @Web.get('login/:module/:providerName/:clientName?')
41
53
  @Passport.public()
42
- @Api.body(v.object(DtoPassportJwt))
43
- async login<T extends keyof IAuthProviderRecord>(
54
+ async loginOauth<T extends keyof IAuthProviderRecord>(
44
55
  @Arg.param('module') module: string,
45
56
  @Arg.param('providerName') providerName: string,
46
57
  @Arg.param('clientName', z.string().optional()) clientName?: IAuthenticateOptions<IAuthProviderRecord[T]>['clientName'],
47
58
  @Arg.query('redirect', v.optional()) redirect?: string,
48
- ): Promise<DtoPassportJwt> {
49
- const jwt = await this.bean.auth.authenticate(`${module}:${providerName}` as T, {
59
+ ) {
60
+ // only support oauth, so not return jwt to client
61
+ await this.bean.auth.authenticate(`${module}:${providerName}` as T, {
50
62
  state: { intention: 'login', redirect },
51
63
  clientName,
52
64
  });
53
- return this._combineDtoPassportJwt(jwt);
54
65
  }
55
66
 
56
67
  @Web.get('associate/:module/:providerName/:clientName?')
@@ -1,4 +1,4 @@
1
- import type { TableIdentity } from 'vona-module-a-orm';
1
+ import type { TableIdentity } from 'table-identity';
2
2
  import type { IAuthBase } from 'vona-module-a-user';
3
3
  import type { IDecoratorDtoOptions } from 'vona-module-a-web';
4
4
  import { Api, v } from 'vona-module-a-openapi';
@@ -0,0 +1,18 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { DtoCaptchaVerify } from 'vona-module-a-captcha';
3
+ import { Api, v } from 'vona-module-a-openapi';
4
+ import { Dto } from 'vona-module-a-web';
5
+
6
+ export interface IDtoOptionsLogin extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsLogin>()
9
+ export class DtoLogin {
10
+ @Api.field(v.min(3), v.trim())
11
+ username: string;
12
+
13
+ @Api.field(v.min(6))
14
+ password: string;
15
+
16
+ @Api.field(v.captcha({ scene: 'a-captchasimple:simple' }))
17
+ captcha: DtoCaptchaVerify;
18
+ }
@@ -0,0 +1,26 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+ import { DtoCaptchaVerify } from 'vona-module-a-captcha';
3
+ import { Api, v } from 'vona-module-a-openapi';
4
+ import { Dto } from 'vona-module-a-web';
5
+
6
+ export interface IDtoOptionsRegister extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsRegister>({
9
+ pipes: v.refine('home-user:passwordConfirm'),
10
+ })
11
+ export class DtoRegister {
12
+ @Api.field(v.refine('home-user:usernameUnique'), v.min(3), v.trim())
13
+ username: string;
14
+
15
+ @Api.field(v.refine('home-user:emailUnique'), v.email(), v.trim())
16
+ email: string;
17
+
18
+ @Api.field(v.min(6), v.max(20))
19
+ password: string;
20
+
21
+ @Api.field(v.min(6), v.max(20))
22
+ passwordConfirm: string;
23
+
24
+ @Api.field(v.captcha({ scene: 'a-captchasimple:simple' }))
25
+ captcha: DtoCaptchaVerify;
26
+ }
@@ -1,4 +1,5 @@
1
- import type { IDecoratorEntityOptions, TableIdentity } from 'vona-module-a-orm';
1
+ import type { TableIdentity } from 'table-identity';
2
+ import type { IDecoratorEntityOptions } from 'vona-module-a-orm';
2
3
  import { Api, v } from 'vona-module-a-openapi';
3
4
  import { Entity, EntityBase } from 'vona-module-a-orm';
4
5
 
@@ -15,6 +15,15 @@ export class EntityUser extends EntityBase {
15
15
  @Api.field(v.title($locale('UserAvatar')), v.optional())
16
16
  avatar?: string;
17
17
 
18
+ @Api.field(v.title($locale('UserEmail')), v.optional())
19
+ email?: string;
20
+
21
+ @Api.field(v.title($locale('UserMobile')), v.optional())
22
+ mobile?: string;
23
+
24
+ @Api.field(v.title($locale('UserActivated')), v.default(false))
25
+ activated: boolean;
26
+
18
27
  @Api.field(v.title($locale('UserLocale')), z.string().optional())
19
28
  locale?: keyof ILocaleInfos | undefined;
20
29
  }
@@ -1,4 +1,4 @@
1
- import type { TableIdentity } from 'vona-module-a-orm';
1
+ import type { TableIdentity } from 'table-identity';
2
2
  import type { IAuthBase } from 'vona-module-a-user';
3
3
  import type { IAuth } from '../types/auth.ts';
4
4
  import { cast } from 'vona';
@@ -1,4 +1,4 @@
1
- import type { TableIdentity } from 'vona-module-a-orm';
1
+ import type { TableIdentity } from 'table-identity';
2
2
  import type { IRoleBase } from 'vona-module-a-user';
3
3
  import type { IRole } from '../types/role.ts';
4
4
  import { cast } from 'vona';
@@ -1,11 +1,11 @@
1
+ import type { TableIdentity } from 'table-identity';
1
2
  import type { ILocaleInfos } from 'vona';
2
- import type { TableIdentity } from 'vona-module-a-orm';
3
3
  import type { IUserBase } from 'vona-module-a-user';
4
4
  import type { IUser } from '../types/user.ts';
5
5
  import { cast } from 'vona';
6
6
  import { setUserAdapter } from 'vona-module-a-user';
7
7
 
8
- setUserAdapter({ getUserId, getUserName, getUserAvatar, getUserLocale, getUserAnonymous });
8
+ setUserAdapter({ getUserId, getUserName, getUserAvatar, getUserEmail, getUserMobile, getUserActivated, getUserLocale, getUserAnonymous });
9
9
 
10
10
  function getUserId(user: IUserBase): TableIdentity {
11
11
  return cast<IUser>(user).id;
@@ -19,6 +19,18 @@ function getUserAvatar(user: IUserBase): string | undefined {
19
19
  return cast<IUser>(user).avatar;
20
20
  }
21
21
 
22
+ function getUserEmail(user: IUserBase): string | undefined {
23
+ return cast<IUser>(user).email;
24
+ }
25
+
26
+ function getUserMobile(user: IUserBase): string | undefined {
27
+ return cast<IUser>(user).mobile;
28
+ }
29
+
30
+ function getUserActivated(user: IUserBase): boolean {
31
+ return cast<IUser>(user).activated;
32
+ }
33
+
22
34
  function getUserLocale(user: IUserBase): keyof ILocaleInfos | undefined {
23
35
  return cast<IUser>(user).locale;
24
36
  }
@@ -1,3 +1,4 @@
1
+ import type { TableIdentity } from 'table-identity';
1
2
  import type { IAuthUserProfile, IUserBase, IUserInnerAdapter } from 'vona-module-a-user';
2
3
  import type { IUser } from '../types/user.ts';
3
4
  import { BeanBase } from 'vona';
@@ -5,20 +6,25 @@ import { Service } from 'vona-module-a-bean';
5
6
 
6
7
  @Service()
7
8
  export class ServiceUserInnerAdapter extends BeanBase implements IUserInnerAdapter {
8
- async createByProfile(profile: IAuthUserProfile): Promise<IUserBase> {
9
- return await this.scope.model.user.insert({
9
+ async create(user: Partial<IUser>): Promise<IUserBase> {
10
+ return await this.scope.model.user.insert(user);
11
+ }
12
+
13
+ async userOfProfile(profile: IAuthUserProfile): Promise<IUserBase> {
14
+ return {
10
15
  name: profile.username!,
16
+ email: profile.emails?.[0].value,
11
17
  avatar: profile.photos?.[0].value,
12
- locale: undefined,
13
- });
18
+ locale: profile.locale || this.ctx.locale,
19
+ } as IUser;
14
20
  }
15
21
 
16
22
  async createAnonymous(): Promise<IUserBase> {
17
- return { id: -1, name: 'anonymous', avatar: undefined, locale: undefined } as IUserBase;
23
+ return { id: -1, name: 'anonymous', avatar: undefined, locale: undefined } as IUser;
18
24
  }
19
25
 
20
26
  async findOneByName(name: string): Promise<IUserBase | undefined> {
21
- return await this.findOne({ name });
27
+ return await this.scope.model.user.get({ name: { _eqI_: name } });
22
28
  }
23
29
 
24
30
  async findOne(user: Partial<IUser>): Promise<IUserBase | undefined> {
@@ -32,4 +38,8 @@ export class ServiceUserInnerAdapter extends BeanBase implements IUserInnerAdapt
32
38
  async remove(user: Partial<IUser>): Promise<void> {
33
39
  await this.scope.model.user.delete(user);
34
40
  }
41
+
42
+ async setActivated(id: TableIdentity, activated: boolean): Promise<void> {
43
+ await this.scope.model.user.update({ id, activated });
44
+ }
35
45
  }
@@ -1,5 +1,5 @@
1
+ import type { TableIdentity } from 'table-identity';
1
2
  import type { IPayloadDataBase } from 'vona-module-a-jwt';
2
- import type { TableIdentity } from 'vona-module-a-orm';
3
3
  import type { IPassportBase } from 'vona-module-a-user';
4
4
  import type { IAuth } from './auth.ts';
5
5
  import type { IUser } from './user.ts';
@@ -4,5 +4,8 @@ import type { IUserBase } from 'vona-module-a-user';
4
4
  export interface IUser extends IUserBase {
5
5
  name: string;
6
6
  avatar?: string;
7
+ email?: string;
8
+ mobile?: string;
9
+ activated: boolean;
7
10
  locale?: keyof ILocaleInfos | undefined;
8
11
  }
@@ -1,4 +1,5 @@
1
- import type { IQueryParams, TableIdentity } from 'vona-module-a-orm';
1
+ import type { TableIdentity } from 'table-identity';
2
+ import type { IQueryParams } from 'vona-module-a-orm';
2
3
  import type { IDecoratorControllerOptions } from 'vona-module-a-web';
3
4
  import type { Model<%=argv.resourceNameCapitalize%> } from '../model/<%=argv.resourceName%>.ts';
4
5
  import { BeanBase } from 'vona';
@@ -23,9 +24,6 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
23
24
  @Web.get()
24
25
  @Api.body(Dto<%=argv.resourceNameCapitalize%>QueryRes)
25
26
  async findMany(@Arg.queryPro(Dto<%=argv.resourceNameCapitalize%>Query) params: IQueryParams<Model<%=argv.resourceNameCapitalize%>>): Promise<Dto<%=argv.resourceNameCapitalize%>QueryRes> {
26
- if (!params.orders) {
27
- params.orders = [['<%=argv.moduleResourceName%>.createdAt', 'desc']];
28
- }
29
27
  return await this.scope.service.<%=argv.resourceName%>.findMany(params);
30
28
  }
31
29
 
@@ -1,9 +1,11 @@
1
1
  import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
- import { $Dto } from 'vona-module-a-orm';
2
+ import { $Dto, $tableName } from 'vona-module-a-orm';
3
3
  import { Dto } from 'vona-module-a-web';
4
4
  import { Entity<%=argv.resourceNameCapitalize%> } from '../entity/<%=argv.resourceName%>.ts';
5
5
 
6
6
  export interface IDtoOptions<%=argv.resourceNameCapitalize%>Query extends IDecoratorDtoOptions {}
7
7
 
8
- @Dto<IDtoOptions<%=argv.resourceNameCapitalize%>Query>()
8
+ @Dto<IDtoOptions<%=argv.resourceNameCapitalize%>Query>({
9
+ openapi: { query: { table: $tableName(Entity<%=argv.resourceNameCapitalize%>) } },
10
+ })
9
11
  export class Dto<%=argv.resourceNameCapitalize%>Query extends $Dto.queryPage(Entity<%=argv.resourceNameCapitalize%>, ['name']) {}
@@ -1,4 +1,5 @@
1
- import type { IQueryParams, TableIdentity } from 'vona-module-a-orm';
1
+ import type { TableIdentity } from 'table-identity';
2
+ import type { IQueryParams } from 'vona-module-a-orm';
2
3
  import type { Dto<%=argv.resourceNameCapitalize%>Create } from '../dto/<%=argv.resourceName%>Create.ts';
3
4
  import type { Dto<%=argv.resourceNameCapitalize%>QueryRes } from '../dto/<%=argv.resourceName%>QueryRes.ts';
4
5
  import type { Dto<%=argv.resourceNameCapitalize%>Update } from '../dto/<%=argv.resourceName%>Update.ts';
@@ -134,6 +134,7 @@ export class CliToolsMetadata extends BeanCliBase {
134
134
  _generatePatch(content) {
135
135
  if (!content)
136
136
  return content;
137
+ content = this._generatePatch_resources(content, 'table-identity', ['TableIdentity'], true);
137
138
  content = this._generatePatch_resources(content, 'vona-module-a-openapi', ['TypeEntityOptionsFields', 'TypeControllerOptionsActions'], true);
138
139
  content = this._generatePatch_resources(content, 'vona-module-a-orm', [
139
140
  'TypeEntityMeta',
@@ -3,6 +3,7 @@ import { getEnvFiles } from '@cabloy/dotenv';
3
3
  import chalk from 'chalk';
4
4
  import fse from 'fs-extra';
5
5
  import { copyTemplateFile, getEnvMeta, resolveTemplatePath } from "../../utils.js";
6
+ import { generateZod } from "./generateZod.js";
6
7
  export async function generateEntryFiles(configMeta, configOptions, modulesMeta, env) {
7
8
  // config
8
9
  await __generateConfig();
@@ -12,6 +13,8 @@ export async function generateEntryFiles(configMeta, configOptions, modulesMeta,
12
13
  await __generateEnvJson();
13
14
  // app
14
15
  await __generateApp();
16
+ // zod
17
+ await generateZod(configOptions);
15
18
  //////////////////////////////
16
19
  async function __generateConfig() {
17
20
  // check config
@@ -0,0 +1,2 @@
1
+ import type { VonaBinConfigOptions } from './types.ts';
2
+ export declare function generateZod(configOptions: VonaBinConfigOptions): Promise<void>;
@@ -0,0 +1,48 @@
1
+ import { createRequire } from 'node:module';
2
+ import path from 'node:path';
3
+ import fse from 'fs-extra';
4
+ import { copyTemplateIfNeed, pathToHref } from "../../utils.js";
5
+ const __ImportZodCore = 'zod/v4/core';
6
+ export async function generateZod(configOptions) {
7
+ await __generateZodCoreUtil(configOptions);
8
+ await __generateZodCoreSchemas(configOptions);
9
+ }
10
+ async function __generateZodCoreUtil(configOptions) {
11
+ const pathZodCore = parseZodCorePath(configOptions.appDir);
12
+ const fileSrc = path.join(pathZodCore, 'util.js');
13
+ const fileSrcBak = path.join(pathZodCore, 'util-origin.js');
14
+ copyTemplateIfNeed(fileSrc, fileSrcBak);
15
+ const content = fse.readFileSync(fileSrcBak).toString();
16
+ const contentNew = content
17
+ .replace('export function finalizeIssue', `let __localeAdapterFn;
18
+ export function setLocaleAdapter(localeAdapterFn) {
19
+ __localeAdapterFn=localeAdapterFn;
20
+ }
21
+ export function finalizeIssue`)
22
+ .replace('const message = unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ??', `const msg = unwrapMessage(iss.inst?._zod.def?.error?.(iss));
23
+ const message = (__localeAdapterFn?__localeAdapterFn(msg):msg) ??`);
24
+ fse.writeFileSync(fileSrc, contentNew);
25
+ }
26
+ async function __generateZodCoreSchemas(configOptions) {
27
+ const pathZodCore = parseZodCorePath(configOptions.appDir);
28
+ const fileSrc = path.join(pathZodCore, 'schemas.js');
29
+ const fileSrcBak = path.join(pathZodCore, 'schemas-origin.js');
30
+ copyTemplateIfNeed(fileSrc, fileSrcBak);
31
+ const content = fse.readFileSync(fileSrcBak).toString();
32
+ const contentNew = content
33
+ .replace('export const $ZodType =', `let __parseAdapterFn;
34
+ export function setParseAdapter(parseAdapterFn) {
35
+ __parseAdapterFn = parseAdapterFn;
36
+ }
37
+ export const $ZodType =`)
38
+ .replace('inst._zod.run = inst._zod.parse;', 'inst._zod.run = __parseAdapterFn ? __parseAdapterFn(inst, inst._zod.parse) : inst._zod.parse;')
39
+ .replace(/inst._zod.run = (\(payload, ctx\) => \{[\s\S]*?return runChecks\(result, checks, ctx\);\s*\};)/, (_, $0) => {
40
+ return `const __run = ${$0}\ninst._zod.run = __parseAdapterFn ? __parseAdapterFn(inst, __run) : __run;`;
41
+ });
42
+ fse.writeFileSync(fileSrc, contentNew);
43
+ }
44
+ function parseZodCorePath(appDir) {
45
+ const require = createRequire(pathToHref(path.join(appDir, '/')));
46
+ const fileCoreIndex = require.resolve(__ImportZodCore);
47
+ return path.dirname(fileCoreIndex);
48
+ }
@@ -15,3 +15,4 @@ export declare function saveJSONFile(fileName: string, json: object): Promise<vo
15
15
  export declare function pathToHref(fileName: string): string;
16
16
  export declare function getOutDir(): string;
17
17
  export declare function getOutReleasesDir(): string;
18
+ export declare function copyTemplateIfNeed(fileSrc: string, fileDest: string): void;
package/dist/lib/utils.js CHANGED
@@ -69,3 +69,8 @@ export function getOutDir() {
69
69
  export function getOutReleasesDir() {
70
70
  return `dist-releases/${process.env.META_FLAVOR}-${process.env.APP_VERSION}`;
71
71
  }
72
+ export function copyTemplateIfNeed(fileSrc, fileDest) {
73
+ if (!fse.existsSync(fileDest)) {
74
+ fse.copyFileSync(fileSrc, fileDest);
75
+ }
76
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vona-cli-set-api",
3
3
  "type": "module",
4
- "version": "1.0.172",
4
+ "version": "1.0.176",
5
5
  "description": "vona cli-set-api",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -61,7 +61,7 @@
61
61
  "ts-node": "^10.9.2",
62
62
  "urllib": "^4.6.11",
63
63
  "uuid": "^11.1.0",
64
- "vona-core": "^5.0.48",
64
+ "vona-core": "^5.0.49",
65
65
  "why-is-node-running": "^3.2.2",
66
66
  "yargs-parser": "^21.1.1"
67
67
  },