@robsun/create-keystone-app 0.1.13 → 0.1.14

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 (54) hide show
  1. package/README.md +19 -10
  2. package/bin/create-keystone-app.js +199 -60
  3. package/package.json +1 -1
  4. package/template/.husky/pre-commit +4 -0
  5. package/template/.lintstagedrc.json +5 -0
  6. package/template/.prettierrc +9 -0
  7. package/template/README.md +45 -23
  8. package/template/apps/server/.air.toml +44 -0
  9. package/template/apps/server/README.md +27 -0
  10. package/template/apps/server/cmd/server/main.go +213 -0
  11. package/template/apps/server/config.yaml +51 -0
  12. package/template/apps/server/docs/docs.go +34 -0
  13. package/template/apps/server/go.mod +13 -0
  14. package/template/apps/server/go.sum +72 -0
  15. package/template/apps/server/internal/app/routes/module_routes.go +16 -0
  16. package/template/apps/server/internal/app/routes/routes.go +226 -0
  17. package/template/apps/server/internal/app/startup/startup.go +74 -0
  18. package/template/apps/server/internal/frontend/dist/.gitkeep +1 -0
  19. package/template/apps/server/internal/frontend/embed.go +28 -0
  20. package/template/apps/server/internal/frontend/handler.go +122 -0
  21. package/template/apps/server/internal/{demo/demo.go → modules/demo/handlers.go} +4 -1
  22. package/template/apps/server/internal/modules/demo/module.go +55 -0
  23. package/template/apps/server/internal/modules/manifest.go +11 -0
  24. package/template/apps/server/internal/modules/registry.go +145 -0
  25. package/template/apps/web/.env.example +3 -0
  26. package/template/apps/web/README.md +29 -0
  27. package/template/apps/web/eslint.config.js +35 -0
  28. package/template/apps/web/package.json +27 -10
  29. package/template/apps/web/postcss.config.js +6 -0
  30. package/template/apps/web/src/index.css +3 -0
  31. package/template/apps/web/src/main.tsx +1 -0
  32. package/template/apps/web/src/modules/demo/help/overview.md +12 -0
  33. package/template/apps/web/src/modules/demo/routes.tsx +2 -0
  34. package/template/apps/web/tailwind.config.js +18 -0
  35. package/template/apps/web/tests/setup.ts +37 -0
  36. package/template/apps/web/tsconfig.app.json +3 -3
  37. package/template/apps/web/vite.config.ts +28 -2
  38. package/template/docker-compose.yml +45 -0
  39. package/template/docs/CONVENTIONS.md +61 -88
  40. package/template/package.json +15 -3
  41. package/template/scripts/build.bat +133 -0
  42. package/template/scripts/build.js +25 -0
  43. package/template/scripts/build.sh +99 -0
  44. package/template/scripts/clean.bat +35 -0
  45. package/template/scripts/clean.js +25 -0
  46. package/template/scripts/clean.sh +34 -0
  47. package/template/scripts/dev.bat +82 -0
  48. package/template/scripts/dev.js +25 -0
  49. package/template/scripts/dev.sh +88 -0
  50. package/template/scripts/test.bat +86 -0
  51. package/template/scripts/test.js +25 -0
  52. package/template/scripts/test.sh +86 -0
  53. package/template/apps/server/main.go +0 -28
  54. /package/template/{config.yaml → apps/server/config.example.yaml} +0 -0
