@fluxra-ai/fluxra-cli 0.1.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/LICENSE +201 -0
- package/README.md +274 -0
- package/bin/fluxra +6 -0
- package/dist/cli/command-context.d.ts +17 -0
- package/dist/cli/command-context.d.ts.map +1 -0
- package/dist/cli/command-context.js +26 -0
- package/dist/cli/command-context.js.map +1 -0
- package/dist/cli/commands/auth/index.d.ts +3 -0
- package/dist/cli/commands/auth/index.d.ts.map +1 -0
- package/dist/cli/commands/auth/index.js +165 -0
- package/dist/cli/commands/auth/index.js.map +1 -0
- package/dist/cli/commands/chat/index.d.ts +3 -0
- package/dist/cli/commands/chat/index.d.ts.map +1 -0
- package/dist/cli/commands/chat/index.js +1201 -0
- package/dist/cli/commands/chat/index.js.map +1 -0
- package/dist/cli/commands/config/index.d.ts +3 -0
- package/dist/cli/commands/config/index.d.ts.map +1 -0
- package/dist/cli/commands/config/index.js +66 -0
- package/dist/cli/commands/config/index.js.map +1 -0
- package/dist/cli/commands/help.d.ts +7 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +106 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/local/doctor.d.ts +26 -0
- package/dist/cli/commands/local/doctor.d.ts.map +1 -0
- package/dist/cli/commands/local/doctor.js +265 -0
- package/dist/cli/commands/local/doctor.js.map +1 -0
- package/dist/cli/commands/local/export.d.ts +41 -0
- package/dist/cli/commands/local/export.d.ts.map +1 -0
- package/dist/cli/commands/local/export.js +83 -0
- package/dist/cli/commands/local/export.js.map +1 -0
- package/dist/cli/commands/local/index.d.ts +6 -0
- package/dist/cli/commands/local/index.d.ts.map +1 -0
- package/dist/cli/commands/local/index.js +116 -0
- package/dist/cli/commands/local/index.js.map +1 -0
- package/dist/cli/commands/local/inspect.d.ts +42 -0
- package/dist/cli/commands/local/inspect.d.ts.map +1 -0
- package/dist/cli/commands/local/inspect.js +125 -0
- package/dist/cli/commands/local/inspect.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +8 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +253 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/profile/index.d.ts +3 -0
- package/dist/cli/commands/profile/index.d.ts.map +1 -0
- package/dist/cli/commands/profile/index.js +114 -0
- package/dist/cli/commands/profile/index.js.map +1 -0
- package/dist/cli/commands/schema.d.ts +7 -0
- package/dist/cli/commands/schema.d.ts.map +1 -0
- package/dist/cli/commands/schema.js +33 -0
- package/dist/cli/commands/schema.js.map +1 -0
- package/dist/cli/errors.d.ts +16 -0
- package/dist/cli/errors.d.ts.map +1 -0
- package/dist/cli/errors.js +15 -0
- package/dist/cli/errors.js.map +1 -0
- package/dist/cli/fluxra.d.ts +9 -0
- package/dist/cli/fluxra.d.ts.map +1 -0
- package/dist/cli/fluxra.js +55 -0
- package/dist/cli/fluxra.js.map +1 -0
- package/dist/cli/helpers.d.ts +13 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +32 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/output.d.ts +14 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +55 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/version.d.ts +6 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +8 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/core/auth/auth-service.d.ts +35 -0
- package/dist/core/auth/auth-service.d.ts.map +1 -0
- package/dist/core/auth/auth-service.js +116 -0
- package/dist/core/auth/auth-service.js.map +1 -0
- package/dist/core/config/global-config.d.ts +38 -0
- package/dist/core/config/global-config.d.ts.map +1 -0
- package/dist/core/config/global-config.js +75 -0
- package/dist/core/config/global-config.js.map +1 -0
- package/dist/core/errors/error-model.d.ts +48 -0
- package/dist/core/errors/error-model.d.ts.map +1 -0
- package/dist/core/errors/error-model.js +152 -0
- package/dist/core/errors/error-model.js.map +1 -0
- package/dist/core/filesystem/paths.d.ts +45 -0
- package/dist/core/filesystem/paths.d.ts.map +1 -0
- package/dist/core/filesystem/paths.js +77 -0
- package/dist/core/filesystem/paths.js.map +1 -0
- package/dist/core/http/auth-api.d.ts +71 -0
- package/dist/core/http/auth-api.d.ts.map +1 -0
- package/dist/core/http/auth-api.js +91 -0
- package/dist/core/http/auth-api.js.map +1 -0
- package/dist/core/http/block-api.d.ts +37 -0
- package/dist/core/http/block-api.d.ts.map +1 -0
- package/dist/core/http/block-api.js +36 -0
- package/dist/core/http/block-api.js.map +1 -0
- package/dist/core/http/chat-api.d.ts +41 -0
- package/dist/core/http/chat-api.d.ts.map +1 -0
- package/dist/core/http/chat-api.js +88 -0
- package/dist/core/http/chat-api.js.map +1 -0
- package/dist/core/http/conversation-management-api.d.ts +65 -0
- package/dist/core/http/conversation-management-api.d.ts.map +1 -0
- package/dist/core/http/conversation-management-api.js +59 -0
- package/dist/core/http/conversation-management-api.js.map +1 -0
- package/dist/core/http/directory-api.d.ts +32 -0
- package/dist/core/http/directory-api.d.ts.map +1 -0
- package/dist/core/http/directory-api.js +36 -0
- package/dist/core/http/directory-api.js.map +1 -0
- package/dist/core/http/directory-profile-api.d.ts +32 -0
- package/dist/core/http/directory-profile-api.d.ts.map +1 -0
- package/dist/core/http/directory-profile-api.js +39 -0
- package/dist/core/http/directory-profile-api.js.map +1 -0
- package/dist/core/http/http-client.d.ts +41 -0
- package/dist/core/http/http-client.d.ts.map +1 -0
- package/dist/core/http/http-client.js +127 -0
- package/dist/core/http/http-client.js.map +1 -0
- package/dist/core/http/message-api.d.ts +55 -0
- package/dist/core/http/message-api.d.ts.map +1 -0
- package/dist/core/http/message-api.js +64 -0
- package/dist/core/http/message-api.js.map +1 -0
- package/dist/core/http/rate-limit.d.ts +22 -0
- package/dist/core/http/rate-limit.d.ts.map +1 -0
- package/dist/core/http/rate-limit.js +66 -0
- package/dist/core/http/rate-limit.js.map +1 -0
- package/dist/core/http/token-lifecycle.d.ts +18 -0
- package/dist/core/http/token-lifecycle.d.ts.map +1 -0
- package/dist/core/http/token-lifecycle.js +73 -0
- package/dist/core/http/token-lifecycle.js.map +1 -0
- package/dist/core/locking/profile-lock.d.ts +32 -0
- package/dist/core/locking/profile-lock.d.ts.map +1 -0
- package/dist/core/locking/profile-lock.js +104 -0
- package/dist/core/locking/profile-lock.js.map +1 -0
- package/dist/core/profiles/profile-service.d.ts +35 -0
- package/dist/core/profiles/profile-service.d.ts.map +1 -0
- package/dist/core/profiles/profile-service.js +119 -0
- package/dist/core/profiles/profile-service.js.map +1 -0
- package/dist/core/profiles/profile-types.d.ts +28 -0
- package/dist/core/profiles/profile-types.d.ts.map +1 -0
- package/dist/core/profiles/profile-types.js +13 -0
- package/dist/core/profiles/profile-types.js.map +1 -0
- package/dist/core/secrets/secrets-service.d.ts +25 -0
- package/dist/core/secrets/secrets-service.d.ts.map +1 -0
- package/dist/core/secrets/secrets-service.js +67 -0
- package/dist/core/secrets/secrets-service.js.map +1 -0
- package/dist/core/secrets/secrets-types.d.ts +29 -0
- package/dist/core/secrets/secrets-types.d.ts.map +1 -0
- package/dist/core/secrets/secrets-types.js +33 -0
- package/dist/core/secrets/secrets-types.js.map +1 -0
- package/dist/core/sqlite/chat-schema.d.ts +14 -0
- package/dist/core/sqlite/chat-schema.d.ts.map +1 -0
- package/dist/core/sqlite/chat-schema.js +172 -0
- package/dist/core/sqlite/chat-schema.js.map +1 -0
- package/dist/core/sqlite/core-schema.d.ts +14 -0
- package/dist/core/sqlite/core-schema.d.ts.map +1 -0
- package/dist/core/sqlite/core-schema.js +54 -0
- package/dist/core/sqlite/core-schema.js.map +1 -0
- package/dist/core/sqlite/database.d.ts +40 -0
- package/dist/core/sqlite/database.d.ts.map +1 -0
- package/dist/core/sqlite/database.js +68 -0
- package/dist/core/sqlite/database.js.map +1 -0
- package/dist/core/sqlite/migrations.d.ts +22 -0
- package/dist/core/sqlite/migrations.d.ts.map +1 -0
- package/dist/core/sqlite/migrations.js +64 -0
- package/dist/core/sqlite/migrations.js.map +1 -0
- package/dist/modules/chat/inbox/conversation-service.d.ts +35 -0
- package/dist/modules/chat/inbox/conversation-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/conversation-service.js +54 -0
- package/dist/modules/chat/inbox/conversation-service.js.map +1 -0
- package/dist/modules/chat/inbox/history-service.d.ts +25 -0
- package/dist/modules/chat/inbox/history-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/history-service.js +57 -0
- package/dist/modules/chat/inbox/history-service.js.map +1 -0
- package/dist/modules/chat/inbox/index.d.ts +9 -0
- package/dist/modules/chat/inbox/index.d.ts.map +1 -0
- package/dist/modules/chat/inbox/index.js +9 -0
- package/dist/modules/chat/inbox/index.js.map +1 -0
- package/dist/modules/chat/inbox/read-service.d.ts +36 -0
- package/dist/modules/chat/inbox/read-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/read-service.js +91 -0
- package/dist/modules/chat/inbox/read-service.js.map +1 -0
- package/dist/modules/chat/inbox/search-service.d.ts +20 -0
- package/dist/modules/chat/inbox/search-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/search-service.js +23 -0
- package/dist/modules/chat/inbox/search-service.js.map +1 -0
- package/dist/modules/chat/inbox/unread-service.d.ts +38 -0
- package/dist/modules/chat/inbox/unread-service.d.ts.map +1 -0
- package/dist/modules/chat/inbox/unread-service.js +65 -0
- package/dist/modules/chat/inbox/unread-service.js.map +1 -0
- package/dist/modules/chat/render/message-render.d.ts +35 -0
- package/dist/modules/chat/render/message-render.d.ts.map +1 -0
- package/dist/modules/chat/render/message-render.js +129 -0
- package/dist/modules/chat/render/message-render.js.map +1 -0
- package/dist/modules/chat/send/conversation-service.d.ts +53 -0
- package/dist/modules/chat/send/conversation-service.d.ts.map +1 -0
- package/dist/modules/chat/send/conversation-service.js +110 -0
- package/dist/modules/chat/send/conversation-service.js.map +1 -0
- package/dist/modules/chat/send/directory-cache-service.d.ts +37 -0
- package/dist/modules/chat/send/directory-cache-service.d.ts.map +1 -0
- package/dist/modules/chat/send/directory-cache-service.js +49 -0
- package/dist/modules/chat/send/directory-cache-service.js.map +1 -0
- package/dist/modules/chat/send/send-service.d.ts +36 -0
- package/dist/modules/chat/send/send-service.d.ts.map +1 -0
- package/dist/modules/chat/send/send-service.js +113 -0
- package/dist/modules/chat/send/send-service.js.map +1 -0
- package/dist/modules/chat/store/conversation-repo.d.ts +53 -0
- package/dist/modules/chat/store/conversation-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/conversation-repo.js +75 -0
- package/dist/modules/chat/store/conversation-repo.js.map +1 -0
- package/dist/modules/chat/store/directory-cache-repo.d.ts +41 -0
- package/dist/modules/chat/store/directory-cache-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/directory-cache-repo.js +64 -0
- package/dist/modules/chat/store/directory-cache-repo.js.map +1 -0
- package/dist/modules/chat/store/job-repo.d.ts +72 -0
- package/dist/modules/chat/store/job-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/job-repo.js +140 -0
- package/dist/modules/chat/store/job-repo.js.map +1 -0
- package/dist/modules/chat/store/message-repo.d.ts +98 -0
- package/dist/modules/chat/store/message-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/message-repo.js +231 -0
- package/dist/modules/chat/store/message-repo.js.map +1 -0
- package/dist/modules/chat/store/outbox-repo.d.ts +73 -0
- package/dist/modules/chat/store/outbox-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/outbox-repo.js +112 -0
- package/dist/modules/chat/store/outbox-repo.js.map +1 -0
- package/dist/modules/chat/store/read-state-repo.d.ts +83 -0
- package/dist/modules/chat/store/read-state-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/read-state-repo.js +210 -0
- package/dist/modules/chat/store/read-state-repo.js.map +1 -0
- package/dist/modules/chat/store/sync-state-repo.d.ts +45 -0
- package/dist/modules/chat/store/sync-state-repo.d.ts.map +1 -0
- package/dist/modules/chat/store/sync-state-repo.js +67 -0
- package/dist/modules/chat/store/sync-state-repo.js.map +1 -0
- package/dist/modules/chat/sync/backfill.d.ts +13 -0
- package/dist/modules/chat/sync/backfill.d.ts.map +1 -0
- package/dist/modules/chat/sync/backfill.js +37 -0
- package/dist/modules/chat/sync/backfill.js.map +1 -0
- package/dist/modules/chat/sync/cron-manager.d.ts +50 -0
- package/dist/modules/chat/sync/cron-manager.d.ts.map +1 -0
- package/dist/modules/chat/sync/cron-manager.js +164 -0
- package/dist/modules/chat/sync/cron-manager.js.map +1 -0
- package/dist/modules/chat/sync/index.d.ts +8 -0
- package/dist/modules/chat/sync/index.d.ts.map +1 -0
- package/dist/modules/chat/sync/index.js +7 -0
- package/dist/modules/chat/sync/index.js.map +1 -0
- package/dist/modules/chat/sync/job-logger.d.ts +44 -0
- package/dist/modules/chat/sync/job-logger.d.ts.map +1 -0
- package/dist/modules/chat/sync/job-logger.js +139 -0
- package/dist/modules/chat/sync/job-logger.js.map +1 -0
- package/dist/modules/chat/sync/sync-service.d.ts +14 -0
- package/dist/modules/chat/sync/sync-service.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-service.js +174 -0
- package/dist/modules/chat/sync/sync-service.js.map +1 -0
- package/dist/modules/chat/sync/sync-status.d.ts +14 -0
- package/dist/modules/chat/sync/sync-status.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-status.js +77 -0
- package/dist/modules/chat/sync/sync-status.js.map +1 -0
- package/dist/modules/chat/sync/sync-types.d.ts +80 -0
- package/dist/modules/chat/sync/sync-types.d.ts.map +1 -0
- package/dist/modules/chat/sync/sync-types.js +5 -0
- package/dist/modules/chat/sync/sync-types.js.map +1 -0
- package/dist/modules/chat/sync/watch-mode.d.ts +45 -0
- package/dist/modules/chat/sync/watch-mode.d.ts.map +1 -0
- package/dist/modules/chat/sync/watch-mode.js +161 -0
- package/dist/modules/chat/sync/watch-mode.js.map +1 -0
- package/package.json +67 -0
- package/tool-schema.json +1039 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbox repository - manage failed/pending message sends
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Enqueue a message to outbox
|
|
6
|
+
*/
|
|
7
|
+
export function enqueueMessage(db, message) {
|
|
8
|
+
db.prepare(`
|
|
9
|
+
INSERT INTO outbox (
|
|
10
|
+
id, conversation_id, recipient_agent_id, content, type, in_reply_to, mentions,
|
|
11
|
+
status, retry_count, created_at
|
|
12
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', 0, datetime('now'))
|
|
13
|
+
`).run(message.id, message.conversationId || null, message.recipientAgentId || null, message.content, message.type || 'text', message.inReplyTo || null, message.mentions ? JSON.stringify(message.mentions) : null);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get pending messages from outbox
|
|
17
|
+
*/
|
|
18
|
+
export function getPendingMessages(db) {
|
|
19
|
+
return db.prepare(`
|
|
20
|
+
SELECT * FROM outbox WHERE status = 'pending' ORDER BY created_at ASC
|
|
21
|
+
`).all();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get all outbox entries
|
|
25
|
+
*/
|
|
26
|
+
export function getAllOutboxEntries(db) {
|
|
27
|
+
return db.prepare(`
|
|
28
|
+
SELECT * FROM outbox ORDER BY created_at DESC
|
|
29
|
+
`).all();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Mark an outbox entry as sent
|
|
33
|
+
*/
|
|
34
|
+
export function markMessageSent(db, outboxId, remoteMessageId) {
|
|
35
|
+
db.prepare(`
|
|
36
|
+
UPDATE outbox SET
|
|
37
|
+
status = 'sent',
|
|
38
|
+
remote_message_id = ?,
|
|
39
|
+
sent_at = datetime('now'),
|
|
40
|
+
last_error = NULL
|
|
41
|
+
WHERE id = ?
|
|
42
|
+
`).run(remoteMessageId, outboxId);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Mark an outbox entry as failed
|
|
46
|
+
*/
|
|
47
|
+
export function markMessageFailed(db, outboxId, error) {
|
|
48
|
+
db.prepare(`
|
|
49
|
+
UPDATE outbox SET
|
|
50
|
+
status = 'failed',
|
|
51
|
+
retry_count = retry_count + 1,
|
|
52
|
+
last_error = ?
|
|
53
|
+
WHERE id = ?
|
|
54
|
+
`).run(error, outboxId);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get retryable messages (retry_count < maxRetries)
|
|
58
|
+
*/
|
|
59
|
+
export function getRetryableMessages(db, maxRetries) {
|
|
60
|
+
return db.prepare(`
|
|
61
|
+
SELECT * FROM outbox
|
|
62
|
+
WHERE status IN ('pending', 'failed') AND retry_count < ?
|
|
63
|
+
ORDER BY created_at ASC
|
|
64
|
+
`).all(maxRetries);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Reset a failed message to pending for retry
|
|
68
|
+
*/
|
|
69
|
+
export function resetMessageForRetry(db, outboxId) {
|
|
70
|
+
db.prepare(`
|
|
71
|
+
UPDATE outbox SET
|
|
72
|
+
status = 'pending',
|
|
73
|
+
last_error = NULL
|
|
74
|
+
WHERE id = ?
|
|
75
|
+
`).run(outboxId);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Delete an outbox entry
|
|
79
|
+
*/
|
|
80
|
+
export function deleteOutboxEntry(db, outboxId) {
|
|
81
|
+
db.prepare('DELETE FROM outbox WHERE id = ?').run(outboxId);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get outbox statistics
|
|
85
|
+
*/
|
|
86
|
+
export function getOutboxStats(db) {
|
|
87
|
+
const row = db.prepare(`
|
|
88
|
+
SELECT
|
|
89
|
+
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending,
|
|
90
|
+
SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
|
|
91
|
+
SUM(CASE WHEN status = 'sent' THEN 1 ELSE 0 END) as sent,
|
|
92
|
+
SUM(retry_count) as totalRetries
|
|
93
|
+
FROM outbox
|
|
94
|
+
`).get();
|
|
95
|
+
return {
|
|
96
|
+
pending: row.pending || 0,
|
|
97
|
+
failed: row.failed || 0,
|
|
98
|
+
sent: row.sent || 0,
|
|
99
|
+
totalRetries: row.totalRetries || 0,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clean up old sent entries (older than specified hours)
|
|
104
|
+
*/
|
|
105
|
+
export function cleanupOldOutboxEntries(db, olderThanHours = 24) {
|
|
106
|
+
const result = db.prepare(`
|
|
107
|
+
DELETE FROM outbox
|
|
108
|
+
WHERE status = 'sent' AND sent_at < datetime('now', ?)
|
|
109
|
+
`).run(`-${olderThanHours} hours`);
|
|
110
|
+
return result.changes;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=outbox-repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox-repo.js","sourceRoot":"","sources":["../../../../src/modules/chat/store/outbox-repo.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoBH;;GAEG;AACH,MAAM,UAAU,cAAc,CAC5B,EAAqB,EACrB,OAQC;IAED,EAAE,CAAC,OAAO,CAAC;;;;;GAKV,CAAC,CAAC,GAAG,CACJ,OAAO,CAAC,EAAE,EACV,OAAO,CAAC,cAAc,IAAI,IAAI,EAC9B,OAAO,CAAC,gBAAgB,IAAI,IAAI,EAChC,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,IAAI,IAAI,MAAM,EACtB,OAAO,CAAC,SAAS,IAAI,IAAI,EACzB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAC3D,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAqB;IACtD,OAAO,EAAE,CAAC,OAAO,CAAC;;GAEjB,CAAC,CAAC,GAAG,EAAmB,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAqB;IACvD,OAAO,EAAE,CAAC,OAAO,CAAC;;GAEjB,CAAC,CAAC,GAAG,EAAmB,CAAC;AAC5B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,EAAqB,EACrB,QAAgB,EAChB,eAAuB;IAEvB,EAAE,CAAC,OAAO,CAAC;;;;;;;GAOV,CAAC,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,EAAqB,EACrB,QAAgB,EAChB,KAAa;IAEb,EAAE,CAAC,OAAO,CAAC;;;;;;GAMV,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,EAAqB,EACrB,UAAkB;IAElB,OAAO,EAAE,CAAC,OAAO,CAAC;;;;GAIjB,CAAC,CAAC,GAAG,CAAC,UAAU,CAAkB,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,EAAqB,EACrB,QAAgB;IAEhB,EAAE,CAAC,OAAO,CAAC;;;;;GAKV,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAAqB,EAAE,QAAgB;IACvE,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,EAAqB;IAMlD,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;GAOtB,CAAC,CAAC,GAAG,EAAyG,CAAC;IAEhH,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,OAAO,IAAI,CAAC;QACzB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC;QACvB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC;QACnB,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,EAAqB,EACrB,iBAAyB,EAAE;IAE3B,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC;;;GAGzB,CAAC,CAAC,GAAG,CAAC,IAAI,cAAc,QAAQ,CAAC,CAAC;IAEnC,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read state repository - managing read/unread tracking
|
|
3
|
+
*/
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
/**
|
|
6
|
+
* Get unread message count by conversation
|
|
7
|
+
*/
|
|
8
|
+
export declare function getUnreadByConversation(db: Database.Database): Array<{
|
|
9
|
+
conversation_id: string;
|
|
10
|
+
unread_count: number;
|
|
11
|
+
last_message_at: string;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Mark all messages in a conversation as read
|
|
15
|
+
*/
|
|
16
|
+
export declare function markConversationRead(db: Database.Database, conversationId: string): number;
|
|
17
|
+
/**
|
|
18
|
+
* Mark specific messages as read
|
|
19
|
+
*/
|
|
20
|
+
export declare function markMessagesRead(db: Database.Database, messageIds: string[]): number;
|
|
21
|
+
/**
|
|
22
|
+
* Get unread summary for all conversations
|
|
23
|
+
*/
|
|
24
|
+
export declare function getUnreadSummary(db: Database.Database): Array<{
|
|
25
|
+
conversation_id: string;
|
|
26
|
+
conversation_type: string;
|
|
27
|
+
conversation_name: string | null;
|
|
28
|
+
unread_count: number;
|
|
29
|
+
last_unread_at: string;
|
|
30
|
+
last_sender: string;
|
|
31
|
+
has_mention: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Get unread messages that mention the current agent
|
|
35
|
+
*/
|
|
36
|
+
export declare function getUnreadMentions(db: Database.Database, options?: {
|
|
37
|
+
conversationId?: string;
|
|
38
|
+
limit?: number;
|
|
39
|
+
}): Array<{
|
|
40
|
+
message_id: string;
|
|
41
|
+
conversation_id: string;
|
|
42
|
+
sender_id: string;
|
|
43
|
+
content: string | null;
|
|
44
|
+
remote_created_at: string;
|
|
45
|
+
conversation_type: string;
|
|
46
|
+
conversation_name: string | null;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Get unread message count with mention filter
|
|
50
|
+
*/
|
|
51
|
+
export declare function getUnreadCountByMention(db: Database.Database, conversationId?: string): number;
|
|
52
|
+
/**
|
|
53
|
+
* Get detailed unread statistics for a specific conversation
|
|
54
|
+
*/
|
|
55
|
+
export declare function getConversationUnreadStats(db: Database.Database, conversationId: string): {
|
|
56
|
+
totalUnread: number;
|
|
57
|
+
mentionedUnread: number;
|
|
58
|
+
firstUnreadAt: string | null;
|
|
59
|
+
lastUnreadAt: string | null;
|
|
60
|
+
uniqueSenders: number;
|
|
61
|
+
} | null;
|
|
62
|
+
/**
|
|
63
|
+
* Get unread messages with surrounding history context
|
|
64
|
+
* Returns N messages before each unread message
|
|
65
|
+
*/
|
|
66
|
+
export declare function getUnreadWithHistory(db: Database.Database, options?: {
|
|
67
|
+
conversationId?: string;
|
|
68
|
+
historyBefore?: number;
|
|
69
|
+
limit?: number;
|
|
70
|
+
}): Array<{
|
|
71
|
+
message_id: string;
|
|
72
|
+
conversation_id: string;
|
|
73
|
+
sender_id: string;
|
|
74
|
+
content: string | null;
|
|
75
|
+
type: string;
|
|
76
|
+
status: string;
|
|
77
|
+
remote_created_at: string;
|
|
78
|
+
is_read: number;
|
|
79
|
+
is_mentioned: number;
|
|
80
|
+
conversation_type: string;
|
|
81
|
+
conversation_name: string | null;
|
|
82
|
+
}>;
|
|
83
|
+
//# sourceMappingURL=read-state-repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-state-repo.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/store/read-state-repo.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,KAAK,CAAC;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC,CASnF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,cAAc,EAAE,MAAM,GACrB,MAAM,CAUR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,CAcR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,QAAQ,CAAC,QAAQ,GACpB,KAAK,CAAC;IACP,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CA4BD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACxD,KAAK,CAAC;IACP,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,CAAC,CA+BD;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CAiBR;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,cAAc,EAAE,MAAM,GACrB;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CA8BP;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,GAAE;IACP,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CACX,GACL,KAAK,CAAC;IACP,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,CAAC,CAwGD"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read state repository - managing read/unread tracking
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Get unread message count by conversation
|
|
6
|
+
*/
|
|
7
|
+
export function getUnreadByConversation(db) {
|
|
8
|
+
return db.prepare(`
|
|
9
|
+
SELECT m.conversation_id, COUNT(*) as unread_count, MAX(m.remote_created_at) as last_message_at
|
|
10
|
+
FROM message_local_state ml
|
|
11
|
+
JOIN messages m ON m.message_id = ml.message_id
|
|
12
|
+
WHERE ml.is_read = 0 AND m.sender_id != 'me'
|
|
13
|
+
GROUP BY m.conversation_id
|
|
14
|
+
ORDER BY last_message_at DESC
|
|
15
|
+
`).all();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Mark all messages in a conversation as read
|
|
19
|
+
*/
|
|
20
|
+
export function markConversationRead(db, conversationId) {
|
|
21
|
+
const result = db.prepare(`
|
|
22
|
+
UPDATE message_local_state
|
|
23
|
+
SET is_read = 1, read_at = datetime('now'), updated_at = datetime('now')
|
|
24
|
+
WHERE message_id IN (
|
|
25
|
+
SELECT message_id FROM messages WHERE conversation_id = ?
|
|
26
|
+
) AND is_read = 0
|
|
27
|
+
`).run(conversationId);
|
|
28
|
+
return result.changes;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Mark specific messages as read
|
|
32
|
+
*/
|
|
33
|
+
export function markMessagesRead(db, messageIds) {
|
|
34
|
+
if (messageIds.length === 0) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
const placeholders = messageIds.map(() => '?').join(',');
|
|
38
|
+
const query = `
|
|
39
|
+
UPDATE message_local_state
|
|
40
|
+
SET is_read = 1, read_at = datetime('now'), updated_at = datetime('now')
|
|
41
|
+
WHERE message_id IN (${placeholders}) AND is_read = 0
|
|
42
|
+
`;
|
|
43
|
+
const result = db.prepare(query).run(...messageIds);
|
|
44
|
+
return result.changes;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get unread summary for all conversations
|
|
48
|
+
*/
|
|
49
|
+
export function getUnreadSummary(db) {
|
|
50
|
+
return db.prepare(`
|
|
51
|
+
SELECT
|
|
52
|
+
c.conversation_id,
|
|
53
|
+
c.type as conversation_type,
|
|
54
|
+
c.name as conversation_name,
|
|
55
|
+
COUNT(ml.message_id) as unread_count,
|
|
56
|
+
MAX(m.remote_created_at) as last_unread_at,
|
|
57
|
+
(SELECT m2.sender_id FROM messages m2
|
|
58
|
+
JOIN message_local_state ml2 ON m2.message_id = ml2.message_id
|
|
59
|
+
WHERE m2.conversation_id = c.conversation_id AND ml2.is_read = 0
|
|
60
|
+
ORDER BY m2.remote_created_at DESC LIMIT 1) as last_sender,
|
|
61
|
+
MAX(CASE WHEN ml.is_mentioned = 1 THEN 1 ELSE 0 END) as has_mention
|
|
62
|
+
FROM conversations c
|
|
63
|
+
JOIN messages m ON m.conversation_id = c.conversation_id
|
|
64
|
+
JOIN message_local_state ml ON m.message_id = ml.message_id
|
|
65
|
+
WHERE ml.is_read = 0 AND m.sender_id != 'me'
|
|
66
|
+
GROUP BY c.conversation_id
|
|
67
|
+
ORDER BY last_unread_at DESC
|
|
68
|
+
`).all();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get unread messages that mention the current agent
|
|
72
|
+
*/
|
|
73
|
+
export function getUnreadMentions(db, options = {}) {
|
|
74
|
+
const limit = options.limit || 50;
|
|
75
|
+
let query = `
|
|
76
|
+
SELECT m.message_id, m.conversation_id, m.sender_id, m.content, m.remote_created_at,
|
|
77
|
+
c.type as conversation_type, c.name as conversation_name
|
|
78
|
+
FROM message_local_state ml
|
|
79
|
+
JOIN messages m ON m.message_id = ml.message_id
|
|
80
|
+
JOIN conversations c ON c.conversation_id = m.conversation_id
|
|
81
|
+
WHERE ml.is_read = 0 AND ml.is_mentioned = 1 AND m.sender_id != 'me'
|
|
82
|
+
`;
|
|
83
|
+
const params = [];
|
|
84
|
+
if (options.conversationId) {
|
|
85
|
+
query += ` AND m.conversation_id = ?`;
|
|
86
|
+
params.push(options.conversationId);
|
|
87
|
+
}
|
|
88
|
+
query += ` ORDER BY m.remote_created_at DESC LIMIT ?`;
|
|
89
|
+
params.push(limit);
|
|
90
|
+
return db.prepare(query).all(...params);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get unread message count with mention filter
|
|
94
|
+
*/
|
|
95
|
+
export function getUnreadCountByMention(db, conversationId) {
|
|
96
|
+
let query = `
|
|
97
|
+
SELECT COUNT(*) as count
|
|
98
|
+
FROM message_local_state ml
|
|
99
|
+
JOIN messages m ON m.message_id = ml.message_id
|
|
100
|
+
WHERE ml.is_read = 0 AND ml.is_mentioned = 1 AND m.sender_id != 'me'
|
|
101
|
+
`;
|
|
102
|
+
const params = [];
|
|
103
|
+
if (conversationId) {
|
|
104
|
+
query += ` AND m.conversation_id = ?`;
|
|
105
|
+
params.push(conversationId);
|
|
106
|
+
}
|
|
107
|
+
const row = db.prepare(query).get(...params);
|
|
108
|
+
return row.count;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get detailed unread statistics for a specific conversation
|
|
112
|
+
*/
|
|
113
|
+
export function getConversationUnreadStats(db, conversationId) {
|
|
114
|
+
const row = db.prepare(`
|
|
115
|
+
SELECT
|
|
116
|
+
COUNT(*) as totalUnread,
|
|
117
|
+
SUM(CASE WHEN ml.is_mentioned = 1 THEN 1 ELSE 0 END) as mentionedUnread,
|
|
118
|
+
MIN(m.remote_created_at) as firstUnreadAt,
|
|
119
|
+
MAX(m.remote_created_at) as lastUnreadAt,
|
|
120
|
+
COUNT(DISTINCT m.sender_id) as uniqueSenders
|
|
121
|
+
FROM message_local_state ml
|
|
122
|
+
JOIN messages m ON m.message_id = ml.message_id
|
|
123
|
+
WHERE ml.is_read = 0 AND m.conversation_id = ? AND m.sender_id != 'me'
|
|
124
|
+
`).get(conversationId);
|
|
125
|
+
if (row.totalUnread === 0) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
totalUnread: row.totalUnread,
|
|
130
|
+
mentionedUnread: row.mentionedUnread,
|
|
131
|
+
firstUnreadAt: row.firstUnreadAt,
|
|
132
|
+
lastUnreadAt: row.lastUnreadAt,
|
|
133
|
+
uniqueSenders: row.uniqueSenders,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get unread messages with surrounding history context
|
|
138
|
+
* Returns N messages before each unread message
|
|
139
|
+
*/
|
|
140
|
+
export function getUnreadWithHistory(db, options = {}) {
|
|
141
|
+
const historyBefore = options.historyBefore || 10;
|
|
142
|
+
const limit = options.limit || 100;
|
|
143
|
+
// First, get unread message IDs
|
|
144
|
+
let unreadQuery = `
|
|
145
|
+
SELECT m.message_id, m.remote_created_at
|
|
146
|
+
FROM message_local_state ml
|
|
147
|
+
JOIN messages m ON m.message_id = ml.message_id
|
|
148
|
+
WHERE ml.is_read = 0 AND m.sender_id != 'me'
|
|
149
|
+
`;
|
|
150
|
+
const unreadParams = [];
|
|
151
|
+
if (options.conversationId) {
|
|
152
|
+
unreadQuery += ` AND m.conversation_id = ?`;
|
|
153
|
+
unreadParams.push(options.conversationId);
|
|
154
|
+
}
|
|
155
|
+
unreadQuery += ` ORDER BY m.remote_created_at ASC`;
|
|
156
|
+
const unreadMessages = db.prepare(unreadQuery).all(...unreadParams);
|
|
157
|
+
if (unreadMessages.length === 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
// Get the earliest unread message's timestamp
|
|
161
|
+
const earliestUnread = unreadMessages[0].remote_created_at;
|
|
162
|
+
// Fetch messages: history before earliest unread + all unread
|
|
163
|
+
let query = `
|
|
164
|
+
SELECT m.message_id, m.conversation_id, m.sender_id, m.content, m.type, m.status,
|
|
165
|
+
m.remote_created_at, ml.is_read, ml.is_mentioned,
|
|
166
|
+
c.type as conversation_type, c.name as conversation_name
|
|
167
|
+
FROM messages m
|
|
168
|
+
JOIN message_local_state ml ON m.message_id = ml.message_id
|
|
169
|
+
JOIN conversations c ON c.conversation_id = m.conversation_id
|
|
170
|
+
WHERE m.remote_created_at < ? AND m.sender_id != 'me'
|
|
171
|
+
`;
|
|
172
|
+
const params = [earliestUnread];
|
|
173
|
+
if (options.conversationId) {
|
|
174
|
+
query += ` AND m.conversation_id = ?`;
|
|
175
|
+
params.push(options.conversationId);
|
|
176
|
+
}
|
|
177
|
+
query += ` ORDER BY m.remote_created_at DESC LIMIT ?`;
|
|
178
|
+
params.push(historyBefore);
|
|
179
|
+
const historyMessages = db.prepare(query).all(...params);
|
|
180
|
+
// Now get the unread messages
|
|
181
|
+
let unreadFullQuery = `
|
|
182
|
+
SELECT m.message_id, m.conversation_id, m.sender_id, m.content, m.type, m.status,
|
|
183
|
+
m.remote_created_at, ml.is_read, ml.is_mentioned,
|
|
184
|
+
c.type as conversation_type, c.name as conversation_name
|
|
185
|
+
FROM message_local_state ml
|
|
186
|
+
JOIN messages m ON m.message_id = ml.message_id
|
|
187
|
+
JOIN conversations c ON c.conversation_id = m.conversation_id
|
|
188
|
+
WHERE ml.is_read = 0 AND m.sender_id != 'me'
|
|
189
|
+
`;
|
|
190
|
+
const unreadFullParams = [];
|
|
191
|
+
if (options.conversationId) {
|
|
192
|
+
unreadFullQuery += ` AND m.conversation_id = ?`;
|
|
193
|
+
unreadFullParams.push(options.conversationId);
|
|
194
|
+
}
|
|
195
|
+
unreadFullQuery += ` ORDER BY m.remote_created_at ASC LIMIT ?`;
|
|
196
|
+
unreadFullParams.push(limit);
|
|
197
|
+
const unreadFullMessages = db.prepare(unreadFullQuery).all(...unreadFullParams);
|
|
198
|
+
// Combine and deduplicate
|
|
199
|
+
const allMessages = [...historyMessages, ...unreadFullMessages];
|
|
200
|
+
const seen = new Set();
|
|
201
|
+
const deduplicated = allMessages.filter((msg) => {
|
|
202
|
+
if (seen.has(msg.message_id))
|
|
203
|
+
return false;
|
|
204
|
+
seen.add(msg.message_id);
|
|
205
|
+
return true;
|
|
206
|
+
});
|
|
207
|
+
// Sort by timestamp
|
|
208
|
+
return deduplicated.sort((a, b) => new Date(a.remote_created_at).getTime() - new Date(b.remote_created_at).getTime());
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=read-state-repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-state-repo.js","sourceRoot":"","sources":["../../../../src/modules/chat/store/read-state-repo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync state repository - persistence for sync cursors and timing
|
|
3
|
+
*/
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
export interface SyncStateRecord {
|
|
6
|
+
id: number;
|
|
7
|
+
last_sync_attempt: string | null;
|
|
8
|
+
last_sync_success: string | null;
|
|
9
|
+
last_sync_error: string | null;
|
|
10
|
+
global_cursor: string | null;
|
|
11
|
+
next_poll_after: string | null;
|
|
12
|
+
min_poll_interval: number;
|
|
13
|
+
total_messages_synced: number;
|
|
14
|
+
total_conversations_synced: number;
|
|
15
|
+
updated_at: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Initialize sync state if not exists
|
|
19
|
+
*/
|
|
20
|
+
export declare function initializeSyncState(db: Database.Database): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get current sync state
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSyncState(db: Database.Database): SyncStateRecord;
|
|
25
|
+
/**
|
|
26
|
+
* Update sync state after a sync attempt
|
|
27
|
+
*/
|
|
28
|
+
export declare function updateSyncState(db: Database.Database, updates: {
|
|
29
|
+
success?: boolean;
|
|
30
|
+
error?: string;
|
|
31
|
+
globalCursor?: string;
|
|
32
|
+
nextPollAfter?: string;
|
|
33
|
+
minPollInterval?: number;
|
|
34
|
+
messagesSynced?: number;
|
|
35
|
+
conversationsSynced?: number;
|
|
36
|
+
}): void;
|
|
37
|
+
/**
|
|
38
|
+
* Check if we can poll now (respecting rate limits)
|
|
39
|
+
*/
|
|
40
|
+
export declare function canPollNow(db: Database.Database): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Get next allowed poll time
|
|
43
|
+
*/
|
|
44
|
+
export declare function getNextPollTime(db: Database.Database): Date | null;
|
|
45
|
+
//# sourceMappingURL=sync-state-repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-state-repo.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/store/sync-state-repo.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,0BAA0B,EAAE,MAAM,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAS/D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,eAAe,CAInE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,GACA,IAAI,CAgCN;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAWzD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAQlE"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync state repository - persistence for sync cursors and timing
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Initialize sync state if not exists
|
|
6
|
+
*/
|
|
7
|
+
export function initializeSyncState(db) {
|
|
8
|
+
const existing = db.prepare('SELECT id FROM sync_state WHERE id = 1').get();
|
|
9
|
+
if (!existing) {
|
|
10
|
+
db.prepare(`
|
|
11
|
+
INSERT INTO sync_state (id, min_poll_interval, total_messages_synced, total_conversations_synced)
|
|
12
|
+
VALUES (1, 1, 0, 0)
|
|
13
|
+
`).run();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Get current sync state
|
|
18
|
+
*/
|
|
19
|
+
export function getSyncState(db) {
|
|
20
|
+
initializeSyncState(db);
|
|
21
|
+
return db.prepare('SELECT * FROM sync_state WHERE id = 1').get();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Update sync state after a sync attempt
|
|
25
|
+
*/
|
|
26
|
+
export function updateSyncState(db, updates) {
|
|
27
|
+
initializeSyncState(db);
|
|
28
|
+
const currentState = getSyncState(db);
|
|
29
|
+
const now = new Date().toISOString();
|
|
30
|
+
const stmt = db.prepare(`
|
|
31
|
+
UPDATE sync_state SET
|
|
32
|
+
last_sync_attempt = ?,
|
|
33
|
+
last_sync_success = COALESCE(?, last_sync_success),
|
|
34
|
+
last_sync_error = COALESCE(?, last_sync_error),
|
|
35
|
+
global_cursor = COALESCE(?, global_cursor),
|
|
36
|
+
next_poll_after = COALESCE(?, next_poll_after),
|
|
37
|
+
min_poll_interval = COALESCE(?, min_poll_interval),
|
|
38
|
+
total_messages_synced = total_messages_synced + COALESCE(?, 0),
|
|
39
|
+
total_conversations_synced = total_conversations_synced + COALESCE(?, 0),
|
|
40
|
+
updated_at = ?
|
|
41
|
+
WHERE id = 1
|
|
42
|
+
`);
|
|
43
|
+
stmt.run(now, updates.success ? now : null, updates.error || null, updates.globalCursor || null, updates.nextPollAfter || null, updates.minPollInterval || null, updates.messagesSynced || 0, updates.conversationsSynced || 0, now);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if we can poll now (respecting rate limits)
|
|
47
|
+
*/
|
|
48
|
+
export function canPollNow(db) {
|
|
49
|
+
const state = getSyncState(db);
|
|
50
|
+
if (!state.next_poll_after) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
const nextPollAfter = new Date(state.next_poll_after);
|
|
54
|
+
const now = new Date();
|
|
55
|
+
return now >= nextPollAfter;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get next allowed poll time
|
|
59
|
+
*/
|
|
60
|
+
export function getNextPollTime(db) {
|
|
61
|
+
const state = getSyncState(db);
|
|
62
|
+
if (!state.next_poll_after) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return new Date(state.next_poll_after);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=sync-state-repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-state-repo.js","sourceRoot":"","sources":["../../../../src/modules/chat/store/sync-state-repo.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiBH;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAqB;IACvD,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,GAAG,EAAE,CAAC;IAE5E,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,EAAE,CAAC,OAAO,CAAC;;;KAGV,CAAC,CAAC,GAAG,EAAE,CAAC;IACX,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,EAAqB;IAChD,mBAAmB,CAAC,EAAE,CAAC,CAAC;IAExB,OAAO,EAAE,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,EAAqB,CAAC;AACtF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,EAAqB,EACrB,OAQC;IAED,mBAAmB,CAAC,EAAE,CAAC,CAAC;IAExB,MAAM,YAAY,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IAEtC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;;;;;GAYvB,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CACN,GAAG,EACH,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAC5B,OAAO,CAAC,KAAK,IAAI,IAAI,EACrB,OAAO,CAAC,YAAY,IAAI,IAAI,EAC5B,OAAO,CAAC,aAAa,IAAI,IAAI,EAC7B,OAAO,CAAC,eAAe,IAAI,IAAI,EAC/B,OAAO,CAAC,cAAc,IAAI,CAAC,EAC3B,OAAO,CAAC,mBAAmB,IAAI,CAAC,EAChC,GAAG,CACJ,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,EAAqB;IAC9C,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IAE/B,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,OAAO,GAAG,IAAI,aAAa,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,EAAqB;IACnD,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IAE/B,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation backfill logic — fetch metadata for missing conversations
|
|
3
|
+
*/
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
export interface BackfillResult {
|
|
6
|
+
inserted: boolean;
|
|
7
|
+
updated: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Backfill conversation metadata from the remote API
|
|
11
|
+
*/
|
|
12
|
+
export declare function backfillConversation(accessToken: string, conversationId: string, chatDb: Database.Database): Promise<BackfillResult>;
|
|
13
|
+
//# sourceMappingURL=backfill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backfill.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/sync/backfill.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,QAAQ,CAAC,QAAQ,GACxB,OAAO,CAAC,cAAc,CAAC,CAkCzB"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation backfill logic — fetch metadata for missing conversations
|
|
3
|
+
*/
|
|
4
|
+
import { getConversation } from '../../../core/http/chat-api.js';
|
|
5
|
+
import { upsertConversation, upsertParticipants } from '../store/conversation-repo.js';
|
|
6
|
+
/**
|
|
7
|
+
* Backfill conversation metadata from the remote API
|
|
8
|
+
*/
|
|
9
|
+
export async function backfillConversation(accessToken, conversationId, chatDb) {
|
|
10
|
+
// Check if already exists
|
|
11
|
+
const existing = chatDb.prepare('SELECT conversation_id FROM conversations WHERE conversation_id = ?').get(conversationId);
|
|
12
|
+
if (existing) {
|
|
13
|
+
// Conversation already exists, nothing to backfill
|
|
14
|
+
return { inserted: false, updated: false };
|
|
15
|
+
}
|
|
16
|
+
// Fetch from remote
|
|
17
|
+
const response = await getConversation(accessToken, conversationId);
|
|
18
|
+
const conv = response.data;
|
|
19
|
+
// Upsert conversation
|
|
20
|
+
upsertConversation(chatDb, {
|
|
21
|
+
conversation_id: conv.conversation_id,
|
|
22
|
+
type: conv.type || 'group',
|
|
23
|
+
name: conv.name || null,
|
|
24
|
+
created_by: conv.creator_id || '',
|
|
25
|
+
created_at: conv.created_at,
|
|
26
|
+
updated_at: conv.updated_at,
|
|
27
|
+
});
|
|
28
|
+
// Upsert participants if available
|
|
29
|
+
if (conv.members && conv.members.length > 0) {
|
|
30
|
+
upsertParticipants(chatDb, conv.conversation_id, conv.members.map(m => ({
|
|
31
|
+
agent_id: m.agent_id,
|
|
32
|
+
role: m.role || 'member',
|
|
33
|
+
})));
|
|
34
|
+
}
|
|
35
|
+
return { inserted: true, updated: false };
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=backfill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backfill.js","sourceRoot":"","sources":["../../../../src/modules/chat/sync/backfill.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAOvF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,WAAmB,EACnB,cAAsB,EACtB,MAAyB;IAEzB,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAC7B,qEAAqE,CACtE,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAEtB,IAAI,QAAQ,EAAE,CAAC;QACb,mDAAmD;QACnD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,oBAAoB;IACpB,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IAE3B,sBAAsB;IACtB,kBAAkB,CAAC,MAAM,EAAE;QACzB,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,IAAI,EAAG,IAAI,CAAC,IAA2B,IAAI,OAAO;QAClD,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;QACvB,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;QACjC,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC,CAAC;IAEH,mCAAmC;IACnC,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5C,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACtE,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,IAAI,EAAG,CAAC,CAAC,IAAqC,IAAI,QAAQ;SAC3D,CAAC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron manager - install/uninstall cron entries for background sync
|
|
3
|
+
*/
|
|
4
|
+
import Database from 'better-sqlite3';
|
|
5
|
+
export interface CronInstallOptions {
|
|
6
|
+
profileName: string;
|
|
7
|
+
schedule?: string;
|
|
8
|
+
command?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CronStatus {
|
|
11
|
+
installed: boolean;
|
|
12
|
+
schedule: string;
|
|
13
|
+
profileName: string;
|
|
14
|
+
lastRun: string | null;
|
|
15
|
+
lastSuccess: string | null;
|
|
16
|
+
lastError: string | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check if cron is installed for a profile
|
|
20
|
+
*/
|
|
21
|
+
export declare function isCronInstalled(db: Database.Database, profileName: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Install cron for a profile
|
|
24
|
+
*/
|
|
25
|
+
export declare function installCron(db: Database.Database, options: CronInstallOptions): {
|
|
26
|
+
success: boolean;
|
|
27
|
+
schedule: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Uninstall cron for a profile
|
|
31
|
+
*/
|
|
32
|
+
export declare function uninstallCron(db: Database.Database, profileName: string): {
|
|
33
|
+
success: boolean;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Get cron status for a profile
|
|
37
|
+
*/
|
|
38
|
+
export declare function getCronStatus(db: Database.Database, profileName: string): CronStatus;
|
|
39
|
+
/**
|
|
40
|
+
* Detect cron conflicts (duplicate entries)
|
|
41
|
+
*/
|
|
42
|
+
export declare function detectCronConflicts(db: Database.Database, profileName: string): string[];
|
|
43
|
+
/**
|
|
44
|
+
* List all installed cron entries
|
|
45
|
+
*/
|
|
46
|
+
export declare function listInstalledCrons(): Array<{
|
|
47
|
+
profileName: string;
|
|
48
|
+
schedule: string;
|
|
49
|
+
}>;
|
|
50
|
+
//# sourceMappingURL=cron-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-manager.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/sync/cron-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAKtC,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AA+CD;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAGnF;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,EAAE,kBAAkB,GAC1B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAiCxC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAqB9F;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,WAAW,EAAE,MAAM,GAClB,UAAU,CAYZ;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAkBxF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBrF"}
|