@vira-ui/cli 0.3.3-alpha → 0.4.1-alpha

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 (42) hide show
  1. package/dist/go/appYaml.js +34 -0
  2. package/dist/go/backendEnvExample.js +21 -0
  3. package/dist/go/backendReadme.js +18 -0
  4. package/dist/go/channelHelpers.js +29 -0
  5. package/dist/go/configGo.js +262 -0
  6. package/dist/go/dbGo.js +47 -0
  7. package/dist/go/dbYaml.js +11 -0
  8. package/dist/go/dockerCompose.js +38 -0
  9. package/dist/go/dockerComposeProd.js +54 -0
  10. package/dist/go/dockerfile.js +19 -0
  11. package/dist/go/eventHandlerTemplate.js +34 -0
  12. package/dist/go/eventsAPI.js +414 -0
  13. package/dist/go/goMod.js +20 -0
  14. package/dist/go/kafkaGo.js +71 -0
  15. package/dist/go/kafkaYaml.js +10 -0
  16. package/dist/go/kanbanHandlers.js +221 -0
  17. package/dist/go/mainGo.js +527 -0
  18. package/dist/go/readme.js +14 -0
  19. package/dist/go/redisGo.js +35 -0
  20. package/dist/go/redisYaml.js +8 -0
  21. package/dist/go/registryGo.js +47 -0
  22. package/dist/go/sqlcYaml.js +17 -0
  23. package/dist/go/stateStore.js +119 -0
  24. package/dist/go/typesGo.js +15 -0
  25. package/dist/go/useViraState.js +160 -0
  26. package/dist/go/useViraStream.js +167 -0
  27. package/dist/index.js +644 -192
  28. package/dist/react/appTsx.js +52 -0
  29. package/dist/react/envExample.js +7 -0
  30. package/dist/react/envLocal.js +5 -0
  31. package/dist/react/indexCss.js +22 -0
  32. package/dist/react/indexHtml.js +16 -0
  33. package/dist/react/kanbanAppTsx.js +34 -0
  34. package/dist/react/kanbanBoard.js +63 -0
  35. package/dist/react/kanbanCard.js +65 -0
  36. package/dist/react/kanbanColumn.js +67 -0
  37. package/dist/react/kanbanModels.js +37 -0
  38. package/dist/react/kanbanService.js +119 -0
  39. package/dist/react/mainTsx.js +16 -0
  40. package/dist/react/tsconfig.js +25 -0
  41. package/dist/react/viteConfig.js +31 -0
  42. package/package.json +3 -4
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appYaml = void 0;
4
+ exports.appYaml = `service: vira-engine
5
+ env: development
6
+ http:
7
+ port: 8080
8
+ logging:
9
+ level: info
10
+ db:
11
+ host: localhost
12
+ port: 5432
13
+ user: vira
14
+ password: vira
15
+ database: vira
16
+ sslmode: disable
17
+ redis:
18
+ host: localhost
19
+ port: 6379
20
+ db: 0
21
+ password: ""
22
+ kafka:
23
+ brokers:
24
+ - localhost:9092
25
+ groupId: vira-engine
26
+ topics:
27
+ events: vira.events
28
+ dlq: vira.events.dlq
29
+ state:
30
+ diffMode: merge # merge | patch
31
+ maxHistory: 100
32
+ persist: memory # memory | redis
33
+ ttlSeconds: 0 # 0 = no TTL
34
+ `;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.backendEnvExample = void 0;
4
+ exports.backendEnvExample = `PORT=8080
5
+ LOG_LEVEL=info
6
+ DB_HOST=localhost
7
+ DB_PORT=5432
8
+ DB_USER=vira
9
+ DB_PASSWORD=vira
10
+ DB_NAME=vira
11
+ DB_SSLMODE=disable
12
+ REDIS_HOST=localhost
13
+ REDIS_PORT=6379
14
+ REDIS_PASSWORD=
15
+ REDIS_DB=0
16
+ KAFKA_BROKERS=localhost:9092
17
+ KAFKA_GROUP_ID=vira-engine
18
+ KAFKA_TOPIC_EVENTS=vira.events
19
+ KAFKA_TOPIC_DLQ=vira.events.dlq
20
+ AUTH_TOKEN=
21
+ `;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.backendReadme = void 0;
4
+ exports.backendReadme = `# Vira Engine Backend (stub)
5
+
6
+ - HTTP сервер на :8080 с chi, middleware (RequestID, RealIP, Recoverer, логирование)
7
+ - Контекст: reqID (Request-ID), userID из X-User-ID
8
+ - Конфиги: config/app.yaml, db.yaml, redis.yaml, kafka.yaml (PORT/LOG_LEVEL/DB_*/REDIS_*/KAFKA_* env override)
9
+ - DB: pgx pool, sqlc.yaml scaffold (queries/, migrations/)
10
+ - Redis: go-redis v9 клиент с health/ping
11
+ - Kafka: kafka-go клиент, health/ping, writer/reader factory
12
+ - Docker: multi-stage Dockerfile для API, docker-compose.prod.yml (API+PG+Redis+Kafka)
13
+ - Дальнейшее: расширить хендлеры, миграции, Kafka outbox, Redis cache
14
+ - TODO: OTEL exporter (traces/logs/metrics)
15
+
16
+ ## Быстрый старт
17
+ go run ./cmd/api
18
+ `;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.channelHelpers = void 0;
4
+ exports.channelHelpers = `package events
5
+
6
+ import "fmt"
7
+
8
+ // Channel helpers for common entity scopes.
9
+ func ChannelUser(id any) string {
10
+ return fmt.Sprintf("user:%v", id)
11
+ }
12
+
13
+ func ChannelTask(id any) string {
14
+ return fmt.Sprintf("task:%v", id)
15
+ }
16
+
17
+ func ChannelNotifications(userID any) string {
18
+ return fmt.Sprintf("notifications:%v", userID)
19
+ }
20
+
21
+ func ChannelCustom(name string, key any) string {
22
+ return fmt.Sprintf("%s:%v", name, key)
23
+ }
24
+
25
+ // ChannelKanban returns a kanban board channel.
26
+ func ChannelKanban(boardID any) string {
27
+ return fmt.Sprintf("kanban:%v", boardID)
28
+ }
29
+ `;
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configGo = void 0;
4
+ exports.configGo = `package config
5
+
6
+ import (
7
+ "fmt"
8
+ "os"
9
+ "strconv"
10
+
11
+ "github.com/rs/zerolog"
12
+ "gopkg.in/yaml.v3"
13
+ )
14
+
15
+ type Config struct {
16
+ Service string \`yaml:"service"\`
17
+ Env string \`yaml:"env"\`
18
+ HTTP struct {
19
+ Port int \`yaml:"port"\`
20
+ } \`yaml:"http"\`
21
+ Logging struct {
22
+ Level string \`yaml:"level"\`
23
+ } \`yaml:"logging"\`
24
+ DB struct {
25
+ Host string \`yaml:"host"\`
26
+ Port int \`yaml:"port"\`
27
+ User string \`yaml:"user"\`
28
+ Password string \`yaml:"password"\`
29
+ Database string \`yaml:"database"\`
30
+ SSLMode string \`yaml:"sslmode"\`
31
+ } \`yaml:"db"\`
32
+ Kafka struct {
33
+ Brokers []string \`yaml:"brokers"\`
34
+ GroupID string \`yaml:"groupId"\`
35
+ Topics struct {
36
+ Events string \`yaml:"events"\`
37
+ DLQ string \`yaml:"dlq"\`
38
+ } \`yaml:"topics"\`
39
+ } \`yaml:"kafka"\`
40
+ Redis struct {
41
+ Host string \`yaml:"host"\`
42
+ Port int \`yaml:"port"\`
43
+ Password string \`yaml:"password"\`
44
+ DB int \`yaml:"db"\`
45
+ } \`yaml:"redis"\`
46
+ Auth struct {
47
+ Token string \`yaml:"token"\`
48
+ } \`yaml:"auth"\`
49
+ State struct {
50
+ DiffMode string \`yaml:"diffMode"\`
51
+ MaxHistory int \`yaml:"maxHistory"\`
52
+ Persist string \`yaml:"persist"\`
53
+ TTLSec int \`yaml:"ttlSeconds"\`
54
+ } \`yaml:"state"\`
55
+ }
56
+
57
+ func Load(path string) Config {
58
+ var cfg Config
59
+ data, err := os.ReadFile(path)
60
+ if err != nil {
61
+ panic(err)
62
+ }
63
+ if err := yaml.Unmarshal(data, &cfg); err != nil {
64
+ panic(err)
65
+ }
66
+
67
+ overrideEnv(&cfg)
68
+ applyDefaults(&cfg)
69
+ return cfg
70
+ }
71
+
72
+ func NewLogger(cfg Config) zerolog.Logger {
73
+ level := parseLevel(cfg.Logging.Level)
74
+ return zerolog.New(os.Stdout).
75
+ Level(level).
76
+ With().
77
+ Timestamp().
78
+ Str("service", cfg.Service).
79
+ Str("env", cfg.Env).
80
+ Logger()
81
+ }
82
+
83
+ func overrideEnv(cfg *Config) {
84
+ if port := os.Getenv("PORT"); port != "" {
85
+ if p := parsePort(port); p > 0 {
86
+ cfg.HTTP.Port = p
87
+ }
88
+ }
89
+ if lvl := os.Getenv("LOG_LEVEL"); lvl != "" {
90
+ cfg.Logging.Level = lvl
91
+ }
92
+ if host := os.Getenv("DB_HOST"); host != "" {
93
+ cfg.DB.Host = host
94
+ }
95
+ if port := os.Getenv("DB_PORT"); port != "" {
96
+ if p := parsePort(port); p > 0 {
97
+ cfg.DB.Port = p
98
+ }
99
+ }
100
+ if user := os.Getenv("DB_USER"); user != "" {
101
+ cfg.DB.User = user
102
+ }
103
+ if pass := os.Getenv("DB_PASSWORD"); pass != "" {
104
+ cfg.DB.Password = pass
105
+ }
106
+ if db := os.Getenv("DB_NAME"); db != "" {
107
+ cfg.DB.Database = db
108
+ }
109
+ if ssl := os.Getenv("DB_SSLMODE"); ssl != "" {
110
+ cfg.DB.SSLMode = ssl
111
+ }
112
+ if brokers := os.Getenv("KAFKA_BROKERS"); brokers != "" {
113
+ cfg.Kafka.Brokers = splitAndTrim(brokers)
114
+ }
115
+ if group := os.Getenv("KAFKA_GROUP_ID"); group != "" {
116
+ cfg.Kafka.GroupID = group
117
+ }
118
+ if events := os.Getenv("KAFKA_TOPIC_EVENTS"); events != "" {
119
+ cfg.Kafka.Topics.Events = events
120
+ }
121
+ if dlq := os.Getenv("KAFKA_TOPIC_DLQ"); dlq != "" {
122
+ cfg.Kafka.Topics.DLQ = dlq
123
+ }
124
+ if host := os.Getenv("REDIS_HOST"); host != "" {
125
+ cfg.Redis.Host = host
126
+ }
127
+ if port := os.Getenv("REDIS_PORT"); port != "" {
128
+ if p := parsePort(port); p > 0 {
129
+ cfg.Redis.Port = p
130
+ }
131
+ }
132
+ if pass := os.Getenv("REDIS_PASSWORD"); pass != "" {
133
+ cfg.Redis.Password = pass
134
+ }
135
+ if db := os.Getenv("REDIS_DB"); db != "" {
136
+ if p := parsePort(db); p >= 0 {
137
+ cfg.Redis.DB = p
138
+ }
139
+ }
140
+ if diff := os.Getenv("DIFF_MODE"); diff != "" {
141
+ cfg.State.DiffMode = diff
142
+ }
143
+ if hist := os.Getenv("DIFF_MAX_HISTORY"); hist != "" {
144
+ if p := parsePort(hist); p > 0 {
145
+ cfg.State.MaxHistory = p
146
+ }
147
+ }
148
+ if p := os.Getenv("STATE_PERSIST"); p != "" {
149
+ cfg.State.Persist = p
150
+ }
151
+ if ttl := os.Getenv("STATE_TTL_SECONDS"); ttl != "" {
152
+ if p := parsePort(ttl); p >= 0 {
153
+ cfg.State.TTLSec = p
154
+ }
155
+ }
156
+ }
157
+
158
+ func applyDefaults(cfg *Config) {
159
+ if cfg.HTTP.Port == 0 {
160
+ cfg.HTTP.Port = 8080
161
+ }
162
+ if cfg.Service == "" {
163
+ cfg.Service = "vira-engine"
164
+ }
165
+ if cfg.Env == "" {
166
+ cfg.Env = "development"
167
+ }
168
+ if cfg.Logging.Level == "" {
169
+ cfg.Logging.Level = "info"
170
+ }
171
+ if cfg.DB.Port == 0 {
172
+ cfg.DB.Port = 5432
173
+ }
174
+ if cfg.DB.Host == "" {
175
+ cfg.DB.Host = "localhost"
176
+ }
177
+ if cfg.DB.User == "" {
178
+ cfg.DB.User = "vira"
179
+ }
180
+ if cfg.DB.Password == "" {
181
+ cfg.DB.Password = "vira"
182
+ }
183
+ if cfg.DB.Database == "" {
184
+ cfg.DB.Database = "vira"
185
+ }
186
+ if cfg.DB.SSLMode == "" {
187
+ cfg.DB.SSLMode = "disable"
188
+ }
189
+ if len(cfg.Kafka.Brokers) == 0 {
190
+ cfg.Kafka.Brokers = []string{"localhost:9092"}
191
+ }
192
+ if cfg.Kafka.GroupID == "" {
193
+ cfg.Kafka.GroupID = "vira-engine"
194
+ }
195
+ if cfg.Kafka.Topics.Events == "" {
196
+ cfg.Kafka.Topics.Events = "vira.events"
197
+ }
198
+ if cfg.Kafka.Topics.DLQ == "" {
199
+ cfg.Kafka.Topics.DLQ = "vira.events.dlq"
200
+ }
201
+ if cfg.Redis.Port == 0 {
202
+ cfg.Redis.Port = 6379
203
+ }
204
+ if cfg.Redis.Host == "" {
205
+ cfg.Redis.Host = "localhost"
206
+ }
207
+ if cfg.Redis.DB < 0 {
208
+ cfg.Redis.DB = 0
209
+ }
210
+ if token := os.Getenv("AUTH_TOKEN"); token != "" {
211
+ cfg.Auth.Token = token
212
+ }
213
+ if cfg.State.DiffMode == "" {
214
+ cfg.State.DiffMode = "merge" // merge | patch
215
+ }
216
+ if cfg.State.MaxHistory == 0 {
217
+ cfg.State.MaxHistory = 100
218
+ }
219
+ if cfg.State.Persist == "" {
220
+ cfg.State.Persist = "memory" // memory | redis
221
+ }
222
+ if cfg.State.TTLSec < 0 {
223
+ cfg.State.TTLSec = 0
224
+ }
225
+ }
226
+
227
+ func parseLevel(lvl string) zerolog.Level {
228
+ switch lvl {
229
+ case "debug":
230
+ return zerolog.DebugLevel
231
+ case "warn":
232
+ return zerolog.WarnLevel
233
+ case "error":
234
+ return zerolog.ErrorLevel
235
+ case "fatal":
236
+ return zerolog.FatalLevel
237
+ default:
238
+ return zerolog.InfoLevel
239
+ }
240
+ }
241
+
242
+ func parsePort(val string) int {
243
+ var p int
244
+ _, err := fmt.Sscanf(val, "%d", &p)
245
+ if err != nil {
246
+ return 0
247
+ }
248
+ return p
249
+ }
250
+
251
+ func splitAndTrim(val string) []string {
252
+ parts := strings.Split(val, ",")
253
+ out := make([]string, 0, len(parts))
254
+ for _, p := range parts {
255
+ t := strings.TrimSpace(p)
256
+ if t != "" {
257
+ out = append(out, t)
258
+ }
259
+ }
260
+ return out
261
+ }
262
+ `;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dbGo = void 0;
4
+ exports.dbGo = `package db
5
+
6
+ import (
7
+ "context"
8
+ "fmt"
9
+ "time"
10
+
11
+ "github.com/jackc/pgx/v5/pgxpool"
12
+ "github.com/rs/zerolog"
13
+
14
+ "vira-engine-backend/internal/config"
15
+ )
16
+
17
+ func NewPool(ctx context.Context, cfg config.Config, logger zerolog.Logger) (*pgxpool.Pool, error) {
18
+ dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s",
19
+ cfg.DB.User,
20
+ cfg.DB.Password,
21
+ cfg.DB.Host,
22
+ cfg.DB.Port,
23
+ cfg.DB.Database,
24
+ cfg.DB.SSLMode,
25
+ )
26
+
27
+ poolConfig, err := pgxpool.ParseConfig(dsn)
28
+ if err != nil {
29
+ return nil, fmt.Errorf("parse pool config: %w", err)
30
+ }
31
+ poolConfig.MaxConnLifetime = time.Hour
32
+ poolConfig.MaxConnIdleTime = 30 * time.Minute
33
+ poolConfig.HealthCheckPeriod = 30 * time.Second
34
+
35
+ pool, err := pgxpool.NewWithConfig(ctx, poolConfig)
36
+ if err != nil {
37
+ return nil, fmt.Errorf("create pool: %w", err)
38
+ }
39
+
40
+ if err := pool.Ping(ctx); err != nil {
41
+ return nil, fmt.Errorf("ping db: %w", err)
42
+ }
43
+
44
+ logger.Info().Str("db.host", cfg.DB.Host).Int("db.port", cfg.DB.Port).Msg("db pool ready")
45
+ return pool, nil
46
+ }
47
+ `;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dbYaml = void 0;
4
+ exports.dbYaml = `driver: postgres
5
+ host: localhost
6
+ port: 5432
7
+ user: vira
8
+ password: vira
9
+ database: vira
10
+ sslmode: disable
11
+ `;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dockerCompose = void 0;
4
+ exports.dockerCompose = `version: "3.9"
5
+ services:
6
+ postgres:
7
+ image: postgres:15
8
+ environment:
9
+ POSTGRES_USER: vira
10
+ POSTGRES_PASSWORD: vira
11
+ POSTGRES_DB: vira
12
+ ports:
13
+ - "5432:5432"
14
+
15
+ redis:
16
+ image: redis:7
17
+ ports:
18
+ - "6379:6379"
19
+
20
+ zookeeper:
21
+ image: bitnami/zookeeper:3.9
22
+ environment:
23
+ ALLOW_ANONYMOUS_LOGIN: "yes"
24
+ ports:
25
+ - "2181:2181"
26
+
27
+ kafka:
28
+ image: bitnami/kafka:3.6
29
+ environment:
30
+ KAFKA_CFG_ZOOKEEPER_CONNECT: zookeeper:2181
31
+ KAFKA_CFG_LISTENERS: PLAINTEXT://:9092
32
+ KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
33
+ ALLOW_PLAINTEXT_LISTENER: "yes"
34
+ depends_on:
35
+ - zookeeper
36
+ ports:
37
+ - "9092:9092"
38
+ `;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dockerComposeProd = void 0;
4
+ exports.dockerComposeProd = `version: "3.9"
5
+ services:
6
+ postgres:
7
+ image: postgres:15
8
+ environment:
9
+ POSTGRES_USER: vira
10
+ POSTGRES_PASSWORD: vira
11
+ POSTGRES_DB: vira
12
+ volumes:
13
+ - pgdata:/var/lib/postgresql/data
14
+
15
+ redis:
16
+ image: redis:7
17
+ command: ["redis-server", "--appendonly", "yes"]
18
+ volumes:
19
+ - redisdata:/data
20
+
21
+ kafka:
22
+ image: bitnami/kafka:3.6
23
+ environment:
24
+ KAFKA_CFG_LISTENERS: PLAINTEXT://:9092
25
+ KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
26
+ ALLOW_PLAINTEXT_LISTENER: "yes"
27
+ ports:
28
+ - "9092:9092"
29
+
30
+ api:
31
+ build:
32
+ context: ../backend
33
+ depends_on:
34
+ - postgres
35
+ - redis
36
+ - kafka
37
+ environment:
38
+ PORT: 8080
39
+ DB_HOST: postgres
40
+ DB_PORT: 5432
41
+ DB_USER: vira
42
+ DB_PASSWORD: vira
43
+ DB_NAME: vira
44
+ DB_SSLMODE: disable
45
+ REDIS_HOST: redis
46
+ REDIS_PORT: 6379
47
+ KAFKA_BROKERS: kafka:9092
48
+ ports:
49
+ - "8080:8080"
50
+
51
+ volumes:
52
+ pgdata:
53
+ redisdata:
54
+ `;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dockerfile = void 0;
4
+ exports.dockerfile = `# ---- build stage ----
5
+ FROM golang:1.21-alpine AS builder
6
+ WORKDIR /app
7
+ COPY go.mod go.sum ./
8
+ RUN go mod download
9
+ COPY . .
10
+ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /app/bin/vira-api ./cmd/api
11
+
12
+ # ---- runtime stage ----
13
+ FROM gcr.io/distroless/base-debian12:nonroot
14
+ WORKDIR /app
15
+ COPY --from=builder /app/bin/vira-api /app/vira-api
16
+ COPY config ./config
17
+ EXPOSE 8080
18
+ ENTRYPOINT ["/app/vira-api"]
19
+ `;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.eventHandlerTemplate = void 0;
4
+ const eventHandlerTemplate = (name) => {
5
+ const pascal = name
6
+ .split(/[^a-zA-Z0-9]+/)
7
+ .filter(Boolean)
8
+ .map((s) => s[0].toUpperCase() + s.slice(1))
9
+ .join("");
10
+ return `package events
11
+
12
+ import (
13
+ "context"
14
+ "encoding/json"
15
+ "github.com/gorilla/websocket"
16
+ )
17
+
18
+ // ${pascal} handles event: ${name}
19
+ func ${pascal}(ctx context.Context, hub EventEmitter, conn *websocket.Conn, msg WSMessage) {
20
+ var payload map[string]any
21
+ if len(msg.Data) > 0 {
22
+ _ = json.Unmarshal(msg.Data, &payload)
23
+ }
24
+
25
+ // TODO: implement domain logic here
26
+ // Example: hub.Emit(ChannelCustom("demo", "echo"), payload)
27
+ }
28
+
29
+ func init() {
30
+ Register("${name}", ${pascal})
31
+ }
32
+ `;
33
+ };
34
+ exports.eventHandlerTemplate = eventHandlerTemplate;