@@ -0,0 +1,213 @@
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "fmt"
7
+ "log"
8
+ "net/http"
9
+ "os"
10
+ "os/signal"
11
+ "strings"
12
+ "syscall"
13
+ "time"
14
+
15
+ "github.com/gin-gonic/gin"
16
+ "gorm.io/gorm"
17
+
18
+ "github.com/robsuncn/keystone/bootstrap/config"
19
+ approvalSvc "github.com/robsuncn/keystone/domain/approval/service"
20
+ "github.com/robsuncn/keystone/domain/service"
21
+ coreexporter "github.com/robsuncn/keystone/infra/exporter"
22
+ "github.com/robsuncn/keystone/infra/importer"
23
+ "github.com/robsuncn/keystone/infra/jobs"
24
+ "github.com/robsuncn/keystone/infra/jobs/processors"
25
+ "github.com/robsuncn/keystone/infra/queue"
26
+ "github.com/robsuncn/keystone/infra/repository"
27
+ "github.com/robsuncn/keystone/infra/storage"
28
+
29
+ "__APP_NAME__/apps/server/internal/app/routes"
30
+ "__APP_NAME__/apps/server/internal/app/startup"
31
+ "__APP_NAME__/apps/server/internal/modules"
32
+ )
33
+
34
+ func main() {
35
+ cfg, err := config.Load()
36
+ if err != nil {
37
+ log.Fatalf("failed to load config: %v", err)
38
+ }
39
+ applyLocalDefaults(cfg)
40
+
41
+ if err := approvalSvc.RegisterDefaultSchemas(); err != nil {
42
+ log.Fatalf("failed to register approval schemas: %v", err)
43
+ }
44
+
45
+ cfg.Modules.Enabled = ensureModuleEnabled(cfg.Modules.Enabled, "keystone")
46
+
47
+ modules.RegisterAll()
48
+
49
+ db, err := startup.InitializeDatabase(cfg)
50
+ if err != nil {
51
+ log.Fatalf("database initialization failed: %v", err)
52
+ }
53
+
54
+ setGinMode(cfg)
55
+
56
+ jobQueue := initQueue(cfg)
57
+ router := routes.SetupRouter(cfg, db, jobQueue)
58
+
59
+ blacklistRepo := repository.NewTokenBlacklistRepository(db)
60
+ loginLogRepo := repository.NewLoginLogRepository(db)
61
+ auditLogRepo := repository.NewAuditLogRepository(db)
62
+ stopCleanup := jobs.StartCleanupJobs(blacklistRepo, loginLogRepo, auditLogRepo)
63
+
64
+ stopWorker := startJobWorker(cfg, db, jobQueue)
65
+
66
+ port := ""
67
+ if cfg != nil {
68
+ port = strings.TrimSpace(cfg.Server.Port)
69
+ }
70
+ if envPort := strings.TrimSpace(os.Getenv("PORT")); envPort != "" {
71
+ port = envPort
72
+ }
73
+ if port == "" {
74
+ port = "8080"
75
+ }
76
+
77
+ server := &http.Server{
78
+ Addr: fmt.Sprintf(":%s", port),
79
+ Handler: router,
80
+ }
81
+
82
+ go func() {
83
+ log.Printf("Starting server on port %s in %s mode", port, cfg.Server.Mode)
84
+ if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
85
+ log.Fatalf("failed to start server: %v", err)
86
+ }
87
+ }()
88
+
89
+ quit := make(chan os.Signal, 1)
90
+ signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
91
+ <-quit
92
+
93
+ if stopCleanup != nil {
94
+ stopCleanup()
95
+ }
96
+ if stopWorker != nil {
97
+ stopWorker()
98
+ }
99
+
100
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
101
+ defer cancel()
102
+ if err := server.Shutdown(ctx); err != nil {
103
+ log.Printf("shutdown error: %v", err)
104
+ }
105
+ }
106
+
107
+ func applyLocalDefaults(cfg *config.Config) {
108
+ if cfg == nil {
109
+ return
110
+ }
111
+ cfg.Database.Driver = strings.TrimSpace(cfg.Database.Driver)
112
+ if cfg.Database.Driver == "" {
113
+ cfg.Database.Driver = "sqlite"
114
+ }
115
+ if cfg.Database.Path == "" || cfg.Database.Path == "./data/keystone.db" {
116
+ cfg.Database.Path = "./data/keystone-local.db"
117
+ }
118
+ if strings.TrimSpace(cfg.Server.Mode) == "" {
119
+ cfg.Server.Mode = "debug"
120
+ }
121
+ }
122
+
123
+ func ensureModuleEnabled(enabled []string, name string) []string {
124
+ if name == "" {
125
+ return enabled
126
+ }
127
+ for _, existing := range enabled {
128
+ if existing == name {
129
+ return enabled
130
+ }
131
+ }
132
+ return append(enabled, name)
133
+ }
134
+
135
+ func setGinMode(cfg *config.Config) {
136
+ mode := "debug"
137
+ if cfg != nil {
138
+ mode = strings.ToLower(strings.TrimSpace(cfg.Server.Mode))
139
+ }
140
+ switch mode {
141
+ case "release":
142
+ gin.SetMode(gin.ReleaseMode)
143
+ case "test":
144
+ gin.SetMode(gin.TestMode)
145
+ default:
146
+ gin.SetMode(gin.DebugMode)
147
+ }
148
+ }
149
+
150
+ func initQueue(cfg *config.Config) queue.Queue {
151
+ if cfg == nil {
152
+ return nil
153
+ }
154
+ queueBackend, err := queue.New(cfg.Queue)
155
+ if err != nil {
156
+ log.Printf("queue init failed: %v", err)
157
+ return nil
158
+ }
159
+ return queueBackend
160
+ }
161
+
162
+ func startJobWorker(cfg *config.Config, db *gorm.DB, jobQueue queue.Queue) func() {
163
+ if cfg == nil || db == nil || jobQueue == nil {
164
+ return nil
165
+ }
166
+
167
+ jobRepo := repository.NewJobRepository(db)
168
+ jobSvc := service.NewJobService(db, jobRepo)
169
+ notificationRepo := repository.NewNotificationRepository(db)
170
+ notificationSvc := service.NewNotificationService(db, notificationRepo)
171
+
172
+ jobRegistry := jobs.NewRegistry()
173
+
174
+ storageSvc, storageErr := storage.New(cfg.Storage)
175
+ if storageErr != nil {
176
+ log.Printf("storage init failed for jobs: %v", storageErr)
177
+ }
178
+ if storageSvc != nil {
179
+ importSvc := importer.NewService(storageSvc).
180
+ WithProgressTracker(func(job queue.Job) importer.ProgressTracker {
181
+ return importer.JobProgressTracker{JobID: job.ID, TenantID: job.TenantID, Jobs: jobSvc}
182
+ })
183
+ exportSvc := coreexporter.NewService(storageSvc).
184
+ WithProgressTracker(func(job queue.Job) coreexporter.ProgressTracker {
185
+ return coreexporter.JobProgressTracker{JobID: job.ID, TenantID: job.TenantID, Jobs: jobSvc}
186
+ })
187
+ importProcessor := processors.NewImportJobProcessor(importSvc, notificationSvc)
188
+ if err := jobs.RegisterImportJob(jobRegistry, importProcessor); err != nil {
189
+ log.Printf("import job registration failed: %v", err)
190
+ }
191
+ exportProcessor := processors.NewExportJobProcessor(exportSvc, notificationSvc)
192
+ if err := jobs.RegisterExportJob(jobRegistry, exportProcessor); err != nil {
193
+ log.Printf("export job registration failed: %v", err)
194
+ }
195
+ }
196
+
197
+ if err := jobs.RegisterNotificationJob(jobRegistry, notificationSvc); err != nil {
198
+ log.Printf("notification job registration failed: %v", err)
199
+ }
200
+ if err := modules.RegisterJobs(cfg.Modules.Enabled, jobRegistry); err != nil {
201
+ log.Printf("module job registration failed: %v", err)
202
+ }
203
+
204
+ executor := jobs.NewExecutor(jobRegistry, jobSvc)
205
+ worker := queue.Worker{Queue: jobQueue, Handler: executor}
206
+ workerCtx, cancelWorker := context.WithCancel(context.Background())
207
+ go func() {
208
+ if err := worker.Run(workerCtx); err != nil && !errors.Is(err, context.Canceled) {
209
+ log.Printf("worker stopped: %v", err)
210
+ }
211
+ }()
212
+ return cancelWorker
213
+ }
@@ -0,0 +1,51 @@
1
+ server:
2
+ port: "8080"
3
+ mode: "debug"
4
+ swagger_enabled: true
5
+
6
+ modules:
7
+ enabled:
8
+ - "keystone"
9
+ - "demo"
10
+
11
+ database:
12
+ driver: "sqlite"
13
+ host: "localhost"
14
+ port: "5432"
15
+ user: "keystone"
16
+ password: "keystone"
17
+ dbname: "keystone"
18
+ sslmode: "disable"
19
+ path: "./data/keystone-local.db"
20
+
21
+ jwt:
22
+ secret: "change-me-in-prod"
23
+ access_token_ttl: 2
24
+ refresh_token_ttl: 168
25
+
26
+ approval:
27
+ callback_secret: ""
28
+
29
+ pdf:
30
+ font_path: ""
31
+
32
+ queue:
33
+ driver: "memory"
34
+ buffer: 200
35
+ redis:
36
+ addr: "localhost:6379"
37
+ password: ""
38
+ db: 0
39
+ key: "keystone:jobs"
40
+
41
+ storage:
42
+ driver: "local"
43
+ local_dir: "./storage"
44
+ base_url: ""
45
+ s3:
46
+ endpoint: ""
47
+ region: ""
48
+ bucket: ""
49
+ access_key: ""
50
+ secret_key: ""
51
+ use_ssl: true
@@ -0,0 +1,34 @@
1
+ package docs
2
+
3
+ import "github.com/swaggo/swag"
4
+
5
+ const docTemplate = `{
6
+ "swagger": "2.0",
7
+ "info": {
8
+ "description": "Keystone API documentation",
9
+ "title": "Keystone API",
10
+ "version": "{{.Version}}"
11
+ },
12
+ "host": "{{.Host}}",
13
+ "basePath": "{{.BasePath}}",
14
+ "schemes": {{ marshal .Schemes }},
15
+ "paths": {}
16
+ }`
17
+
18
+ // SwaggerInfo holds exported Swagger Info so clients can modify it.
19
+ var SwaggerInfo = &swag.Spec{
20
+ Version: "0.1.0",
21
+ Host: "",
22
+ BasePath: "/api/v1",
23
+ Schemes: []string{"http", "https"},
24
+ Title: "Keystone API",
25
+ Description: "Keystone API documentation",
26
+ InfoInstanceName: "swagger",
27
+ SwaggerTemplate: docTemplate,
28
+ LeftDelim: "{{",
29
+ RightDelim: "}}",
30
+ }
31
+
32
+ func init() {
33
+ swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
34
+ }
@@ -5,11 +5,17 @@ go 1.24.3
5
5
  require (
6
6
  github.com/gin-gonic/gin v1.11.0
7
7
  github.com/robsuncn/keystone v0.1.1
8
+ github.com/swaggo/files v1.0.1
9
+ github.com/swaggo/gin-swagger v1.6.0
10
+ github.com/swaggo/swag v1.16.2
8
11
  gorm.io/gorm v1.31.1
9
12
  )
