@vira-ui/cli 0.4.1-alpha → 1.0.1

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.
@@ -4,259 +4,259 @@ exports.configGo = void 0;
4
4
  exports.configGo = `package config
5
5
 
6
6
  import (
7
- "fmt"
8
- "os"
9
- "strconv"
7
+ "fmt"
8
+ "os"
9
+ "strings"
10
10
 
11
- "github.com/rs/zerolog"
12
- "gopkg.in/yaml.v3"
11
+ "github.com/rs/zerolog"
12
+ "gopkg.in/yaml.v3"
13
13
  )
14
14
 
15
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"\`
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
55
  }
56
56
 
57
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
- }
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
66
 
67
- overrideEnv(&cfg)
68
- applyDefaults(&cfg)
69
- return cfg
67
+ overrideEnv(&cfg)
68
+ applyDefaults(&cfg)
69
+ return cfg
70
70
  }
71
71
 
72
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()
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
81
  }
82
82
 
83
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
- }
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
156
  }
157
157
 
158
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
- }
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
225
  }
226
226
 
227
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
- }
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
240
  }
241
241
 
242
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
243
+ var p int
244
+ _, err := fmt.Sscanf(val, "%d", &p)
245
+ if err != nil {
246
+ return 0
247
+ }
248
+ return p
249
249
  }
250
250
 
251
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
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
261
  }
262
262
  `;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dockerCompose = void 0;
4
- exports.dockerCompose = `version: "3.9"
4
+ exports.dockerCompose = `
5
5
  services:
6
6
  postgres:
7
7
  image: postgres:15
@@ -18,21 +18,35 @@ services:
18
18
  - "6379:6379"
19
19
 
20
20
  zookeeper:
21
- image: bitnami/zookeeper:3.9
21
+ image: confluentinc/cp-zookeeper:7.5.0
22
22
  environment:
23
- ALLOW_ANONYMOUS_LOGIN: "yes"
23
+ ZOOKEEPER_CLIENT_PORT: 2181
24
+ ZOOKEEPER_TICK_TIME: 2000
24
25
  ports:
25
26
  - "2181:2181"
27
+ healthcheck:
28
+ test: ["CMD-SHELL", "nc -z localhost 2181 || exit 1"]
29
+ interval: 10s
30
+ timeout: 5s
31
+ retries: 5
26
32
 
27
33
  kafka:
28
- image: bitnami/kafka:3.6
34
+ image: confluentinc/cp-kafka:7.5.0
29
35
  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"
36
+ KAFKA_BROKER_ID: 1
37
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
38
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
39
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
40
+ KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
34
41
  depends_on:
35
- - zookeeper
42
+ zookeeper:
43
+ condition: service_healthy
36
44
  ports:
37
45
  - "9092:9092"
46
+ healthcheck:
47
+ test: ["CMD-SHELL", "kafka-broker-api-versions --bootstrap-server localhost:9092 || exit 1"]
48
+ interval: 30s
49
+ timeout: 10s
50
+ retries: 5
51
+ start_period: 60s
38
52
  `;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.dockerComposeProd = void 0;
4
- exports.dockerComposeProd = `version: "3.9"
4
+ exports.dockerComposeProd = `
5
5
  services:
6
6
  postgres:
7
7
  image: postgres:15
@@ -18,14 +18,40 @@ services:
18
18
  volumes:
19
19
  - redisdata:/data
20
20
 
21
+ zookeeper:
22
+ image: confluentinc/cp-zookeeper:7.5.0
23
+ environment:
24
+ ZOOKEEPER_CLIENT_PORT: 2181
25
+ ZOOKEEPER_TICK_TIME: 2000
26
+ volumes:
27
+ - zookeeper-data:/var/lib/zookeeper/data
28
+ healthcheck:
29
+ test: ["CMD-SHELL", "nc -z localhost 2181 || exit 1"]
30
+ interval: 10s
31
+ timeout: 5s
32
+ retries: 5
33
+
21
34
  kafka:
22
- image: bitnami/kafka:3.6
35
+ image: confluentinc/cp-kafka:7.5.0
23
36
  environment:
24
- KAFKA_CFG_LISTENERS: PLAINTEXT://:9092
25
- KAFKA_CFG_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
26
- ALLOW_PLAINTEXT_LISTENER: "yes"
37
+ KAFKA_BROKER_ID: 1
38
+ KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
39
+ KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092
40
+ KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
41
+ KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
42
+ depends_on:
43
+ zookeeper:
44
+ condition: service_healthy
27
45
  ports:
28
46
  - "9092:9092"
47
+ volumes:
48
+ - kafka-data:/var/lib/kafka/data
49
+ healthcheck:
50
+ test: ["CMD-SHELL", "kafka-broker-api-versions --bootstrap-server localhost:9092 || exit 1"]
51
+ interval: 30s
52
+ timeout: 10s
53
+ retries: 5
54
+ start_period: 60s
29
55
 
30
56
  api:
31
57
  build:
@@ -51,4 +77,6 @@ services:
51
77
  volumes:
52
78
  pgdata:
53
79
  redisdata:
80
+ zookeeper-data:
81
+ kafka-data:
54
82
  `;
@@ -16,6 +16,11 @@ import (
16
16
  // VRP_VERSION is the current protocol version.
17
17
  const VRP_VERSION = "0.1"
18
18
 
19
+ // ProtocolVersion returns the current VRP version.
20
+ func ProtocolVersion() string {
21
+ return VRP_VERSION
22
+ }
23
+
19
24
  // WSMessage matches protocol message schema.
20
25
  type WSMessage struct {
21
26
  Type string \`json:"type"\`
@@ -70,6 +75,8 @@ type Hub struct {
70
75
  maxHistory int
71
76
  store StateStore
72
77
  ttlSec int
78
+ msgIDs map[string]int64 // msgId -> timestamp cache for dedup (bounded)
79
+ maxMsgIDs int
73
80
  }
74
81
 
75
82
  // StateSnapshot stores a versioned state snapshot.
@@ -285,16 +292,10 @@ func (h *Hub) applyUpdate(channel string, payload any, force bool) {
285
292
  if !force && prev != nil {
286
293
  var patch json.RawMessage
287
294
  var err error
288
- if h.diffMode == DiffModePatch {
289
- // Generate RFC 6902 JSON Patch
290
- patchOps, err := jsonpatch.CreatePatch(prev, newData)
291
- if err == nil {
292
- patch, _ = json.Marshal(patchOps)
293
- }
294
- } else {
295
- // Generate RFC 7396 JSON Merge Patch
296
- patch, err = jsonpatch.CreateMergePatch(prev, newData)
297
- }
295
+ // Note: json-patch/v5 only supports CreateMergePatch (RFC 7396)
296
+ // For RFC 6902 JSON Patch, we'd need a different library or custom implementation
297
+ // For now, always use merge patch regardless of diffMode setting
298
+ patch, err = jsonpatch.CreateMergePatch(prev, newData)
298
299
  if err == nil && len(patch) > 2 {
299
300
  h.applyDiff(channel, patch)
300
301
  return