vona-cli-set-api 1.0.174 → 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 (29) 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 +105 -1
  7. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.emailConfirmCallback.ts +24 -0
  8. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.passwordResetCallback.ts +22 -0
  9. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/eventListener.register.ts +23 -0
  10. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/meta.version.ts +5 -5
  11. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.emailUnique.ts +20 -0
  12. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.passwordConfirm.ts +20 -0
  13. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/bean/zodRefine.usernameUnique.ts +20 -0
  14. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/config.ts +3 -0
  15. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/locale/en-us.ts +6 -0
  16. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/config/locale/zh-cn.ts +6 -0
  17. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/controller/passport.ts +19 -8
  18. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/login.ts +18 -0
  19. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/dto/register.ts +26 -0
  20. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/service/userInnerAdapter.ts +2 -2
  21. package/cli/templates/create/project/basic/boilerplate/src/suite/a-home/modules/home-user/src/types/passport.ts +1 -1
  22. package/cli/templates/tools/crud/boilerplate/src/controller/{{resourceName}}.ts_ +0 -3
  23. package/cli/templates/tools/crud/boilerplate/src/dto/{{resourceName}}Query.ts_ +4 -2
  24. package/dist/lib/bean/toolsBin/generateEntryFiles.js +3 -0
  25. package/dist/lib/bean/toolsBin/generateZod.d.ts +2 -0
  26. package/dist/lib/bean/toolsBin/generateZod.js +48 -0
  27. package/dist/lib/utils.d.ts +1 -0
  28. package/dist/lib/utils.js +5 -0
  29. 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.103"
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
+ }
@@ -300,12 +300,18 @@ declare module 'vona' {
300
300
  /** service: end */
301
301
  /** eventListener: begin */
302
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';
303
306
 
304
307
  import { type IDecoratorEventListenerOptions } from 'vona-module-a-event';
305
308
  declare module 'vona-module-a-event' {
306
309
 
307
310
  export interface IEventListenerRecord {
308
311
  'home-user:activate': IDecoratorEventListenerOptions;
312
+ 'home-user:emailConfirmCallback': IDecoratorEventListenerOptions;
313
+ 'home-user:passwordResetCallback': IDecoratorEventListenerOptions;
314
+ 'home-user:register': IDecoratorEventListenerOptions;
309
315
  }
310
316
 
311
317
 
@@ -320,6 +326,36 @@ declare module 'vona-module-home-user' {
320
326
  export interface EventListenerActivate {
321
327
  get $beanFullName(): 'home-user.eventListener.activate';
322
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';
323
359
  }
324
360
  }
325
361
  /** eventListener: end */
@@ -362,18 +398,24 @@ declare module 'vona-module-home-user' {
362
398
  /** meta: end */
363
399
  /** dto: begin */
364
400
  export * from '../dto/auth.ts';
401
+ export * from '../dto/login.ts';
365
402
  export * from '../dto/passport.ts';
366
403
  export * from '../dto/passportJwt.ts';
404
+ export * from '../dto/register.ts';
367
405
  import type { IDtoOptionsAuth } from '../dto/auth.ts';
406
+ import type { IDtoOptionsLogin } from '../dto/login.ts';
368
407
  import type { IDtoOptionsPassport } from '../dto/passport.ts';
369
408
  import type { IDtoOptionsPassportJwt } from '../dto/passportJwt.ts';
409
+ import type { IDtoOptionsRegister } from '../dto/register.ts';
370
410
  import 'vona';
371
411
  declare module 'vona-module-a-web' {
372
412
 
373
413
  export interface IDtoRecord {
374
414
  'home-user:auth': IDtoOptionsAuth;
415
+ 'home-user:login': IDtoOptionsLogin;
375
416
  'home-user:passport': IDtoOptionsPassport;
376
417
  'home-user:passportJwt': IDtoOptionsPassportJwt;
418
+ 'home-user:register': IDtoOptionsRegister;
377
419
  }
378
420
 
379
421
 
@@ -384,14 +426,20 @@ declare module 'vona-module-home-user' {
384
426
  /** dto: end */
385
427
  /** dto: begin */
386
428
  import type { DtoAuth } from '../dto/auth.ts';
429
+ import type { DtoLogin } from '../dto/login.ts';
387
430
  import type { DtoPassport } from '../dto/passport.ts';
388
- import type { DtoPassportJwt } from '../dto/passportJwt.ts';
431
+ import type { DtoPassportJwt } from '../dto/passportJwt.ts';
432
+ import type { DtoRegister } from '../dto/register.ts';
389
433
  declare module 'vona-module-home-user' {
390
434
 
391
435
  export interface IDtoOptionsAuth {
392
436
  fields?: TypeEntityOptionsFields<DtoAuth, IDtoOptionsAuth[TypeSymbolKeyFieldsMore]>;
393
437
  }
394
438
 
439
+ export interface IDtoOptionsLogin {
440
+ fields?: TypeEntityOptionsFields<DtoLogin, IDtoOptionsLogin[TypeSymbolKeyFieldsMore]>;
441
+ }
442
+
395
443
  export interface IDtoOptionsPassport {
396
444
  fields?: TypeEntityOptionsFields<DtoPassport, IDtoOptionsPassport[TypeSymbolKeyFieldsMore]>;
397
445
  }
@@ -399,6 +447,10 @@ declare module 'vona-module-home-user' {
399
447
  export interface IDtoOptionsPassportJwt {
400
448
  fields?: TypeEntityOptionsFields<DtoPassportJwt, IDtoOptionsPassportJwt[TypeSymbolKeyFieldsMore]>;
401
449
  }
450
+
451
+ export interface IDtoOptionsRegister {
452
+ fields?: TypeEntityOptionsFields<DtoRegister, IDtoOptionsRegister[TypeSymbolKeyFieldsMore]>;
453
+ }
402
454
  }
403
455
  /** dto: end */
404
456
  /** controller: begin */
@@ -444,6 +496,7 @@ declare module 'vona-module-a-web' {
444
496
  }
445
497
  export interface IApiPathPostRecord{
446
498
  '/home/user/passport/logout': undefined;
499
+ '/home/user/passport/register': undefined;
447
500
  '/home/user/passport/login': undefined;
448
501
  '/home/user/passport/refreshAuthToken': undefined;
449
502
  '/home/user/passport/createPassportJwtFromOauthCode': undefined;
@@ -452,6 +505,57 @@ export interface IApiPathPostRecord{
452
505
 
453
506
  }
454
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 */
455
559
  /** config: begin */
456
560
  export * from '../config/config.ts';
457
561
  import type { config } from '../config/config.ts';
@@ -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
+ }
@@ -1,5 +1,4 @@
1
1
  import type { IMetaVersionInit, IMetaVersionInitOptions, IMetaVersionUpdate, IMetaVersionUpdateOptions } from 'vona-module-a-version';
2
- import type { IUser } from '../types/user.ts';
3
2
  import { BeanBase } from 'vona';
4
3
  import { Meta } from 'vona-module-a-meta';
5
4
 
@@ -43,11 +42,12 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate, IMetaVe
43
42
  name: 'admin',
44
43
  });
45
44
  // user: admin
46
- await this.bean.userInner.register({
47
- name: 'admin',
45
+ await this.bean.authSimple.authenticate({
46
+ username: 'admin',
47
+ password: options.password || this.scope.config.passwordDefault.admin,
48
48
  avatar: ':emoji:flower',
49
- locale: undefined,
50
- } as IUser, true);
49
+ confirmed: true,
50
+ }, 'register', 'default');
51
51
  }
52
52
  }
53
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,4 +1,7 @@
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',
@@ -8,4 +11,7 @@ export default {
8
11
  UserMobile: 'Mobile',
9
12
  UserActivated: 'Activated',
10
13
  UserLocale: 'Language',
14
+ UsernameExists: 'Username Exists',
15
+ EmailExists: 'Email Exists',
16
+ PasswordsNotMatch: 'Passwords do not match',
11
17
  };
@@ -1,4 +1,7 @@
1
1
  export default {
2
+ ConfirmationEmailExpired: '确认邮件链接已经过期',
3
+ ConfirmationEmailSucceeded: '您的邮件地址已经确认',
4
+ PasswordResetEmailExpired: '重置密码链接已经过期',
2
5
  Role: '角色',
3
6
  RoleName: '角色名',
4
7
  User: '用户',
@@ -8,4 +11,7 @@ export default {
8
11
  UserMobile: '手机号',
9
12
  UserActivated: '已激活',
10
13
  UserLocale: '语言',
14
+ UsernameExists: '用户名已存在',
15
+ EmailExists: '电子邮件已存在',
16
+ PasswordsNotMatch: '密码不一致',
11
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?')
@@ -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
+ }
@@ -15,7 +15,7 @@ export class ServiceUserInnerAdapter extends BeanBase implements IUserInnerAdapt
15
15
  name: profile.username!,
16
16
  email: profile.emails?.[0].value,
17
17
  avatar: profile.photos?.[0].value,
18
- locale: undefined,
18
+ locale: profile.locale || this.ctx.locale,
19
19
  } as IUser;
20
20
  }
21
21
 
@@ -24,7 +24,7 @@ export class ServiceUserInnerAdapter extends BeanBase implements IUserInnerAdapt
24
24
  }
