@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,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stateStore = void 0;
4
+ exports.stateStore = `package events
5
+
6
+ import (
7
+ "context"
8
+ "encoding/json"
9
+ "fmt"
10
+ "time"
11
+
12
+ "github.com/redis/go-redis/v9"
13
+ )
14
+
15
+ // StateStore abstracts persist/replay of channel state.
16
+ type StateStore interface {
17
+ SaveSnapshot(ctx context.Context, channel string, snapshot StateSnapshot, ttlSec int) error
18
+ LoadSnapshot(ctx context.Context, channel string) (StateSnapshot, bool, error)
19
+ AppendHistory(ctx context.Context, channel string, snapshot StateSnapshot, maxLen int, ttlSec int) error
20
+ LoadHistory(ctx context.Context, channel string, fromVersion int64) ([]StateSnapshot, error)
21
+ }
22
+
23
+ // MemoryStore fallback (no-op persist)
24
+ type MemoryStore struct{}
25
+
26
+ func (MemoryStore) SaveSnapshot(ctx context.Context, channel string, snapshot StateSnapshot, ttlSec int) error { return nil }
27
+ func (MemoryStore) LoadSnapshot(ctx context.Context, channel string) (StateSnapshot, bool, error) {
28
+ return StateSnapshot{}, false, nil
29
+ }
30
+ func (MemoryStore) AppendHistory(ctx context.Context, channel string, snapshot StateSnapshot, maxLen int, ttlSec int) error {
31
+ return nil
32
+ }
33
+ func (MemoryStore) LoadHistory(ctx context.Context, channel string, fromVersion int64) ([]StateSnapshot, error) {
34
+ return nil, nil
35
+ }
36
+
37
+ // RedisStore persists snapshots/history into Redis.
38
+ type RedisStore struct {
39
+ client *redis.Client
40
+ }
41
+
42
+ func NewRedisStore(client *redis.Client) *RedisStore {
43
+ return &RedisStore{client: client}
44
+ }
45
+
46
+ // Keys:
47
+ // snapshot:<channel> -> json StateSnapshot
48
+ // history:<channel> -> list of json StateSnapshot (trimmed)
49
+
50
+ func snapshotKey(ch string) string { return fmt.Sprintf("snapshot:%s", ch) }
51
+ func historyKey(ch string) string { return fmt.Sprintf("history:%s", ch) }
52
+
53
+ func (s *RedisStore) SaveSnapshot(ctx context.Context, channel string, snapshot StateSnapshot, ttlSec int) error {
54
+ raw, err := json.Marshal(snapshot)
55
+ if err != nil {
56
+ return err
57
+ }
58
+ key := snapshotKey(channel)
59
+ if err := s.client.Set(ctx, key, raw, time.Duration(ttlSec)*time.Second).Err(); err != nil {
60
+ return err
61
+ }
62
+ return nil
63
+ }
64
+
65
+ func (s *RedisStore) LoadSnapshot(ctx context.Context, channel string) (StateSnapshot, bool, error) {
66
+ key := snapshotKey(channel)
67
+ val, err := s.client.Get(ctx, key).Bytes()
68
+ if err == redis.Nil {
69
+ return StateSnapshot{}, false, nil
70
+ }
71
+ if err != nil {
72
+ return StateSnapshot{}, false, err
73
+ }
74
+ var snap StateSnapshot
75
+ if err := json.Unmarshal(val, &snap); err != nil {
76
+ return StateSnapshot{}, false, err
77
+ }
78
+ return snap, true, nil
79
+ }
80
+
81
+ func (s *RedisStore) AppendHistory(ctx context.Context, channel string, snapshot StateSnapshot, maxLen int, ttlSec int) error {
82
+ raw, err := json.Marshal(snapshot)
83
+ if err != nil {
84
+ return err
85
+ }
86
+ key := historyKey(channel)
87
+ pipe := s.client.Pipeline()
88
+ pipe.RPush(ctx, key, raw)
89
+ if maxLen > 0 {
90
+ pipe.LTrim(ctx, key, int64(-maxLen), int64(-1))
91
+ }
92
+ if ttlSec > 0 {
93
+ pipe.Expire(ctx, key, time.Duration(ttlSec)*time.Second)
94
+ }
95
+ _, err = pipe.Exec(ctx)
96
+ return err
97
+ }
98
+
99
+ func (s *RedisStore) LoadHistory(ctx context.Context, channel string, fromVersion int64) ([]StateSnapshot, error) {
100
+ key := historyKey(channel)
101
+ items, err := s.client.LRange(ctx, key, 0, -1).Result()
102
+ if err == redis.Nil {
103
+ return nil, nil
104
+ }
105
+ if err != nil {
106
+ return nil, err
107
+ }
108
+ var out []StateSnapshot
109
+ for _, item := range items {
110
+ var snap StateSnapshot
111
+ if err := json.Unmarshal([]byte(item), &snap); err == nil {
112
+ if snap.VersionNo > fromVersion {
113
+ out = append(out, snap)
114
+ }
115
+ }
116
+ }
117
+ return out, nil
118
+ }
119
+ `;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.typesGo = void 0;
4
+ exports.typesGo = `package types
5
+
6
+ import "time"
7
+
8
+ // Example shared model; extend with your domain structs.
9
+ type User struct {
10
+ ID int \`json:"id"\`
11
+ Username string \`json:"username"\`
12
+ Role string \`json:"role"\`
13
+ UpdatedAt time.Time \`json:"updated_at"\`
14
+ }
15
+ `;
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useViraState = void 0;
4
+ exports.useViraState = `import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
5
+
6
+ type Message = { type: string; channel?: string; data?: any; patch?: any; ts?: number; session?: string; interval?: number; versionNo?: number };
7
+ const WS_PATH = '/ws';
8
+
9
+ export function useViraState<T = any, C extends string = string>(channel: C, initial: T | null = null) {
10
+ const [data, setData] = useState<T | null>(initial);
11
+ const wsRef = useRef<WebSocket | null>(null);
12
+ const sessionRef = useRef<string | null>(null);
13
+ const bufferRef = useRef<Array<{ send: () => void; ver: number }>>([]);
14
+ const versionRef = useRef<number>(0);
15
+ const lastSentVersionRef = useRef<number>(0);
16
+ const url = useMemo(() => {
17
+ const api = import.meta.env.VITE_API_URL || 'http://localhost:8080';
18
+ return api.replace(/^http/, 'ws') + WS_PATH;
19
+ }, []);
20
+
21
+ const sendEvent = useCallback(
22
+ (name: string, payload: any) => {
23
+ const ver = versionRef.current;
24
+ const send = () =>
25
+ wsRef.current?.send(
26
+ JSON.stringify({ type: 'event', name, channel, data: payload, ts: Date.now(), versionNo: ver })
27
+ );
28
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
29
+ send();
30
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
31
+ } else {
32
+ bufferRef.current.push({ send, ver });
33
+ }
34
+ },
35
+ [channel]
36
+ );
37
+
38
+ const sendUpdate = useCallback(
39
+ (payload: any) => {
40
+ const ver = versionRef.current;
41
+ const send = () =>
42
+ wsRef.current?.send(
43
+ JSON.stringify({ type: 'update', channel, data: payload, ts: Date.now(), versionNo: ver })
44
+ );
45
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
46
+ send();
47
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
48
+ } else {
49
+ bufferRef.current.push({ send, ver });
50
+ }
51
+ },
52
+ [channel]
53
+ );
54
+
55
+ const sendDiff = useCallback(
56
+ (patch: any) => {
57
+ const ver = versionRef.current;
58
+ const send = () =>
59
+ wsRef.current?.send(
60
+ JSON.stringify({ type: 'diff', channel, patch, ts: Date.now(), versionNo: ver })
61
+ );
62
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
63
+ send();
64
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
65
+ } else {
66
+ bufferRef.current.push({ send, ver });
67
+ }
68
+ },
69
+ [channel]
70
+ );
71
+
72
+ useEffect(() => {
73
+ if (!channel) return;
74
+ let closed = false;
75
+ let timeout = 500;
76
+
77
+ const connect = () => {
78
+ if (closed) return;
79
+ const ws = new WebSocket(url);
80
+ wsRef.current = ws;
81
+
82
+ ws.onopen = () => {
83
+ ws.send(
84
+ JSON.stringify({
85
+ type: 'handshake',
86
+ client: 'vira-react',
87
+ version: '0.1',
88
+ authToken: import.meta.env.VITE_AUTH_TOKEN || '',
89
+ ts: Date.now(),
90
+ session: sessionRef.current || undefined,
91
+ })
92
+ );
93
+ ws.send(JSON.stringify({ type: 'sub', channels: [channel] }));
94
+ // flush buffered messages
95
+ bufferRef.current.splice(0).forEach(({ send, ver }) => {
96
+ if (ver <= lastSentVersionRef.current) return;
97
+ if (ws.readyState === WebSocket.OPEN) {
98
+ send();
99
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
100
+ }
101
+ });
102
+ };
103
+
104
+ ws.onmessage = (evt) => {
105
+ try {
106
+ const msg = JSON.parse(evt.data as string) as Message;
107
+ if (msg.type === 'ack' && msg.session) {
108
+ sessionRef.current = msg.session;
109
+ }
110
+ if ((msg.type === 'update' || msg.type === 'event') && msg.channel === channel) {
111
+ if (msg.versionNo && msg.versionNo < versionRef.current) return;
112
+ if (msg.versionNo) versionRef.current = msg.versionNo;
113
+ setData(msg.data as T);
114
+ }
115
+ if (msg.type === 'diff' && msg.channel === channel && msg.patch && typeof msg.patch === 'object') {
116
+ if (msg.versionNo && msg.versionNo < versionRef.current) return;
117
+ if (msg.versionNo) versionRef.current = msg.versionNo;
118
+ setData((prev) => {
119
+ if (prev && typeof prev === 'object') {
120
+ return { ...(prev as any), ...(msg.patch as any) };
121
+ }
122
+ return (msg.patch as T) || prev;
123
+ });
124
+ }
125
+ if (msg.type === 'ping') {
126
+ ws.send(JSON.stringify({ type: 'pong', ts: Date.now() }));
127
+ }
128
+ } catch {
129
+ // ignore malformed
130
+ }
131
+ };
132
+
133
+ ws.onclose = () => {
134
+ wsRef.current = null;
135
+ if (closed) return;
136
+ setTimeout(connect, timeout);
137
+ timeout = Math.min(timeout * 2, 5000);
138
+ };
139
+
140
+ ws.onerror = () => {
141
+ ws.close();
142
+ };
143
+ };
144
+
145
+ connect();
146
+
147
+ return () => {
148
+ closed = true;
149
+ wsRef.current?.close();
150
+ };
151
+ }, [channel, url]);
152
+
153
+ return {
154
+ data,
155
+ sendEvent,
156
+ sendUpdate,
157
+ sendDiff,
158
+ };
159
+ }
160
+ `;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useViraStream = void 0;
4
+ exports.useViraStream = `import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
5
+
6
+ type Message = { type: string; channel?: string; data?: any; session?: string; interval?: number; versionNo?: number };
7
+ const WS_PATH = '/ws';
8
+
9
+ export function useViraStream<T = any, C extends string = string>(channel: C) {
10
+ const [data, setData] = useState<T | null>(null);
11
+ const wsRef = useRef<WebSocket | null>(null);
12
+ const sessionRef = useRef<string | null>(null);
13
+ const bufferRef = useRef<Array<{ msg: any; ver: number }>>([]);
14
+ const versionRef = useRef<number>(0);
15
+ const lastSentVersionRef = useRef<number>(0);
16
+ const url = useMemo(() => {
17
+ const api = import.meta.env.VITE_API_URL || 'http://localhost:8080';
18
+ return api.replace(/^http/, 'ws') + WS_PATH;
19
+ }, []);
20
+
21
+ const sendEvent = useCallback(
22
+ (name: string, payload: any, msgId?: string) => {
23
+ const ver = versionRef.current;
24
+ const msg: any = { type: 'event', name, channel, data: payload, ts: Date.now(), versionNo: ver };
25
+ if (msgId) msg.msgId = msgId;
26
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
27
+ wsRef.current.send(JSON.stringify(msg));
28
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
29
+ } else {
30
+ bufferRef.current.push({ msg, ver });
31
+ }
32
+ },
33
+ [channel]
34
+ );
35
+
36
+ const sendUpdate = useCallback(
37
+ (payload: any, msgId?: string) => {
38
+ const ver = versionRef.current;
39
+ const msg: any = { type: 'update', channel, data: payload, ts: Date.now(), versionNo: ver };
40
+ if (msgId) msg.msgId = msgId;
41
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
42
+ wsRef.current.send(JSON.stringify(msg));
43
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
44
+ } else {
45
+ bufferRef.current.push({ msg, ver });
46
+ }
47
+ },
48
+ [channel]
49
+ );
50
+
51
+ const sendDiff = useCallback(
52
+ (patch: any, msgId?: string) => {
53
+ const ver = versionRef.current;
54
+ const msg: any = { type: 'diff', channel, patch, ts: Date.now(), versionNo: ver };
55
+ if (msgId) msg.msgId = msgId;
56
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
57
+ wsRef.current.send(JSON.stringify(msg));
58
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
59
+ } else {
60
+ bufferRef.current.push({ msg, ver });
61
+ }
62
+ },
63
+ [channel]
64
+ );
65
+
66
+ useEffect(() => {
67
+ if (!channel) return;
68
+ let closed = false;
69
+ let timeout = 500;
70
+ let pingIntervalId: any;
71
+
72
+ const connect = () => {
73
+ if (closed) return;
74
+ const ws = new WebSocket(url);
75
+ wsRef.current = ws;
76
+
77
+ ws.onopen = () => {
78
+ console.log(\`WS connected to \${url}\`);
79
+ ws.send(
80
+ JSON.stringify({
81
+ type: 'handshake',
82
+ client: 'vira-react',
83
+ version: '0.1',
84
+ authToken: import.meta.env.VITE_AUTH_TOKEN || '',
85
+ session: sessionRef.current || undefined,
86
+ ts: Date.now(),
87
+ })
88
+ );
89
+ ws.send(JSON.stringify({ type: 'sub', channels: [channel] }));
90
+ // Resend buffered messages
91
+ const buffered = bufferRef.current.splice(0);
92
+ buffered.forEach(({ msg, ver }) => {
93
+ if (ver <= lastSentVersionRef.current) return;
94
+ if (ws.readyState === WebSocket.OPEN) {
95
+ ws.send(JSON.stringify(msg));
96
+ lastSentVersionRef.current = Math.max(lastSentVersionRef.current, ver);
97
+ }
98
+ });
99
+ timeout = 500; // Reset timeout on successful connection
100
+ };
101
+
102
+ ws.onmessage = (evt) => {
103
+ try {
104
+ const msg = JSON.parse(evt.data as string) as Message;
105
+ if (msg.type === 'ack' && msg.session) {
106
+ sessionRef.current = msg.session;
107
+ if (msg.interval) {
108
+ clearInterval(pingIntervalId);
109
+ pingIntervalId = setInterval(() => {
110
+ if (ws.readyState === WebSocket.OPEN) {
111
+ ws.send(JSON.stringify({ type: 'ping', ts: Date.now() }));
112
+ }
113
+ }, msg.interval);
114
+ }
115
+ }
116
+ if ((msg.type === 'update' || msg.type === 'event') && msg.channel === channel) {
117
+ if (msg.versionNo && msg.versionNo < versionRef.current) return;
118
+ if (msg.versionNo) versionRef.current = msg.versionNo;
119
+ setData(msg.data as T);
120
+ }
121
+ if (msg.type === 'diff' && msg.channel === channel && msg.patch && typeof msg.patch === 'object') {
122
+ setData((prev) => {
123
+ if (prev && typeof prev === 'object') {
124
+ return { ...(prev as any), ...(msg.patch as any) };
125
+ }
126
+ return (msg.patch as T) || prev;
127
+ });
128
+ }
129
+ if (msg.type === 'ping') {
130
+ ws.send(JSON.stringify({ type: 'pong', ts: Date.now() }));
131
+ }
132
+ } catch {
133
+ // ignore malformed
134
+ }
135
+ };
136
+
137
+ ws.onclose = () => {
138
+ console.log('WS disconnected. Reconnecting...');
139
+ wsRef.current = null;
140
+ clearInterval(pingIntervalId);
141
+ if (closed) return;
142
+ setTimeout(connect, timeout);
143
+ timeout = Math.min(timeout * 2, 30000); // Max 30 seconds
144
+ };
145
+
146
+ ws.onerror = () => {
147
+ ws.close();
148
+ };
149
+ };
150
+
151
+ connect();
152
+
153
+ return () => {
154
+ closed = true;
155
+ clearInterval(pingIntervalId);
156
+ wsRef.current?.close();
157
+ };
158
+ }, [channel, url]);
159
+
160
+ return {
161
+ data,
162
+ sendEvent,
163
+ sendUpdate,
164
+ sendDiff,
165
+ };
166
+ }
167
+ `;