@revealui/sync 0.2.0 → 0.3.0
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.
- package/README.md +82 -118
- package/dist/collab/agent-client-factory.d.ts.map +1 -1
- package/dist/collab/agent-client.d.ts +1 -0
- package/dist/collab/agent-client.d.ts.map +1 -1
- package/dist/collab/agent-client.js +16 -7
- package/dist/collab/index.d.ts +1 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +1 -0
- package/dist/collab/protocol-constants.d.ts +5 -0
- package/dist/collab/protocol-constants.d.ts.map +1 -0
- package/dist/collab/protocol-constants.js +4 -0
- package/dist/collab/server-index.d.ts +1 -0
- package/dist/collab/server-index.d.ts.map +1 -1
- package/dist/collab/server-index.js +1 -0
- package/dist/collab/use-collab-document.d.ts +1 -1
- package/dist/collab/use-collab-document.d.ts.map +1 -1
- package/dist/collab/use-collab-document.js +7 -4
- package/dist/collab/use-collaboration.d.ts.map +1 -1
- package/dist/collab/yjs-websocket-provider.d.ts.map +1 -1
- package/dist/collab/yjs-websocket-provider.js +1 -2
- package/dist/fetch-with-timeout.d.ts +7 -0
- package/dist/fetch-with-timeout.d.ts.map +1 -0
- package/dist/fetch-with-timeout.js +27 -0
- package/dist/hooks/useAgentContexts.d.ts +29 -0
- package/dist/hooks/useAgentContexts.d.ts.map +1 -0
- package/dist/hooks/useAgentContexts.js +22 -0
- package/dist/hooks/useAgentMemory.d.ts +34 -0
- package/dist/hooks/useAgentMemory.d.ts.map +1 -0
- package/dist/hooks/useAgentMemory.js +37 -0
- package/dist/hooks/useConversations.d.ts +26 -6
- package/dist/hooks/useConversations.d.ts.map +1 -1
- package/dist/hooks/useConversations.js +13 -3
- package/dist/hooks/useCoordinationSessions.d.ts +35 -0
- package/dist/hooks/useCoordinationSessions.d.ts.map +1 -0
- package/dist/hooks/useCoordinationSessions.js +22 -0
- package/dist/hooks/useCoordinationWorkItems.d.ts +41 -0
- package/dist/hooks/useCoordinationWorkItems.d.ts.map +1 -0
- package/dist/hooks/useCoordinationWorkItems.js +22 -0
- package/dist/index.d.ts +22 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/mutations.d.ts +14 -0
- package/dist/mutations.d.ts.map +1 -0
- package/dist/mutations.js +53 -0
- package/dist/provider/index.d.ts +31 -3
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +27 -6
- package/dist/shape-utils.d.ts +11 -0
- package/dist/shape-utils.d.ts.map +1 -0
- package/dist/shape-utils.js +14 -0
- package/dist/test-setup.d.ts.map +1 -1
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
# @revealui/sync
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
See [Project Status](../../docs/PROJECT_STATUS.md) for framework readiness.
|
|
6
|
-
|
|
7
|
-
ElectricSQL sync utilities for RevealUI - real-time data synchronization with local-first architecture.
|
|
3
|
+
ElectricSQL sync utilities for RevealUI — real-time data synchronization with local-first architecture.
|
|
8
4
|
|
|
9
5
|
## Features
|
|
10
6
|
|
|
11
|
-
- **ElectricSQL Integration**: Real-time sync
|
|
12
|
-
- **React Hooks**:
|
|
7
|
+
- **ElectricSQL Integration**: Real-time sync via shape subscriptions
|
|
8
|
+
- **React Hooks**: Subscribe to synced data in React components
|
|
9
|
+
- **Mutations**: Create, update, and delete records via authenticated REST endpoints
|
|
13
10
|
- **Type-safe**: Full TypeScript support with database types
|
|
14
|
-
- **Local-first**: Works offline, syncs when online
|
|
15
11
|
- **React Provider**: Easy setup with `ElectricProvider`
|
|
16
|
-
- **
|
|
12
|
+
- **Yjs Collaboration**: CRDT-based real-time collaborative editing
|
|
17
13
|
|
|
18
14
|
## Installation
|
|
19
15
|
|
|
@@ -32,27 +28,29 @@ import { ElectricProvider } from '@revealui/sync/provider'
|
|
|
32
28
|
|
|
33
29
|
export default function App() {
|
|
34
30
|
return (
|
|
35
|
-
<ElectricProvider>
|
|
31
|
+
<ElectricProvider proxyBaseUrl="https://cms.revealui.com">
|
|
36
32
|
<YourComponents />
|
|
37
33
|
</ElectricProvider>
|
|
38
34
|
)
|
|
39
35
|
}
|
|
40
36
|
```
|
|
41
37
|
|
|
42
|
-
###
|
|
38
|
+
### Read Synced Data
|
|
39
|
+
|
|
40
|
+
Hooks subscribe to ElectricSQL shapes via authenticated proxy routes. Data updates in real-time as the database changes.
|
|
43
41
|
|
|
44
42
|
```typescript
|
|
45
43
|
import { useAgentContexts } from '@revealui/sync'
|
|
46
44
|
|
|
47
45
|
function MyComponent() {
|
|
48
|
-
const {
|
|
46
|
+
const { contexts, isLoading } = useAgentContexts()
|
|
49
47
|
|
|
50
48
|
if (isLoading) return <div>Loading...</div>
|
|
51
49
|
|
|
52
50
|
return (
|
|
53
51
|
<ul>
|
|
54
52
|
{contexts.map(context => (
|
|
55
|
-
<li key={context.id}>{context.
|
|
53
|
+
<li key={context.id}>{JSON.stringify(context.context)}</li>
|
|
56
54
|
))}
|
|
57
55
|
</ul>
|
|
58
56
|
)
|
|
@@ -61,18 +59,29 @@ function MyComponent() {
|
|
|
61
59
|
|
|
62
60
|
### Mutations
|
|
63
61
|
|
|
62
|
+
Each hook returns `create`, `update`, and `remove` functions. Mutations go through authenticated REST endpoints at `/api/sync/*`. ElectricSQL picks up the database changes and pushes updates to all subscribers automatically.
|
|
63
|
+
|
|
64
64
|
```typescript
|
|
65
65
|
import { useAgentContexts } from '@revealui/sync'
|
|
66
66
|
|
|
67
67
|
function CreateContext() {
|
|
68
|
-
const { create } = useAgentContexts()
|
|
68
|
+
const { contexts, create, update, remove } = useAgentContexts()
|
|
69
69
|
|
|
70
70
|
const handleCreate = async () => {
|
|
71
|
-
await create({
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const result = await create({
|
|
72
|
+
agent_id: 'assistant',
|
|
73
|
+
context: { theme: 'dark', language: 'en' },
|
|
74
|
+
priority: 0.8,
|
|
75
75
|
})
|
|
76
|
+
if (!result.success) console.error(result.error)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const handleUpdate = async (id: string) => {
|
|
80
|
+
await update(id, { context: { theme: 'light' } })
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const handleDelete = async (id: string) => {
|
|
84
|
+
await remove(id)
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
return <button onClick={handleCreate}>Create</button>
|
|
@@ -83,141 +92,96 @@ function CreateContext() {
|
|
|
83
92
|
|
|
84
93
|
### `useAgentContexts()`
|
|
85
94
|
|
|
86
|
-
|
|
95
|
+
Subscribe to agent contexts (task context, working memory).
|
|
87
96
|
|
|
88
97
|
```typescript
|
|
89
98
|
const {
|
|
90
|
-
|
|
91
|
-
isLoading, //
|
|
92
|
-
error, // Error
|
|
93
|
-
create, //
|
|
94
|
-
update, //
|
|
95
|
-
remove
|
|
99
|
+
contexts, // AgentContextRecord[]
|
|
100
|
+
isLoading, // boolean
|
|
101
|
+
error, // Error | null
|
|
102
|
+
create, // (data: CreateAgentContextInput) => Promise<MutationResult>
|
|
103
|
+
update, // (id: string, data: UpdateAgentContextInput) => Promise<MutationResult>
|
|
104
|
+
remove, // (id: string) => Promise<MutationResult>
|
|
96
105
|
} = useAgentContexts()
|
|
97
106
|
```
|
|
98
107
|
|
|
99
|
-
### `useAgentMemory()`
|
|
108
|
+
### `useAgentMemory(agentId)`
|
|
100
109
|
|
|
101
|
-
|
|
110
|
+
Subscribe to agent memory (episodic, semantic, working) filtered by agent ID.
|
|
102
111
|
|
|
103
112
|
```typescript
|
|
104
113
|
const {
|
|
105
|
-
|
|
106
|
-
isLoading,
|
|
107
|
-
error,
|
|
108
|
-
create,
|
|
109
|
-
update,
|
|
110
|
-
remove
|
|
111
|
-
} = useAgentMemory()
|
|
114
|
+
memories, // AgentMemoryRecord[]
|
|
115
|
+
isLoading, // boolean
|
|
116
|
+
error, // Error | null
|
|
117
|
+
create, // (data: CreateAgentMemoryInput) => Promise<MutationResult>
|
|
118
|
+
update, // (id: string, data: UpdateAgentMemoryInput) => Promise<MutationResult>
|
|
119
|
+
remove, // (id: string) => Promise<MutationResult>
|
|
120
|
+
} = useAgentMemory('assistant')
|
|
112
121
|
```
|
|
113
122
|
|
|
114
|
-
### `useConversations()`
|
|
123
|
+
### `useConversations(userId)`
|
|
115
124
|
|
|
116
|
-
|
|
125
|
+
Subscribe to conversation history. Server-side proxy enforces row-level filtering by session — the `userId` parameter is for API compatibility but filtering is handled server-side.
|
|
117
126
|
|
|
118
127
|
```typescript
|
|
119
128
|
const {
|
|
120
|
-
|
|
121
|
-
isLoading,
|
|
122
|
-
error,
|
|
123
|
-
create,
|
|
124
|
-
update,
|
|
125
|
-
remove
|
|
126
|
-
} = useConversations()
|
|
129
|
+
conversations, // ConversationRecord[]
|
|
130
|
+
isLoading, // boolean
|
|
131
|
+
error, // Error | null
|
|
132
|
+
create, // (data: CreateConversationInput) => Promise<MutationResult>
|
|
133
|
+
update, // (id: string, data: UpdateConversationInput) => Promise<MutationResult>
|
|
134
|
+
remove, // (id: string) => Promise<MutationResult>
|
|
135
|
+
} = useConversations(userId)
|
|
127
136
|
```
|
|
128
137
|
|
|
129
138
|
## How It Works
|
|
130
139
|
|
|
131
|
-
1. **
|
|
132
|
-
2. **
|
|
133
|
-
3. **
|
|
134
|
-
4. **
|
|
135
|
-
5. **Conflict Resolution**: CRDT-based conflict resolution for offline edits
|
|
140
|
+
1. **Reads**: ElectricSQL shape subscriptions via authenticated CMS proxy (`/api/shapes/*`)
|
|
141
|
+
2. **Writes**: REST mutations via CMS API (`/api/sync/*`) → Postgres → ElectricSQL replication
|
|
142
|
+
3. **Real-time**: Database changes propagate to all shape subscribers automatically
|
|
143
|
+
4. **Auth**: All endpoints require a valid session cookie
|
|
136
144
|
|
|
137
|
-
##
|
|
145
|
+
## Collaboration (Yjs)
|
|
138
146
|
|
|
139
|
-
|
|
140
|
-
# ElectricSQL service URL
|
|
141
|
-
NEXT_PUBLIC_ELECTRIC_SERVICE_URL=http://localhost:5133
|
|
147
|
+
The collab layer provides CRDT-based collaborative editing:
|
|
142
148
|
|
|
143
|
-
|
|
144
|
-
|
|
149
|
+
```typescript
|
|
150
|
+
import { useCollaboration } from '@revealui/sync'
|
|
151
|
+
|
|
152
|
+
function Editor() {
|
|
153
|
+
const { doc, synced, connectedUsers } = useCollaboration({
|
|
154
|
+
documentId: 'doc-uuid',
|
|
155
|
+
serverUrl: 'ws://localhost:4000',
|
|
156
|
+
})
|
|
157
|
+
// ...
|
|
158
|
+
}
|
|
145
159
|
```
|
|
146
160
|
|
|
147
|
-
|
|
161
|
+
Server-side agents can use `AgentCollabClient` from `@revealui/sync/collab/server`.
|
|
148
162
|
|
|
149
|
-
|
|
150
|
-
# Build package
|
|
151
|
-
pnpm --filter @revealui/sync build
|
|
163
|
+
## Environment Variables
|
|
152
164
|
|
|
153
|
-
|
|
154
|
-
|
|
165
|
+
```env
|
|
166
|
+
# ElectricSQL service URL (used by CMS proxy)
|
|
167
|
+
ELECTRIC_SERVICE_URL=http://localhost:5133
|
|
155
168
|
|
|
156
|
-
#
|
|
157
|
-
|
|
169
|
+
# Optional: Electric auth secret
|
|
170
|
+
ELECTRIC_SECRET=your-secret
|
|
158
171
|
|
|
159
|
-
#
|
|
160
|
-
|
|
172
|
+
# Client-side (stored in provider context)
|
|
173
|
+
NEXT_PUBLIC_ELECTRIC_SERVICE_URL=http://localhost:5133
|
|
161
174
|
```
|
|
162
175
|
|
|
163
|
-
##
|
|
176
|
+
## Development
|
|
164
177
|
|
|
165
178
|
```bash
|
|
166
|
-
|
|
167
|
-
pnpm --filter @revealui/sync
|
|
168
|
-
|
|
169
|
-
#
|
|
170
|
-
pnpm --filter @revealui/sync test:watch
|
|
171
|
-
|
|
172
|
-
# Coverage
|
|
173
|
-
pnpm --filter @revealui/sync test:coverage
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
## Architecture
|
|
177
|
-
|
|
178
|
-
```
|
|
179
|
-
┌─────────────────┐
|
|
180
|
-
│ React Component │
|
|
181
|
-
│ (useAgentContexts) │
|
|
182
|
-
└────────┬────────┘
|
|
183
|
-
│
|
|
184
|
-
▼
|
|
185
|
-
┌─────────────────┐
|
|
186
|
-
│ ElectricSQL │
|
|
187
|
-
│ Shape Hook │
|
|
188
|
-
└────────┬────────┘
|
|
189
|
-
│
|
|
190
|
-
▼
|
|
191
|
-
┌─────────────────┐
|
|
192
|
-
│ Electric Sync │
|
|
193
|
-
│ Service │
|
|
194
|
-
└────────┬────────┘
|
|
195
|
-
│
|
|
196
|
-
▼
|
|
197
|
-
┌─────────────────┐
|
|
198
|
-
│ PostgreSQL │
|
|
199
|
-
│ Database │
|
|
200
|
-
└─────────────────┘
|
|
179
|
+
pnpm --filter @revealui/sync build # Build
|
|
180
|
+
pnpm --filter @revealui/sync dev # Watch mode
|
|
181
|
+
pnpm --filter @revealui/sync test # Run tests
|
|
182
|
+
pnpm --filter @revealui/sync typecheck # Type check
|
|
201
183
|
```
|
|
202
184
|
|
|
203
|
-
## Limitations
|
|
204
|
-
|
|
205
|
-
⚠️ **CRITICAL**: ElectricSQL API endpoints need independent verification before production use.
|
|
206
|
-
|
|
207
|
-
**Status:** ⚠️ NEEDS VERIFICATION
|
|
208
|
-
- ElectricSQL integration exists but requires testing
|
|
209
|
-
- API endpoints based on assumptions
|
|
210
|
-
- No integration tests performed yet
|
|
211
|
-
- Not recommended for production until verified
|
|
212
|
-
|
|
213
|
-
See [Project Roadmap](../../docs/PROJECT_ROADMAP.md) and [Production Readiness](../../docs/PRODUCTION_READINESS.md) for details.
|
|
214
|
-
|
|
215
|
-
## Related Documentation
|
|
216
|
-
|
|
217
|
-
- [ElectricSQL Documentation](https://electric-sql.com/docs) - Official ElectricSQL docs
|
|
218
|
-
- [Architecture](../../docs/ARCHITECTURE.md) - System architecture overview
|
|
219
|
-
- [Database Guide](../../docs/DATABASE.md) - Database setup
|
|
220
|
-
|
|
221
185
|
## License
|
|
222
186
|
|
|
223
187
|
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-client-factory.d.ts","sourceRoot":"","sources":["../../src/collab/agent-client-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAsB,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"agent-client-factory.d.ts","sourceRoot":"","sources":["../../src/collab/agent-client-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAsB,MAAM,mBAAmB,CAAC;AAI1E,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAgBtF;AAED,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,wBAAwB,GAAG;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D,OAAO,CAAC,iBAAiB,CAAC,CAK5B"}
|
|
@@ -31,6 +31,7 @@ export declare class AgentCollabClient extends Observable<string> {
|
|
|
31
31
|
private updateHandler;
|
|
32
32
|
private awarenessUpdateHandler;
|
|
33
33
|
private destroyed;
|
|
34
|
+
private pendingSyncAbort;
|
|
34
35
|
constructor(options: AgentCollabClientOptions);
|
|
35
36
|
connect(): void;
|
|
36
37
|
disconnect(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-client.d.ts","sourceRoot":"","sources":["../../src/collab/agent-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"agent-client.d.ts","sourceRoot":"","sources":["../../src/collab/agent-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAOzB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,aAAa,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,iBAAkB,SAAQ,UAAU,CAAC,MAAM,CAAC;IACvD,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC,SAAS,CAAC;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IAEzC,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,aAAa,CAAgE;IACrF,OAAO,CAAC,sBAAsB,CAGpB;IACV,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,gBAAgB,CAA6B;gBAEzC,OAAO,EAAE,wBAAwB;IA0B7C,OAAO,IAAI,IAAI;IAcf,UAAU,IAAI,IAAI;IAkBlB,WAAW,IAAI,CAAC,CAAC,GAAG;IAIpB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI;IAI9B,cAAc,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAIrC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAI/D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAI9D,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAQhD,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI;IAU5D,iBAAiB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAUzD,WAAW,CAAC,SAAS,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B5C,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,UAAU;IAoClB,OAAO,CAAC,aAAa;IAoCrB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,eAAe;CAOxB"}
|
|
@@ -5,8 +5,7 @@ import WebSocket from 'ws';
|
|
|
5
5
|
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
6
6
|
import * as syncProtocol from 'y-protocols/sync';
|
|
7
7
|
import * as Y from 'yjs';
|
|
8
|
-
|
|
9
|
-
const MESSAGE_AWARENESS = 1;
|
|
8
|
+
import { MESSAGE_AWARENESS, MESSAGE_SYNC } from './protocol-constants.js';
|
|
10
9
|
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
11
10
|
const BASE_RECONNECT_DELAY = 1000;
|
|
12
11
|
const RECONNECT_MULTIPLIER = 2;
|
|
@@ -26,6 +25,7 @@ export class AgentCollabClient extends Observable {
|
|
|
26
25
|
updateHandler = null;
|
|
27
26
|
awarenessUpdateHandler;
|
|
28
27
|
destroyed = false;
|
|
28
|
+
pendingSyncAbort = null;
|
|
29
29
|
constructor(options) {
|
|
30
30
|
super();
|
|
31
31
|
this.serverUrl = options.serverUrl;
|
|
@@ -83,8 +83,6 @@ export class AgentCollabClient extends Observable {
|
|
|
83
83
|
return this.doc.getText(name ?? this.defaultTextName);
|
|
84
84
|
}
|
|
85
85
|
getTextContent(name) {
|
|
86
|
-
// Y.Text.toString() returns the text content — ESLint doesn't recognize this
|
|
87
|
-
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
88
86
|
return this.getText(name).toString();
|
|
89
87
|
}
|
|
90
88
|
insertText(index, content, name) {
|
|
@@ -122,22 +120,33 @@ export class AgentCollabClient extends Observable {
|
|
|
122
120
|
if (this.synced)
|
|
123
121
|
return Promise.resolve();
|
|
124
122
|
return new Promise((resolve, reject) => {
|
|
125
|
-
const
|
|
123
|
+
const cleanup = () => {
|
|
124
|
+
clearTimeout(timeout);
|
|
126
125
|
this.off('sync', handler);
|
|
126
|
+
if (this.pendingSyncAbort === abort)
|
|
127
|
+
this.pendingSyncAbort = null;
|
|
128
|
+
};
|
|
129
|
+
const timeout = setTimeout(() => {
|
|
130
|
+
cleanup();
|
|
127
131
|
reject(new Error(`Sync timeout after ${timeoutMs}ms`));
|
|
128
132
|
}, timeoutMs);
|
|
129
133
|
const handler = (isSynced) => {
|
|
130
134
|
if (isSynced) {
|
|
131
|
-
|
|
132
|
-
this.off('sync', handler);
|
|
135
|
+
cleanup();
|
|
133
136
|
resolve();
|
|
134
137
|
}
|
|
135
138
|
};
|
|
139
|
+
const abort = () => {
|
|
140
|
+
cleanup();
|
|
141
|
+
reject(new Error('Client destroyed while waiting for sync'));
|
|
142
|
+
};
|
|
143
|
+
this.pendingSyncAbort = abort;
|
|
136
144
|
this.on('sync', handler);
|
|
137
145
|
});
|
|
138
146
|
}
|
|
139
147
|
destroy() {
|
|
140
148
|
this.destroyed = true;
|
|
149
|
+
this.pendingSyncAbort?.();
|
|
141
150
|
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
142
151
|
this.disconnect();
|
|
143
152
|
this.awareness.destroy();
|
package/dist/collab/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { MESSAGE_AWARENESS, MESSAGE_SYNC } from './protocol-constants.js';
|
|
1
2
|
export type { CollabDocumentState } from './use-collab-document.js';
|
|
2
3
|
export { useCollabDocument } from './use-collab-document.js';
|
|
3
4
|
export type { CollaborationIdentity, UseCollaborationOptions, UseCollaborationResult, } from './use-collaboration.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collab/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collab/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC1E,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EACV,qBAAqB,EACrB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/collab/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol-constants.d.ts","sourceRoot":"","sources":["../../src/collab/protocol-constants.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,0CAA0C;AAC1C,eAAO,MAAM,iBAAiB,IAAI,CAAC"}
|
|
@@ -2,4 +2,5 @@ export type { AgentCollabClientOptions, AgentIdentity } from './agent-client.js'
|
|
|
2
2
|
export { AgentCollabClient } from './agent-client.js';
|
|
3
3
|
export type { CreateAgentClientOptions } from './agent-client-factory.js';
|
|
4
4
|
export { createAgentClient, createAndConnectAgentClient } from './agent-client-factory.js';
|
|
5
|
+
export { MESSAGE_AWARENESS, MESSAGE_SYNC } from './protocol-constants.js';
|
|
5
6
|
//# sourceMappingURL=server-index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-index.d.ts","sourceRoot":"","sources":["../../src/collab/server-index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"server-index.d.ts","sourceRoot":"","sources":["../../src/collab/server-index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -4,5 +4,5 @@ export interface CollabDocumentState {
|
|
|
4
4
|
isLoading: boolean;
|
|
5
5
|
error: Error | null;
|
|
6
6
|
}
|
|
7
|
-
export declare function useCollabDocument(documentId: string
|
|
7
|
+
export declare function useCollabDocument(documentId: string): CollabDocumentState;
|
|
8
8
|
//# sourceMappingURL=use-collab-document.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-collab-document.d.ts","sourceRoot":"","sources":["../../src/collab/use-collab-document.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-collab-document.d.ts","sourceRoot":"","sources":["../../src/collab/use-collab-document.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAKD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,CAiDzE"}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { useShape } from '@electric-sql/react';
|
|
2
|
+
import { fetchWithTimeout } from '../fetch-with-timeout.js';
|
|
3
|
+
import { useElectricConfig } from '../provider/index.js';
|
|
2
4
|
// UUID v4 pattern — only format accepted as a yjs_documents PK
|
|
3
5
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4
|
-
export function useCollabDocument(documentId
|
|
6
|
+
export function useCollabDocument(documentId) {
|
|
7
|
+
const { proxyBaseUrl } = useElectricConfig();
|
|
5
8
|
// Validate before interpolating into the WHERE clause. yjs_documents PKs are
|
|
6
9
|
// always UUIDs — reject anything else so no untrusted string enters the query.
|
|
7
10
|
const isValidId = UUID_RE.test(documentId);
|
|
8
11
|
// Hook must always be called (Rules of Hooks). Pass an impossible WHERE when
|
|
9
12
|
// the ID is invalid so the shape returns no rows but the hook still runs.
|
|
10
13
|
const { data, isLoading, error } = useShape({
|
|
11
|
-
url: `${
|
|
14
|
+
url: `${proxyBaseUrl}/api/shapes/yjs-documents`,
|
|
12
15
|
params: {
|
|
13
|
-
|
|
14
|
-
where: isValidId ? `id = '${documentId}'` : `id = 'invalid'`,
|
|
16
|
+
document_id: isValidId ? documentId : '__invalid__',
|
|
15
17
|
},
|
|
18
|
+
fetchClient: fetchWithTimeout,
|
|
16
19
|
});
|
|
17
20
|
if (!isValidId) {
|
|
18
21
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-collaboration.d.ts","sourceRoot":"","sources":["../../src/collab/use-collaboration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"use-collaboration.d.ts","sourceRoot":"","sources":["../../src/collab/use-collaboration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;IAClB,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CAC3C;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,UAAU,EACV,SAAS,EACT,OAAc,EACd,YAAmB,EACnB,QAAQ,GACT,EAAE,uBAAuB,GAAG,sBAAsB,CAqElD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yjs-websocket-provider.d.ts","sourceRoot":"","sources":["../../src/collab/yjs-websocket-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"yjs-websocket-provider.d.ts","sourceRoot":"","sources":["../../src/collab/yjs-websocket-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAOzB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,qBAAa,cAAe,SAAQ,UAAU,CAAC,MAAM,CAAC;IACpD,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IACX,SAAS,EAAE,iBAAiB,CAAC,SAAS,CAAC;IACvC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,aAAa,CAAgE;IACrF,OAAO,CAAC,sBAAsB,CAGpB;gBAGR,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,UAAU,GAAG,IAAI,CAAA;KAAE;IA2BhD,gBAAgB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAI9C,iBAAiB,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC;IAU9C,OAAO,IAAI,IAAI;IAuFf,UAAU,IAAI,IAAI;IAmBlB,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,eAAe;IAQvB,OAAO,IAAI,IAAI;CAMhB"}
|
|
@@ -4,8 +4,7 @@ import { Observable } from 'lib0/observable';
|
|
|
4
4
|
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
5
5
|
import * as syncProtocol from 'y-protocols/sync';
|
|
6
6
|
import * as Y from 'yjs';
|
|
7
|
-
|
|
8
|
-
const MESSAGE_AWARENESS = 1;
|
|
7
|
+
import { MESSAGE_AWARENESS, MESSAGE_SYNC } from './protocol-constants.js';
|
|
9
8
|
const MAX_RECONNECT_ATTEMPTS = 10;
|
|
10
9
|
const BASE_RECONNECT_DELAY = 1000;
|
|
11
10
|
const RECONNECT_MULTIPLIER = 1.5;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fetch wrapper that aborts requests after {@link SHAPE_FETCH_TIMEOUT_MS} (10 s).
|
|
3
|
+
* Passed as `fetchClient` to ElectricSQL `useShape` so that shape subscription
|
|
4
|
+
* requests to the CMS proxy do not hang indefinitely.
|
|
5
|
+
*/
|
|
6
|
+
export declare function fetchWithTimeout(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
7
|
+
//# sourceMappingURL=fetch-with-timeout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-with-timeout.d.ts","sourceRoot":"","sources":["../src/fetch-with-timeout.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoBhG"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Default timeout for Electric shape proxy fetch requests (milliseconds). */
|
|
2
|
+
const SHAPE_FETCH_TIMEOUT_MS = 10_000;
|
|
3
|
+
/**
|
|
4
|
+
* A fetch wrapper that aborts requests after {@link SHAPE_FETCH_TIMEOUT_MS} (10 s).
|
|
5
|
+
* Passed as `fetchClient` to ElectricSQL `useShape` so that shape subscription
|
|
6
|
+
* requests to the CMS proxy do not hang indefinitely.
|
|
7
|
+
*/
|
|
8
|
+
export function fetchWithTimeout(input, init) {
|
|
9
|
+
// If the caller already provides a signal, respect it and compose with our timeout.
|
|
10
|
+
const externalSignal = init?.signal;
|
|
11
|
+
const controller = new AbortController();
|
|
12
|
+
const timeout = setTimeout(() => controller.abort(), SHAPE_FETCH_TIMEOUT_MS);
|
|
13
|
+
// If the external signal aborts, forward to our controller.
|
|
14
|
+
if (externalSignal) {
|
|
15
|
+
if (externalSignal.aborted) {
|
|
16
|
+
controller.abort(externalSignal.reason);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
externalSignal.addEventListener('abort', () => controller.abort(externalSignal.reason), {
|
|
20
|
+
once: true,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return fetch(input, { ...init, signal: controller.signal }).finally(() => {
|
|
25
|
+
clearTimeout(timeout);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { MutationResult } from '../mutations.js';
|
|
2
|
+
export interface AgentContextRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
session_id: string;
|
|
5
|
+
agent_id: string;
|
|
6
|
+
context: Record<string, unknown>;
|
|
7
|
+
priority: number;
|
|
8
|
+
created_at: string;
|
|
9
|
+
updated_at: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CreateAgentContextInput {
|
|
12
|
+
agent_id: string;
|
|
13
|
+
context?: Record<string, unknown>;
|
|
14
|
+
priority?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface UpdateAgentContextInput {
|
|
17
|
+
context?: Record<string, unknown>;
|
|
18
|
+
priority?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface UseAgentContextsResult {
|
|
21
|
+
contexts: AgentContextRecord[];
|
|
22
|
+
isLoading: boolean;
|
|
23
|
+
error: Error | null;
|
|
24
|
+
create: (data: CreateAgentContextInput) => Promise<MutationResult<AgentContextRecord>>;
|
|
25
|
+
update: (id: string, data: UpdateAgentContextInput) => Promise<MutationResult<AgentContextRecord>>;
|
|
26
|
+
remove: (id: string) => Promise<MutationResult<void>>;
|
|
27
|
+
}
|
|
28
|
+
export declare function useAgentContexts(): UseAgentContextsResult;
|
|
29
|
+
//# sourceMappingURL=useAgentContexts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAgentContexts.d.ts","sourceRoot":"","sources":["../../src/hooks/useAgentContexts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,uBAAuB,KAAK,OAAO,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACvF,MAAM,EAAE,CACN,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,uBAAuB,KAC1B,OAAO,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACjD,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;CACvD;AAED,wBAAgB,gBAAgB,IAAI,sBAAsB,CAqBzD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useShape } from '@electric-sql/react';
|
|
3
|
+
import { fetchWithTimeout } from '../fetch-with-timeout.js';
|
|
4
|
+
import { useSyncMutations } from '../mutations.js';
|
|
5
|
+
import { useElectricConfig } from '../provider/index.js';
|
|
6
|
+
import { toRecords } from '../shape-utils.js';
|
|
7
|
+
export function useAgentContexts() {
|
|
8
|
+
const { proxyBaseUrl } = useElectricConfig();
|
|
9
|
+
const { data, isLoading, error } = useShape({
|
|
10
|
+
url: `${proxyBaseUrl}/api/shapes/agent-contexts`,
|
|
11
|
+
fetchClient: fetchWithTimeout,
|
|
12
|
+
});
|
|
13
|
+
const { create, update, remove } = useSyncMutations('agent-contexts');
|
|
14
|
+
return {
|
|
15
|
+
contexts: toRecords(data),
|
|
16
|
+
isLoading,
|
|
17
|
+
error: error || null,
|
|
18
|
+
create,
|
|
19
|
+
update,
|
|
20
|
+
remove,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { MutationResult } from '../mutations.js';
|
|
2
|
+
export interface AgentMemoryRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
agent_id: string;
|
|
5
|
+
content: string;
|
|
6
|
+
type: string;
|
|
7
|
+
metadata: Record<string, unknown>;
|
|
8
|
+
created_at: string;
|
|
9
|
+
expires_at: string | null;
|
|
10
|
+
}
|
|
11
|
+
export interface CreateAgentMemoryInput {
|
|
12
|
+
agent_id: string;
|
|
13
|
+
content: string;
|
|
14
|
+
type: string;
|
|
15
|
+
source: Record<string, unknown>;
|
|
16
|
+
metadata?: Record<string, unknown>;
|
|
17
|
+
expires_at?: string | null;
|
|
18
|
+
}
|
|
19
|
+
export interface UpdateAgentMemoryInput {
|
|
20
|
+
content?: string;
|
|
21
|
+
type?: string;
|
|
22
|
+
metadata?: Record<string, unknown>;
|
|
23
|
+
expires_at?: string | null;
|
|
24
|
+
}
|
|
25
|
+
export interface UseAgentMemoryResult {
|
|
26
|
+
memories: AgentMemoryRecord[];
|
|
27
|
+
isLoading: boolean;
|
|
28
|
+
error: Error | null;
|
|
29
|
+
create: (data: CreateAgentMemoryInput) => Promise<MutationResult<AgentMemoryRecord>>;
|
|
30
|
+
update: (id: string, data: UpdateAgentMemoryInput) => Promise<MutationResult<AgentMemoryRecord>>;
|
|
31
|
+
remove: (id: string) => Promise<MutationResult<void>>;
|
|
32
|
+
}
|
|
33
|
+
export declare function useAgentMemory(agentId: string): UseAgentMemoryResult;
|
|
34
|
+
//# sourceMappingURL=useAgentMemory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAgentMemory.d.ts","sourceRoot":"","sources":["../../src/hooks/useAgentMemory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAOtD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACrF,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,KAAK,OAAO,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACjG,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;CACvD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,CAuCpE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useShape } from '@electric-sql/react';
|
|
3
|
+
import { fetchWithTimeout } from '../fetch-with-timeout.js';
|
|
4
|
+
import { useSyncMutations } from '../mutations.js';
|
|
5
|
+
import { useElectricConfig } from '../provider/index.js';
|
|
6
|
+
import { toRecords } from '../shape-utils.js';
|
|
7
|
+
const AGENT_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
|
8
|
+
export function useAgentMemory(agentId) {
|
|
9
|
+
const { proxyBaseUrl } = useElectricConfig();
|
|
10
|
+
const isValid = agentId.length > 0 && AGENT_ID_RE.test(agentId);
|
|
11
|
+
// Hook must always be called (Rules of Hooks). Pass an impossible WHERE when
|
|
12
|
+
// the ID is invalid so the shape returns no rows but the hook still runs.
|
|
13
|
+
const { data, isLoading, error } = useShape({
|
|
14
|
+
url: `${proxyBaseUrl}/api/shapes/agent-memories`,
|
|
15
|
+
params: { agent_id: isValid ? agentId : '00000000-0000-0000-0000-000000000000' },
|
|
16
|
+
fetchClient: fetchWithTimeout,
|
|
17
|
+
});
|
|
18
|
+
const { create, update, remove } = useSyncMutations('agent-memories');
|
|
19
|
+
if (!isValid) {
|
|
20
|
+
return {
|
|
21
|
+
memories: [],
|
|
22
|
+
isLoading: false,
|
|
23
|
+
error: new Error('Invalid agentId: must be non-empty alphanumeric, hyphens, underscores only'),
|
|
24
|
+
create,
|
|
25
|
+
update,
|
|
26
|
+
remove,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
memories: toRecords(data),
|
|
31
|
+
isLoading,
|
|
32
|
+
error: error || null,
|
|
33
|
+
create,
|
|
34
|
+
update,
|
|
35
|
+
remove,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -1,11 +1,31 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
1
|
+
import type { MutationResult } from '../mutations.js';
|
|
2
|
+
export interface ConversationRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
user_id: string;
|
|
5
|
+
agent_id: string;
|
|
3
6
|
title?: string | null;
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
status: string;
|
|
8
|
+
device_id?: string | null;
|
|
9
|
+
version: number;
|
|
10
|
+
created_at: string;
|
|
11
|
+
updated_at: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CreateConversationInput {
|
|
14
|
+
agent_id: string;
|
|
15
|
+
title?: string;
|
|
16
|
+
device_id?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface UpdateConversationInput {
|
|
19
|
+
title?: string;
|
|
20
|
+
status?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface UseConversationsResult {
|
|
6
23
|
conversations: ConversationRecord[];
|
|
7
24
|
isLoading: boolean;
|
|
8
25
|
error: Error | null;
|
|
9
|
-
|
|
10
|
-
|
|
26
|
+
create: (data: CreateConversationInput) => Promise<MutationResult<ConversationRecord>>;
|
|
27
|
+
update: (id: string, data: UpdateConversationInput) => Promise<MutationResult<ConversationRecord>>;
|
|
28
|
+
remove: (id: string) => Promise<MutationResult<void>>;
|
|
29
|
+
}
|
|
30
|
+
export declare function useConversations(_userId: string): UseConversationsResult;
|
|
11
31
|
//# sourceMappingURL=useConversations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConversations.d.ts","sourceRoot":"","sources":["../../src/hooks/useConversations.ts"],"names":[],"mappings":"AAIA,KAAK,kBAAkB,GAAG;
|
|
1
|
+
{"version":3,"file":"useConversations.d.ts","sourceRoot":"","sources":["../../src/hooks/useConversations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,kBAAkB,EAAE,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,uBAAuB,KAAK,OAAO,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACvF,MAAM,EAAE,CACN,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,uBAAuB,KAC1B,OAAO,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAC;IACjD,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;CACvD;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB,CAuBxE"}
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useShape } from '@electric-sql/react';
|
|
3
|
+
import { fetchWithTimeout } from '../fetch-with-timeout.js';
|
|
4
|
+
import { useSyncMutations } from '../mutations.js';
|
|
5
|
+
import { useElectricConfig } from '../provider/index.js';
|
|
6
|
+
import { toRecords } from '../shape-utils.js';
|
|
3
7
|
// _userId kept for API compatibility — filtering is enforced by the server-side
|
|
4
8
|
// proxy at /api/shapes/conversations, which reads the session cookie directly.
|
|
5
9
|
export function useConversations(_userId) {
|
|
10
|
+
const { proxyBaseUrl } = useElectricConfig();
|
|
6
11
|
// The proxy validates the session and enforces row-level filtering server-side.
|
|
7
12
|
// Client-provided params are not forwarded — the proxy overrides them.
|
|
8
13
|
const { data, isLoading, error } = useShape({
|
|
9
|
-
url:
|
|
14
|
+
url: `${proxyBaseUrl}/api/shapes/conversations`,
|
|
15
|
+
fetchClient: fetchWithTimeout,
|
|
10
16
|
});
|
|
17
|
+
const { create, update, remove } = useSyncMutations('conversations');
|
|
11
18
|
return {
|
|
12
|
-
conversations:
|
|
19
|
+
conversations: toRecords(data),
|
|
13
20
|
isLoading,
|
|
14
|
-
error: error,
|
|
21
|
+
error: error || null,
|
|
22
|
+
create,
|
|
23
|
+
update,
|
|
24
|
+
remove,
|
|
15
25
|
};
|
|
16
26
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { MutationResult } from '../mutations.js';
|
|
2
|
+
export interface CoordinationSessionRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
agent_id: string;
|
|
5
|
+
started_at: string;
|
|
6
|
+
ended_at: string | null;
|
|
7
|
+
task: string;
|
|
8
|
+
status: string;
|
|
9
|
+
pid: number | null;
|
|
10
|
+
tools: Record<string, number> | null;
|
|
11
|
+
metadata: Record<string, unknown> | null;
|
|
12
|
+
}
|
|
13
|
+
export interface CreateCoordinationSessionInput {
|
|
14
|
+
agent_id: string;
|
|
15
|
+
task?: string;
|
|
16
|
+
pid?: number;
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface UpdateCoordinationSessionInput {
|
|
20
|
+
task?: string;
|
|
21
|
+
status?: string;
|
|
22
|
+
ended_at?: string;
|
|
23
|
+
tools?: Record<string, number>;
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export interface UseCoordinationSessionsResult {
|
|
27
|
+
sessions: CoordinationSessionRecord[];
|
|
28
|
+
isLoading: boolean;
|
|
29
|
+
error: Error | null;
|
|
30
|
+
create: (data: CreateCoordinationSessionInput) => Promise<MutationResult<CoordinationSessionRecord>>;
|
|
31
|
+
update: (id: string, data: UpdateCoordinationSessionInput) => Promise<MutationResult<CoordinationSessionRecord>>;
|
|
32
|
+
remove: (id: string) => Promise<MutationResult<void>>;
|
|
33
|
+
}
|
|
34
|
+
export declare function useCoordinationSessions(): UseCoordinationSessionsResult;
|
|
35
|
+
//# sourceMappingURL=useCoordinationSessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCoordinationSessions.d.ts","sourceRoot":"","sources":["../../src/hooks/useCoordinationSessions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,yBAAyB,EAAE,CAAC;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,CACN,IAAI,EAAE,8BAA8B,KACjC,OAAO,CAAC,cAAc,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,CACN,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,8BAA8B,KACjC,OAAO,CAAC,cAAc,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACxD,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;CACvD;AAED,wBAAgB,uBAAuB,IAAI,6BAA6B,CAqBvE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useShape } from '@electric-sql/react';
|
|
3
|
+
import { fetchWithTimeout } from '../fetch-with-timeout.js';
|
|
4
|
+
import { useSyncMutations } from '../mutations.js';
|
|
5
|
+
import { useElectricConfig } from '../provider/index.js';
|
|
6
|
+
import { toRecords } from '../shape-utils.js';
|
|
7
|
+
export function useCoordinationSessions() {
|
|
8
|
+
const { proxyBaseUrl } = useElectricConfig();
|
|
9
|
+
const { data, isLoading, error } = useShape({
|
|
10
|
+
url: `${proxyBaseUrl}/api/shapes/coordination-sessions`,
|
|
11
|
+
fetchClient: fetchWithTimeout,
|
|
12
|
+
});
|
|
13
|
+
const { create, update, remove } = useSyncMutations('coordination-sessions');
|
|
14
|
+
return {
|
|
15
|
+
sessions: toRecords(data),
|
|
16
|
+
isLoading,
|
|
17
|
+
error: error || null,
|
|
18
|
+
create,
|
|
19
|
+
update,
|
|
20
|
+
remove,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { MutationResult } from '../mutations.js';
|
|
2
|
+
export interface CoordinationWorkItemRecord {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string | null;
|
|
6
|
+
status: string;
|
|
7
|
+
priority: number;
|
|
8
|
+
owner_agent: string | null;
|
|
9
|
+
owner_session: string | null;
|
|
10
|
+
parent_id: string | null;
|
|
11
|
+
metadata: Record<string, unknown> | null;
|
|
12
|
+
created_at: string;
|
|
13
|
+
updated_at: string;
|
|
14
|
+
completed_at: string | null;
|
|
15
|
+
}
|
|
16
|
+
export interface CreateCoordinationWorkItemInput {
|
|
17
|
+
title: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
priority?: number;
|
|
20
|
+
owner_agent?: string;
|
|
21
|
+
parent_id?: string;
|
|
22
|
+
metadata?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
export interface UpdateCoordinationWorkItemInput {
|
|
25
|
+
title?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
status?: string;
|
|
28
|
+
priority?: number;
|
|
29
|
+
owner_agent?: string;
|
|
30
|
+
metadata?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
export interface UseCoordinationWorkItemsResult {
|
|
33
|
+
workItems: CoordinationWorkItemRecord[];
|
|
34
|
+
isLoading: boolean;
|
|
35
|
+
error: Error | null;
|
|
36
|
+
create: (data: CreateCoordinationWorkItemInput) => Promise<MutationResult<CoordinationWorkItemRecord>>;
|
|
37
|
+
update: (id: string, data: UpdateCoordinationWorkItemInput) => Promise<MutationResult<CoordinationWorkItemRecord>>;
|
|
38
|
+
remove: (id: string) => Promise<MutationResult<void>>;
|
|
39
|
+
}
|
|
40
|
+
export declare function useCoordinationWorkItems(): UseCoordinationWorkItemsResult;
|
|
41
|
+
//# sourceMappingURL=useCoordinationWorkItems.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCoordinationWorkItems.d.ts","sourceRoot":"","sources":["../../src/hooks/useCoordinationWorkItems.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,+BAA+B;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,+BAA+B;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,0BAA0B,EAAE,CAAC;IACxC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,CACN,IAAI,EAAE,+BAA+B,KAClC,OAAO,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACzD,MAAM,EAAE,CACN,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,+BAA+B,KAClC,OAAO,CAAC,cAAc,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACzD,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;CACvD;AAED,wBAAgB,wBAAwB,IAAI,8BAA8B,CAqBzE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useShape } from '@electric-sql/react';
|
|
3
|
+
import { fetchWithTimeout } from '../fetch-with-timeout.js';
|
|
4
|
+
import { useSyncMutations } from '../mutations.js';
|
|
5
|
+
import { useElectricConfig } from '../provider/index.js';
|
|
6
|
+
import { toRecords } from '../shape-utils.js';
|
|
7
|
+
export function useCoordinationWorkItems() {
|
|
8
|
+
const { proxyBaseUrl } = useElectricConfig();
|
|
9
|
+
const { data, isLoading, error } = useShape({
|
|
10
|
+
url: `${proxyBaseUrl}/api/shapes/coordination-work-items`,
|
|
11
|
+
fetchClient: fetchWithTimeout,
|
|
12
|
+
});
|
|
13
|
+
const { create, update, remove } = useSyncMutations('coordination-work-items');
|
|
14
|
+
return {
|
|
15
|
+
workItems: toRecords(data),
|
|
16
|
+
isLoading,
|
|
17
|
+
error: error || null,
|
|
18
|
+
create,
|
|
19
|
+
update,
|
|
20
|
+
remove,
|
|
21
|
+
};
|
|
22
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @revealui/sync — Real-time collaboration and sync primitives.
|
|
3
|
+
*
|
|
4
|
+
* The collab layer (Yjs-based) is fully functional.
|
|
5
|
+
* ElectricProvider provides proxyBaseUrl config to child hooks. All hooks route
|
|
6
|
+
* through the authenticated CMS proxy at /api/shapes/* — no direct Electric client.
|
|
7
|
+
*
|
|
8
|
+
* Reads use ElectricSQL shape subscriptions for real-time updates.
|
|
9
|
+
* Writes use REST mutations via /api/sync/* — changes propagate to all
|
|
10
|
+
* subscribers automatically through ElectricSQL replication.
|
|
11
|
+
*/
|
|
1
12
|
export type { CollabDocumentState, UseCollaborationOptions, UseCollaborationResult, } from './collab/index.js';
|
|
2
13
|
export { CollabProvider, useCollabDocument, useCollaboration, } from './collab/index.js';
|
|
14
|
+
export type { AgentContextRecord, CreateAgentContextInput, UpdateAgentContextInput, UseAgentContextsResult, } from './hooks/useAgentContexts.js';
|
|
15
|
+
export { useAgentContexts } from './hooks/useAgentContexts.js';
|
|
16
|
+
export type { AgentMemoryRecord, CreateAgentMemoryInput, UpdateAgentMemoryInput, UseAgentMemoryResult, } from './hooks/useAgentMemory.js';
|
|
17
|
+
export { useAgentMemory } from './hooks/useAgentMemory.js';
|
|
18
|
+
export type { ConversationRecord, CreateConversationInput, UpdateConversationInput, UseConversationsResult, } from './hooks/useConversations.js';
|
|
3
19
|
export { useConversations } from './hooks/useConversations.js';
|
|
4
|
-
export {
|
|
20
|
+
export type { CoordinationSessionRecord, CreateCoordinationSessionInput, UpdateCoordinationSessionInput, UseCoordinationSessionsResult, } from './hooks/useCoordinationSessions.js';
|
|
21
|
+
export { useCoordinationSessions } from './hooks/useCoordinationSessions.js';
|
|
22
|
+
export type { CoordinationWorkItemRecord, CreateCoordinationWorkItemInput, UpdateCoordinationWorkItemInput, UseCoordinationWorkItemsResult, } from './hooks/useCoordinationWorkItems.js';
|
|
23
|
+
export { useCoordinationWorkItems } from './hooks/useCoordinationWorkItems.js';
|
|
24
|
+
export type { MutationResult } from './mutations.js';
|
|
25
|
+
export { ElectricProvider, useElectricConfig } from './provider/index.js';
|
|
5
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,YAAY,EACV,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EACV,kBAAkB,EAClB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,YAAY,EACV,yBAAyB,EACzB,8BAA8B,EAC9B,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,YAAY,EACV,0BAA0B,EAC1B,+BAA+B,EAC/B,+BAA+B,EAC/B,8BAA8B,GAC/B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAC/E,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @revealui/sync — Real-time collaboration and sync primitives.
|
|
3
|
+
*
|
|
4
|
+
* The collab layer (Yjs-based) is fully functional.
|
|
5
|
+
* ElectricProvider provides proxyBaseUrl config to child hooks. All hooks route
|
|
6
|
+
* through the authenticated CMS proxy at /api/shapes/* — no direct Electric client.
|
|
7
|
+
*
|
|
8
|
+
* Reads use ElectricSQL shape subscriptions for real-time updates.
|
|
9
|
+
* Writes use REST mutations via /api/sync/* — changes propagate to all
|
|
10
|
+
* subscribers automatically through ElectricSQL replication.
|
|
11
|
+
*/
|
|
1
12
|
export { CollabProvider, useCollabDocument, useCollaboration, } from './collab/index.js';
|
|
13
|
+
export { useAgentContexts } from './hooks/useAgentContexts.js';
|
|
14
|
+
export { useAgentMemory } from './hooks/useAgentMemory.js';
|
|
2
15
|
export { useConversations } from './hooks/useConversations.js';
|
|
3
|
-
export {
|
|
16
|
+
export { useCoordinationSessions } from './hooks/useCoordinationSessions.js';
|
|
17
|
+
export { useCoordinationWorkItems } from './hooks/useCoordinationWorkItems.js';
|
|
18
|
+
export { ElectricProvider, useElectricConfig } from './provider/index.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface MutationResult<T = unknown> {
|
|
2
|
+
success: boolean;
|
|
3
|
+
data?: T;
|
|
4
|
+
error?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Hook that returns mutation functions for a given sync API endpoint.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useSyncMutations<TCreate, TUpdate, TRecord>(endpoint: string): {
|
|
10
|
+
create: (data: TCreate) => Promise<MutationResult<TRecord>>;
|
|
11
|
+
update: (id: string, data: TUpdate) => Promise<MutationResult<TRecord>>;
|
|
12
|
+
remove: (id: string) => Promise<MutationResult<void>>;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=mutations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../src/mutations.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0CD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM;mBAK3D,OAAO,KAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;iBAO5C,MAAM,QAAQ,OAAO,KAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;iBAOxD,MAAM,KAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;EAOpD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { useElectricConfig } from './provider/index.js';
|
|
4
|
+
/** Default timeout for mutation fetch requests (milliseconds). */
|
|
5
|
+
const MUTATION_FETCH_TIMEOUT_MS = 10_000;
|
|
6
|
+
/**
|
|
7
|
+
* Make an authenticated mutation request to the CMS API.
|
|
8
|
+
* Credentials are included so the session cookie is sent cross-origin.
|
|
9
|
+
* Requests are aborted after {@link MUTATION_FETCH_TIMEOUT_MS} (10 s).
|
|
10
|
+
*/
|
|
11
|
+
async function mutationFetch(url, method, body) {
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const timeout = setTimeout(() => controller.abort(), MUTATION_FETCH_TIMEOUT_MS);
|
|
14
|
+
let response;
|
|
15
|
+
try {
|
|
16
|
+
response = await fetch(url, {
|
|
17
|
+
method,
|
|
18
|
+
credentials: 'include',
|
|
19
|
+
signal: controller.signal,
|
|
20
|
+
headers: body !== undefined ? { 'Content-Type': 'application/json' } : undefined,
|
|
21
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
clearTimeout(timeout);
|
|
26
|
+
}
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const errorData = (await response.json().catch(() => null));
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: errorData?.error ?? `Request failed with status ${response.status}`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const data = (await response.json());
|
|
35
|
+
return { success: true, data };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Hook that returns mutation functions for a given sync API endpoint.
|
|
39
|
+
*/
|
|
40
|
+
export function useSyncMutations(endpoint) {
|
|
41
|
+
const { proxyBaseUrl } = useElectricConfig();
|
|
42
|
+
const baseUrl = `${proxyBaseUrl}/api/sync/${endpoint}`;
|
|
43
|
+
const create = useCallback(async (data) => {
|
|
44
|
+
return mutationFetch(baseUrl, 'POST', data);
|
|
45
|
+
}, [baseUrl]);
|
|
46
|
+
const update = useCallback(async (id, data) => {
|
|
47
|
+
return mutationFetch(`${baseUrl}/${encodeURIComponent(id)}`, 'PATCH', data);
|
|
48
|
+
}, [baseUrl]);
|
|
49
|
+
const remove = useCallback(async (id) => {
|
|
50
|
+
return mutationFetch(`${baseUrl}/${encodeURIComponent(id)}`, 'DELETE');
|
|
51
|
+
}, [baseUrl]);
|
|
52
|
+
return { create, update, remove };
|
|
53
|
+
}
|
package/dist/provider/index.d.ts
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
interface ElectricContextValue {
|
|
3
|
+
/**
|
|
4
|
+
* Direct Electric service URL (e.g. the Railway instance).
|
|
5
|
+
* Stored in context for future use — not consumed by the current proxy-based hooks.
|
|
6
|
+
* All hooks use proxyBaseUrl + /api/shapes/* instead.
|
|
7
|
+
*/
|
|
8
|
+
serviceUrl: string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Base URL prefix for authenticated CMS shape proxy routes.
|
|
11
|
+
* Default '' keeps all hook URLs relative (works for same-origin apps).
|
|
12
|
+
* Set to 'https://cms.revealui.com' when consuming from a different origin.
|
|
13
|
+
*/
|
|
14
|
+
proxyBaseUrl: string;
|
|
15
|
+
debug: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Provides ElectricSQL configuration to child hooks (`useConversations`, `useCollabDocument`).
|
|
19
|
+
*
|
|
20
|
+
* Provides proxyBaseUrl (and optional serviceUrl/debug) to child hooks via context.
|
|
21
|
+
* All hooks use the CMS proxy pattern — no direct Electric connection is established here.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ElectricProvider(props: {
|
|
3
24
|
children: ReactNode;
|
|
4
25
|
serviceUrl?: string;
|
|
26
|
+
proxyBaseUrl?: string;
|
|
5
27
|
debug?: boolean;
|
|
6
|
-
}):
|
|
28
|
+
}): ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* Access the ElectricSQL configuration provided by `ElectricProvider`.
|
|
31
|
+
* Returns `{ serviceUrl: null, debug: false }` if no provider is present.
|
|
32
|
+
*/
|
|
33
|
+
export declare function useElectricConfig(): ElectricContextValue;
|
|
34
|
+
export {};
|
|
7
35
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,SAAS,EAAgB,MAAM,OAAO,CAAC;AAEpE,UAAU,oBAAoB;IAC5B;;;;OAIG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;CAChB;AAQD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,SAAS,CAWZ;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,oBAAoB,CAExD"}
|
package/dist/provider/index.js
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, use, useMemo } from 'react';
|
|
4
|
+
const ElectricContext = createContext({
|
|
5
|
+
serviceUrl: null,
|
|
6
|
+
proxyBaseUrl: '',
|
|
7
|
+
debug: false,
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Provides ElectricSQL configuration to child hooks (`useConversations`, `useCollabDocument`).
|
|
11
|
+
*
|
|
12
|
+
* Provides proxyBaseUrl (and optional serviceUrl/debug) to child hooks via context.
|
|
13
|
+
* All hooks use the CMS proxy pattern — no direct Electric connection is established here.
|
|
14
|
+
*/
|
|
15
|
+
export function ElectricProvider(props) {
|
|
16
|
+
const value = useMemo(() => ({
|
|
17
|
+
serviceUrl: props.serviceUrl ?? null,
|
|
18
|
+
proxyBaseUrl: props.proxyBaseUrl ?? '',
|
|
19
|
+
debug: props.debug ?? false,
|
|
20
|
+
}), [props.serviceUrl, props.proxyBaseUrl, props.debug]);
|
|
21
|
+
return _jsx(ElectricContext, { value: value, children: props.children });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Access the ElectricSQL configuration provided by `ElectricProvider`.
|
|
25
|
+
* Returns `{ serviceUrl: null, debug: false }` if no provider is present.
|
|
26
|
+
*/
|
|
27
|
+
export function useElectricConfig() {
|
|
28
|
+
return use(ElectricContext);
|
|
8
29
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cast ElectricSQL shape data to a typed record array.
|
|
3
|
+
*
|
|
4
|
+
* ElectricSQL's `useShape` returns `Row[]` (i.e. `Record<string, Value>[]`).
|
|
5
|
+
* Our record interfaces describe the exact same shape but lack the index
|
|
6
|
+
* signature that `Row` carries, so TypeScript rejects a direct assignment.
|
|
7
|
+
* This helper encapsulates the boundary cast in one place and returns an
|
|
8
|
+
* empty array when data is falsy.
|
|
9
|
+
*/
|
|
10
|
+
export declare function toRecords<T>(data: unknown[] | undefined): T[];
|
|
11
|
+
//# sourceMappingURL=shape-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape-utils.d.ts","sourceRoot":"","sources":["../src/shape-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,SAAS,GAAG,CAAC,EAAE,CAG7D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cast ElectricSQL shape data to a typed record array.
|
|
3
|
+
*
|
|
4
|
+
* ElectricSQL's `useShape` returns `Row[]` (i.e. `Record<string, Value>[]`).
|
|
5
|
+
* Our record interfaces describe the exact same shape but lack the index
|
|
6
|
+
* signature that `Row` carries, so TypeScript rejects a direct assignment.
|
|
7
|
+
* This helper encapsulates the boundary cast in one place and returns an
|
|
8
|
+
* empty array when data is falsy.
|
|
9
|
+
*/
|
|
10
|
+
export function toRecords(data) {
|
|
11
|
+
if (!Array.isArray(data))
|
|
12
|
+
return [];
|
|
13
|
+
return data;
|
|
14
|
+
}
|
package/dist/test-setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,
|
|
1
|
+
{"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revealui/sync",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"experimental": true,
|
|
4
5
|
"license": "MIT",
|
|
5
6
|
"files": [
|
|
6
7
|
"dist"
|
|
@@ -12,8 +13,8 @@
|
|
|
12
13
|
"ws": "^8.18.0",
|
|
13
14
|
"y-protocols": "^1.0.7",
|
|
14
15
|
"yjs": "^13.6.29",
|
|
15
|
-
"@revealui/
|
|
16
|
-
"@revealui/
|
|
16
|
+
"@revealui/db": "0.3.0",
|
|
17
|
+
"@revealui/contracts": "1.2.0"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
20
|
"@testing-library/jest-dom": "^6.6.4",
|
|
@@ -28,6 +29,9 @@
|
|
|
28
29
|
"vitest": "^4.0.18",
|
|
29
30
|
"dev": "0.0.1"
|
|
30
31
|
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=24.13.0"
|
|
34
|
+
},
|
|
31
35
|
"exports": {
|
|
32
36
|
".": {
|
|
33
37
|
"types": "./dist/index.d.ts",
|
|
@@ -58,9 +62,8 @@
|
|
|
58
62
|
"clean": "rm -rf dist",
|
|
59
63
|
"dev": "tsc --watch",
|
|
60
64
|
"lint": "biome check .",
|
|
61
|
-
"lint:eslint": "eslint .",
|
|
62
65
|
"test": "vitest run",
|
|
63
|
-
"test:coverage": "vitest run --coverage",
|
|
66
|
+
"test:coverage": "vitest run --coverage --coverage.reporter=json-summary --coverage.reporter=html --coverage.reporter=text",
|
|
64
67
|
"test:watch": "vitest",
|
|
65
68
|
"typecheck": "tsc --noEmit"
|
|
66
69
|
}
|