25
25
 
26
26
  async findOneByName(name: string): Promise<IUserBase | undefined> {
27
- return await this.findOne({ name });
27
+ return await this.scope.model.user.get({ name: { _eqI_: name } });
28
28
  }
29
29
 
30
30
  async findOne(user: Partial<IUser>): Promise<IUserBase | undefined> {
@@ -1,5 +1,5 @@
1
- import type { IPayloadDataBase } from 'vona-module-a-jwt';
2
1
  import type { TableIdentity } from 'table-identity';
2
+ import type { IPayloadDataBase } from 'vona-module-a-jwt';
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';
@@ -24,9 +24,6 @@ export class Controller<%=argv.resourceNameCapitalize%> extends BeanBase {
24
24
  @Web.get()
25
25
  @Api.body(Dto<%=argv.resourceNameCapitalize%>QueryRes)
26
26
  async findMany(@Arg.queryPro(Dto<%=argv.resourceNameCapitalize%>Query) params: IQueryParams<Model<%=argv.resourceNameCapitalize%>>): Promise<Dto<%=argv.resourceNameCapitalize%>QueryRes> {
27
- if (!params.orders) {
28
- params.orders = [['<%=argv.moduleResourceName%>.createdAt', 'desc']];
29
- }
30
27
  return await this.scope.service.<%=argv.resourceName%>.findMany(params);
31
28
  }
32
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']) {}
@@ -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.174",
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
  },