10
13
 
11
14
  require (
12
15
  filippo.io/edwards25519 v1.1.0 // indirect
16
+ github.com/KyleBanks/depth v1.2.1 // indirect
17
+ github.com/PuerkitoBio/purell v1.1.1 // indirect
18
+ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
13
19
  github.com/bytedance/sonic v1.14.0 // indirect
14
20
  github.com/bytedance/sonic/loader v0.3.0 // indirect
15
21
  github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -21,6 +27,10 @@ require (
21
27
  github.com/gin-contrib/sse v1.1.0 // indirect
22
28
  github.com/glebarez/go-sqlite v1.21.2 // indirect
23
29
  github.com/glebarez/sqlite v1.11.0 // indirect
30
+ github.com/go-openapi/jsonpointer v0.19.5 // indirect
31
+ github.com/go-openapi/jsonreference v0.19.6 // indirect
32
+ github.com/go-openapi/spec v0.20.4 // indirect
33
+ github.com/go-openapi/swag v0.19.15 // indirect
24
34
  github.com/go-playground/locales v0.14.1 // indirect
25
35
  github.com/go-playground/universal-translator v0.18.1 // indirect
26
36
  github.com/go-playground/validator/v10 v10.27.0 // indirect
@@ -36,9 +46,11 @@ require (
36
46
  github.com/jackc/puddle/v2 v2.2.2 // indirect
37
47
  github.com/jinzhu/inflection v1.0.0 // indirect
38
48
  github.com/jinzhu/now v1.1.5 // indirect
49
+ github.com/josharian/intern v1.0.0 // indirect
39
50
  github.com/json-iterator/go v1.1.12 // indirect
40
51
  github.com/klauspost/cpuid/v2 v2.3.0 // indirect
41
52
  github.com/leodido/go-urn v1.4.0 // indirect
53
+ github.com/mailru/easyjson v0.7.6 // indirect
42
54
  github.com/mattn/go-isatty v0.0.20 // indirect
43
55
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
44
56
  github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -73,6 +85,7 @@ require (
73
85
  golang.org/x/text v0.32.0 // indirect
74
86
  golang.org/x/tools v0.39.0 // indirect
75
87
  google.golang.org/protobuf v1.36.9 // indirect
88
+ gopkg.in/yaml.v2 v2.4.0 // indirect
76
89
  gorm.io/datatypes v1.2.7 // indirect
77
90
  gorm.io/driver/mysql v1.5.6 // indirect
78
91
  gorm.io/driver/postgres v1.6.0 // indirect
@@ -1,5 +1,11 @@
1
1
  filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
2
2
  filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
3
+ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
4
+ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
5
+ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
6
+ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
7
+ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
8
+ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
3
9
  github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
4
10
  github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
5
11
  github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@@ -12,6 +18,7 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
12
18
  github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
13
19
  github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
14
20
  github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
21
+ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
15
22
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
16
23
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
17
24
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -25,6 +32,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
25
32
  github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
26
33
  github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
27
34
  github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
35
+ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
36
+ github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
28
37
  github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
29
38
  github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
30
39
  github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
@@ -33,6 +42,16 @@ github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9g
33
42
  github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
34
43
  github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
35
44
  github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
45
+ github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
46
+ github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
47
+ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
48
+ github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
49
+ github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
50
+ github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
51
+ github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
52
+ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
53
+ github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
54
+ github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
36
55
  github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
37
56
  github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
38
57
  github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -75,16 +94,25 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
75
94
  github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
76
95
  github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
77
96
  github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
97
+ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
98
+ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
78
99
  github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
79
100
  github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
80
101
  github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
81
102
  github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
103
+ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
82
104
  github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
83
105
  github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
106
+ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
107
+ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
84
108
  github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
85
109
  github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
86
110
  github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
87
111
  github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
112
+ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
113
+ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
114
+ github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
115
+ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
88
116
  github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
89
117
  github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
90
118
  github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
@@ -95,6 +123,7 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OH
95
123
  github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
96
124
  github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
97
125
  github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
126
+ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
98
127
  github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
99
128
  github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
100
129
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -133,6 +162,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
133
162
  github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
134
163
  github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
135
164
  github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
165
+ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
136
166
  github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
137
167
  github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
138
168
  github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -141,6 +171,12 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
141
171
  github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
142
172
  github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
143
173
  github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
174
+ github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
175
+ github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
176
+ github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
177
+ github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
178
+ github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
179
+ github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
144
180
  github.com/tiendc/go-deepcopy v1.7.1 h1:LnubftI6nYaaMOcaz0LphzwraqN8jiWTwm416sitff4=
145
181
  github.com/tiendc/go-deepcopy v1.7.1/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
146
182
  github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
@@ -153,35 +189,71 @@ github.com/xuri/excelize/v2 v2.10.0 h1:8aKsP7JD39iKLc6dH5Tw3dgV3sPRh8uRVXu/fMstf
153
189
  github.com/xuri/excelize/v2 v2.10.0/go.mod h1:SC5TzhQkaOsTWpANfm+7bJCldzcnU/jrhqkTi/iBHBU=
154
190
  github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
155
191
  github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
192
+ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
156
193
  go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
157
194
  go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
158
195
  go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
159
196
  go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
160
197
  golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
161
198
  golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
199
+ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
200
+ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
162
201
  golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
163
202
  golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
164
203
  golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
165
204
  golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
205
+ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
166
206
  golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
167
207
  golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
208
+ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
209
+ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
210
+ golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
211
+ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
212
+ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
168
213
  golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
169
214
  golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
215
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
216
+ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
170
217
  golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
171
218
  golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
219
+ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
220
+ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
221
+ golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
222
+ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
223
+ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
224
+ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
225
+ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
172
226
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
173
227
  golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
174
228
  golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
229
+ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
230
+ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
231
+ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
232
+ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
233
+ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
234
+ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
235
+ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
236
+ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
175
237
  golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
176
238
  golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
239
+ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
240
+ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
241
+ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
177
242
  golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
178
243
  golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
244
+ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
179
245
  google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
180
246
  google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
181
247
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
248
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
249
+ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
182
250
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
183
251
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
252
+ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
253
+ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
254
+ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
184
255
  gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
256
+ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
185
257
  gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
186
258
  gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
187
259
  gorm.io/datatypes v1.2.7 h1:ww9GAhF1aGXZY3EB3cJPJ7//JiuQo7DlQA7NNlVaTdk=
@@ -0,0 +1,16 @@
1
+ package routes
2
+
3
+ import (
4
+ "github.com/gin-gonic/gin"
5
+
6
+ "github.com/robsuncn/keystone/bootstrap/config"
7
+
8
+ "__APP_NAME__/apps/server/internal/modules"
9
+ )
10
+
11
+ func registerModuleRoutes(v1 *gin.RouterGroup, cfg *config.Config) {
12
+ if v1 == nil || cfg == nil {
13
+ return
14
+ }
15
+ modules.LoadEnabled(cfg.Modules.Enabled, v1)
16
+ }