@agentshouse/mdruntime 0.1.0-cefbc8bb8a1c0 → 0.1.0-cf08ada271a7f
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 +10 -10
- package/dist/acceptance.d.ts +3 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +309 -0
- package/dist/actions.d.ts +20 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +251 -0
- package/dist/adapter.d.ts +95 -104
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +3 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +21 -56
- package/dist/bootstrap.d.ts +11 -10
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +205 -88
- package/dist/cell.d.ts +6 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +9 -0
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/change-set.d.ts +4 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +6 -0
- package/dist/change.d.ts +1 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +4 -2
- package/dist/chat-types.d.ts +5 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +13 -0
- package/dist/client.d.ts +24 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -5
- package/dist/collection.d.ts +23 -7
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +13 -19
- package/dist/compile.d.ts +6 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +272 -334
- package/dist/connection.d.ts +5 -143
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +101 -5310
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation-live.d.ts +135 -0
- package/dist/conversation-live.d.ts.map +1 -0
- package/dist/conversation-live.js +247 -0
- package/dist/conversation-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +53 -0
- package/dist/conversation.d.ts +41 -47
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +873 -912
- package/dist/declaration.d.ts +10 -0
- package/dist/declaration.d.ts.map +1 -0
- package/dist/declaration.js +24 -0
- package/dist/discovery.d.ts +10 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +177 -0
- package/dist/durability.d.ts +15 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +2 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +17 -7
- package/dist/expectation.d.ts +4 -2
- package/dist/expectation.d.ts.map +1 -1
- package/dist/expectation.js +33 -11
- package/dist/failure.d.ts +1 -0
- package/dist/failure.d.ts.map +1 -1
- package/dist/failure.js +3 -0
- package/dist/figures.d.ts +49 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- package/dist/holdings.d.ts +29 -0
- package/dist/holdings.d.ts.map +1 -0
- package/dist/holdings.js +95 -0
- package/dist/host.d.ts +20 -8
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +38 -33
- package/dist/identity.d.ts +0 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -3
- package/dist/index.d.ts +27 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/install.d.ts +55 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +543 -0
- package/dist/job.d.ts +5 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +7 -0
- package/dist/lifecycle.d.ts +7 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +271 -0
- package/dist/listing.d.ts +53 -0
- package/dist/listing.d.ts.map +1 -0
- package/dist/listing.js +169 -0
- package/dist/live.d.ts +5 -4
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +64 -23
- package/dist/locks.d.ts +9 -0
- package/dist/locks.d.ts.map +1 -0
- package/dist/locks.js +62 -0
- package/dist/log.d.ts +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/lost.d.ts +5 -0
- package/dist/lost.d.ts.map +1 -0
- package/dist/lost.js +61 -0
- package/dist/media.d.ts +1 -1
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +3 -3
- package/dist/memory.d.ts +14 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +177 -85
- package/dist/messages.d.ts +24 -3
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +89 -31
- package/dist/model.d.ts +2 -11
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -23
- package/dist/models.d.ts +10 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +170 -0
- package/dist/observation.d.ts +2 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +14 -14
- package/dist/opened.js +3 -3
- package/dist/opening.d.ts +4 -0
- package/dist/opening.d.ts.map +1 -0
- package/dist/opening.js +59 -0
- package/dist/outcome.d.ts +4 -4
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +3 -0
- package/dist/overlay.d.ts +3 -1
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +43 -21
- package/dist/parts.d.ts +11 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +21 -0
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +22 -0
- package/dist/preparation.d.ts +20 -0
- package/dist/preparation.d.ts.map +1 -0
- package/dist/preparation.js +233 -0
- package/dist/queries.d.ts +16 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +272 -0
- package/dist/query.d.ts +14 -210
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -505
- package/dist/questions.d.ts +34 -0
- package/dist/questions.d.ts.map +1 -0
- package/dist/questions.js +122 -0
- package/dist/queue.d.ts +39 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +455 -0
- package/dist/reach.d.ts +15 -13
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +187 -140
- package/dist/react.d.ts +14 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +10 -1
- package/dist/read.d.ts +7 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +17 -0
- package/dist/readiness.d.ts +2 -16
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +4 -10
- package/dist/reads.d.ts +36 -10
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +160 -77
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +9 -1
- package/dist/refresh.d.ts +7 -5
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +35 -7
- package/dist/refusal.d.ts +5 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +57 -0
- package/dist/replica.d.ts +11 -17
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +64 -34
- package/dist/room-draft.d.ts +7 -8
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +100 -103
- package/dist/room-drafts.d.ts +24 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +217 -0
- package/dist/rows.d.ts +14 -21
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +49 -186
- package/dist/runtime.d.ts +32 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts +41 -86
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +239 -116
- package/dist/saves.d.ts +32 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +413 -0
- package/dist/search.d.ts +12 -63
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +9 -52
- package/dist/seed.d.ts +11 -2
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +71 -1
- package/dist/shared.d.ts +1 -7
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +13 -105
- package/dist/shown.d.ts +32 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +299 -0
- package/dist/socket/admission.d.ts +7 -0
- package/dist/socket/admission.d.ts.map +1 -0
- package/dist/socket/admission.js +39 -0
- package/dist/socket/answers.d.ts +6 -0
- package/dist/socket/answers.d.ts.map +1 -0
- package/dist/socket/answers.js +20 -0
- package/dist/socket/lanes.d.ts +20 -0
- package/dist/socket/lanes.d.ts.map +1 -0
- package/dist/socket/lanes.js +77 -0
- package/dist/socket/reads.d.ts +10 -0
- package/dist/socket/reads.d.ts.map +1 -0
- package/dist/socket/reads.js +31 -0
- package/dist/socket/rooms.d.ts +41 -0
- package/dist/socket/rooms.d.ts.map +1 -0
- package/dist/socket/rooms.js +90 -0
- package/dist/socket/session.d.ts +38 -0
- package/dist/socket/session.d.ts.map +1 -0
- package/dist/socket/session.js +23 -0
- package/dist/socket.d.ts +69 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +175 -0
- package/dist/source.d.ts +61 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +82 -0
- package/dist/status.d.ts +0 -6
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -6
- package/dist/store/fences.d.ts +16 -0
- package/dist/store/fences.d.ts.map +1 -0
- package/dist/store/fences.js +26 -0
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +34 -0
- package/dist/store/readiness.d.ts +10 -0
- package/dist/store/readiness.d.ts.map +1 -0
- package/dist/store/readiness.js +52 -0
- package/dist/store/records.d.ts +210 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +428 -0
- package/dist/store/room-held.d.ts +8 -0
- package/dist/store/room-held.d.ts.map +1 -0
- package/dist/store/room-held.js +17 -0
- package/dist/store/space.d.ts +11 -0
- package/dist/store/space.d.ts.map +1 -0
- package/dist/store/space.js +41 -0
- package/dist/store/watchers.d.ts +17 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +56 -0
- package/dist/store/writes.d.ts +24 -0
- package/dist/store/writes.d.ts.map +1 -0
- package/dist/store/writes.js +125 -0
- package/dist/store.d.ts +107 -157
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +143 -395
- package/dist/stored.d.ts +59 -38
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +279 -210
- package/dist/surface.d.ts +88 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +224 -0
- package/dist/sync.d.ts +19 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +530 -0
- package/dist/tables.d.ts +116 -56
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +214 -98
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/validation.d.ts +3 -4
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +42 -100
- package/dist/windows.d.ts +1 -12
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +2 -75
- package/dist/wire.d.ts +21 -9
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +10 -4
- package/package.json +3 -2
- package/dist/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/fulltext.d.ts +0 -27
- package/dist/fulltext.d.ts.map +0 -1
- package/dist/fulltext.js +0 -370
- package/dist/words.d.ts +0 -19
- package/dist/words.d.ts.map +0 -1
- package/dist/words.js +0 -156
package/dist/tables.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
import { sql } from '@agentshouse/mdmodel';
|
|
1
2
|
import { answerQuery } from './compile.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { conversationRows, droppedMessages, forgottenMessages, heldConversations, keptMessages, messageCount, messageWindow, MESSAGE_TABLES, turnArrived, } from './messages.js';
|
|
4
|
+
import { keptRead, READ_TABLES, readsOfOtherBuildsForgotten, storedRead, } from './reads.js';
|
|
5
|
+
import { conversationTallies, roomTallies, } from './tallies.js';
|
|
6
|
+
import { abandon, release, commit, covering, demoted, ended, entries, erase, facts, fenceRooms, folders, heldLocators, heldRoom, heldRooms, offlineMode, opened, overlaid, presentation, rederive, referrers, refreshing, REPLICA_TABLES, resume, stage, typed, stagedLocators, typedWithin, unrefresh, } from './stored.js';
|
|
5
7
|
const STATEMENTS_HELD = 256;
|
|
6
8
|
export function sqliteConnection(engine, database) {
|
|
7
9
|
const decoder = new TextDecoder();
|
|
8
10
|
const held = new Map();
|
|
11
|
+
database.createFunction(sql.HOLDS_PHRASE, sql.holdsPhrase, {
|
|
12
|
+
arity: 2,
|
|
13
|
+
deterministic: true,
|
|
14
|
+
});
|
|
9
15
|
function prepared(sql) {
|
|
10
16
|
if (sql.includes(';'))
|
|
11
17
|
return null;
|
|
@@ -72,7 +78,7 @@ const TABLES = [
|
|
|
72
78
|
['authored_queues', 'locator TEXT PRIMARY KEY, ids TEXT NOT NULL'],
|
|
73
79
|
[
|
|
74
80
|
'authored_pending',
|
|
75
|
-
'locator TEXT NOT NULL, id TEXT NOT NULL, batch TEXT NOT NULL, state TEXT NOT NULL, files TEXT NOT NULL, PRIMARY KEY (locator, id)',
|
|
81
|
+
'locator TEXT NOT NULL, id TEXT NOT NULL, batch TEXT NOT NULL, state TEXT NOT NULL, files TEXT NOT NULL, paths TEXT NOT NULL, moving INTEGER NOT NULL, PRIMARY KEY (locator, id)',
|
|
76
82
|
],
|
|
77
83
|
[
|
|
78
84
|
'authored_room_drafts',
|
|
@@ -89,38 +95,52 @@ export const RUNTIME_TABLES = [
|
|
|
89
95
|
'CREATE INDEX opened_files_name ON opened_files (locator, path, revision)',
|
|
90
96
|
...REPLICA_TABLES,
|
|
91
97
|
...MESSAGE_TABLES,
|
|
92
|
-
...
|
|
98
|
+
...READ_TABLES,
|
|
93
99
|
];
|
|
94
100
|
const OWNERS = ['authored_pending', 'authored_room_drafts', 'authored_calls'];
|
|
95
101
|
const AUTHORED_KEYS = OWNERS.map((table) => `SELECT value FROM ${table}, json_each(${table}.files)`).join(' UNION ');
|
|
96
102
|
const UNOWNED_PARTS = `DELETE FROM file_parts WHERE key NOT IN (${AUTHORED_KEYS} UNION SELECT key FROM opened_files)`;
|
|
103
|
+
const CLEANABLE_BYTES = `SELECT coalesce(sum(length(bytes)), 0) AS bytes FROM file_parts WHERE key NOT IN (${AUTHORED_KEYS})`;
|
|
97
104
|
const READS = new Set([
|
|
98
|
-
'authored.
|
|
105
|
+
'authored.status',
|
|
106
|
+
'authored.moving',
|
|
107
|
+
'authored.pending',
|
|
108
|
+
'authored.batch',
|
|
109
|
+
'authored.order',
|
|
110
|
+
'authored.queued',
|
|
99
111
|
'authored.roomDrafts',
|
|
112
|
+
'authored.chatDraft.read',
|
|
100
113
|
'authored.chatDrafts',
|
|
101
114
|
'authored.calls',
|
|
102
115
|
'authored.fences',
|
|
116
|
+
'authored.unsent',
|
|
103
117
|
'authored.fact',
|
|
104
118
|
'authored.file',
|
|
105
119
|
'replica.open',
|
|
120
|
+
'replica.rooms',
|
|
121
|
+
'replica.room',
|
|
122
|
+
'replica.covering',
|
|
123
|
+
'replica.offline',
|
|
124
|
+
'replica.held',
|
|
125
|
+
'replica.facts',
|
|
126
|
+
'replica.presentation',
|
|
106
127
|
'replica.query',
|
|
128
|
+
'replica.tallies',
|
|
107
129
|
'replica.entries',
|
|
108
130
|
'replica.typed',
|
|
109
131
|
'replica.referrers',
|
|
110
|
-
'replica.walk',
|
|
111
|
-
'replica.files',
|
|
112
132
|
'replica.folders',
|
|
113
133
|
'replica.typedWithin',
|
|
114
|
-
'replica.counts',
|
|
115
|
-
'replica.search',
|
|
116
|
-
'replica.received',
|
|
117
|
-
'replica.receivedParts',
|
|
118
134
|
'opened.find',
|
|
135
|
+
'opened.held',
|
|
119
136
|
'file.part',
|
|
120
137
|
'conversation.held',
|
|
121
138
|
'conversation.window',
|
|
122
139
|
'conversation.count',
|
|
123
140
|
'conversation.turn',
|
|
141
|
+
'conversation.rows',
|
|
142
|
+
'conversation.tallies',
|
|
143
|
+
'read.stored',
|
|
124
144
|
]);
|
|
125
145
|
const KINDS = new Set([
|
|
126
146
|
...READS,
|
|
@@ -132,18 +152,19 @@ const KINDS = new Set([
|
|
|
132
152
|
'authored.claim',
|
|
133
153
|
'authored.end',
|
|
134
154
|
'replica.stage',
|
|
155
|
+
'replica.resume',
|
|
135
156
|
'replica.refresh',
|
|
136
157
|
'replica.unrefresh',
|
|
137
158
|
'replica.commit',
|
|
138
159
|
'replica.fence',
|
|
139
160
|
'replica.erase',
|
|
140
161
|
'replica.abandon',
|
|
162
|
+
'replica.unfence',
|
|
141
163
|
'replica.release',
|
|
142
164
|
'replica.rederive',
|
|
165
|
+
'replica.demote',
|
|
143
166
|
'replica.fact',
|
|
144
167
|
'replica.present',
|
|
145
|
-
'replica.receive',
|
|
146
|
-
'replica.unreceive',
|
|
147
168
|
'opened.begin',
|
|
148
169
|
'opened.part',
|
|
149
170
|
'opened.keep',
|
|
@@ -152,6 +173,8 @@ const KINDS = new Set([
|
|
|
152
173
|
'conversation.keep',
|
|
153
174
|
'conversation.drop',
|
|
154
175
|
'space.probe',
|
|
176
|
+
'read.keep',
|
|
177
|
+
'read.builds',
|
|
155
178
|
]);
|
|
156
179
|
export function isRuntime(request) {
|
|
157
180
|
return KINDS.has(request.kind);
|
|
@@ -224,29 +247,71 @@ function unowned(connection) {
|
|
|
224
247
|
connection.run(UNOWNED_PARTS);
|
|
225
248
|
}
|
|
226
249
|
function queued(connection) {
|
|
250
|
+
return connection.rows('SELECT locator, ids FROM authored_queues').map((row) => ({
|
|
251
|
+
locator: text(row.locator),
|
|
252
|
+
ids: JSON.parse(text(row.ids)),
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
function heldWork(connection, locator) {
|
|
256
|
+
const room = heldRoom(connection, locator);
|
|
257
|
+
const pending = new Map(connection
|
|
258
|
+
.rows('SELECT id, batch, state FROM authored_pending WHERE locator = ?', [locator])
|
|
259
|
+
.map((row) => [
|
|
260
|
+
text(row.id),
|
|
261
|
+
{ id: text(row.id), batch: text(row.batch), state: text(row.state) },
|
|
262
|
+
]));
|
|
227
263
|
return {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
locator: text(row.locator),
|
|
236
|
-
id: text(row.id),
|
|
237
|
-
batch: text(row.batch),
|
|
238
|
-
state: text(row.state),
|
|
239
|
-
})),
|
|
264
|
+
room: room === null ? null : { ...room, overlaid: overlaid(connection, room.key) },
|
|
265
|
+
queue: heldOrder(connection, locator).map((id) => {
|
|
266
|
+
const held = pending.get(id);
|
|
267
|
+
if (held === undefined)
|
|
268
|
+
throw new Error(`Missing Pending Change ${locator}/${id}`);
|
|
269
|
+
return held;
|
|
270
|
+
}),
|
|
240
271
|
};
|
|
241
272
|
}
|
|
273
|
+
function status(connection) {
|
|
274
|
+
const [completed] = connection.rows("SELECT value FROM replica_facts WHERE name = 'lastCompleted'");
|
|
275
|
+
return {
|
|
276
|
+
queued: texts(connection.rows('SELECT locator FROM authored_queues'), 'locator'),
|
|
277
|
+
lastCompleted: completed === undefined ? null : text(completed.value),
|
|
278
|
+
changes: connection
|
|
279
|
+
.rows('SELECT p.locator, c.value AS path FROM authored_pending p, json_each(p.paths) c')
|
|
280
|
+
.map((row) => ({ locator: text(row.locator), path: text(row.path) })),
|
|
281
|
+
resets: connection
|
|
282
|
+
.rows(`SELECT locator, json_extract(state, '$.submission.reset') AS reset FROM authored_pending
|
|
283
|
+
WHERE json_extract(state, '$.submission.state') = 'reset'`)
|
|
284
|
+
.map((row) => ({ locator: text(row.locator), reset: text(row.reset) })),
|
|
285
|
+
returned: texts(connection.rows(`SELECT record FROM authored_room_drafts WHERE json_type(record, '$.returned') = 'object'`), 'record'),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function pendingOf(connection, locator, id) {
|
|
289
|
+
const [held] = connection.rows('SELECT state FROM authored_pending WHERE locator = ? AND id = ?', [locator, id]);
|
|
290
|
+
return {
|
|
291
|
+
state: held === undefined ? null : text(held.state),
|
|
292
|
+
room: connection.rows('SELECT 1 FROM replica_rooms WHERE locator = ?', [locator]).length > 0,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function roomDraftRecords(connection, locator, paths) {
|
|
296
|
+
if (locator === null) {
|
|
297
|
+
return texts(connection.rows('SELECT record FROM authored_room_drafts'), 'record');
|
|
298
|
+
}
|
|
299
|
+
if (paths === null) {
|
|
300
|
+
return texts(connection.rows('SELECT record FROM authored_room_drafts WHERE locator = ?', [locator]), 'record');
|
|
301
|
+
}
|
|
302
|
+
return texts(connection.rows('SELECT record FROM authored_room_drafts WHERE locator = ? AND path IN (SELECT value FROM json_each(?))', [locator, JSON.stringify(paths)]), 'record');
|
|
303
|
+
}
|
|
304
|
+
function chatDraftRecord(connection, conversation) {
|
|
305
|
+
const [held] = connection.rows('SELECT record FROM authored_chat_drafts WHERE conversation = ?', [
|
|
306
|
+
conversation,
|
|
307
|
+
]);
|
|
308
|
+
return held === undefined ? null : text(held.record);
|
|
309
|
+
}
|
|
242
310
|
function heldOrder(connection, locator) {
|
|
243
311
|
const [held] = connection.rows('SELECT ids FROM authored_queues WHERE locator = ?', [locator]);
|
|
244
312
|
return held === undefined ? [] : JSON.parse(text(held.ids));
|
|
245
313
|
}
|
|
246
|
-
function keptRows(connection, { locator, order, added, founded, roomDrafts, consumedRoomDrafts
|
|
247
|
-
for (const { id, amendment } of amendments ?? []) {
|
|
248
|
-
amended(connection, { kind: 'authored.amend', locator, id, amendment });
|
|
249
|
-
}
|
|
314
|
+
function keptRows(connection, { locator, order, added, founded, roomDrafts, consumedRoomDrafts }) {
|
|
250
315
|
for (const path of consumedRoomDrafts ?? []) {
|
|
251
316
|
connection.run('DELETE FROM authored_room_drafts WHERE locator = ? AND path = ?', [
|
|
252
317
|
locator,
|
|
@@ -273,19 +338,26 @@ function keptRows(connection, { locator, order, added, founded, roomDrafts, cons
|
|
|
273
338
|
connection.run('DELETE FROM authored_pending WHERE locator = ? AND id = ?', [locator, id]);
|
|
274
339
|
}
|
|
275
340
|
}
|
|
276
|
-
for (const { id, batch, state, files } of added ?? []) {
|
|
277
|
-
if (before.has(id)
|
|
341
|
+
for (const { id, batch, state, files, paths, moving } of added ?? []) {
|
|
342
|
+
if (before.has(id))
|
|
278
343
|
continue;
|
|
279
|
-
connection.run('INSERT OR REPLACE INTO authored_pending (locator, id, batch, state, files) VALUES (?, ?, ?, ?, ?)', [locator, id, batch, state, owned(files)]);
|
|
344
|
+
connection.run('INSERT OR REPLACE INTO authored_pending (locator, id, batch, state, files, paths, moving) VALUES (?, ?, ?, ?, ?, ?, ?)', [locator, id, batch, state, owned(files), JSON.stringify(paths), moving ? 1 : 0]);
|
|
280
345
|
}
|
|
281
|
-
for (const { id, batch, files } of founded ?? []) {
|
|
346
|
+
for (const { id, batch, files, paths, moving } of founded ?? []) {
|
|
282
347
|
const [held] = connection.rows('SELECT files FROM authored_pending WHERE locator = ? AND id = ?', [locator, id]);
|
|
283
348
|
if (held === undefined || !before.has(id))
|
|
284
349
|
continue;
|
|
285
|
-
connection.run('UPDATE authored_pending SET batch = ?, files = ? WHERE locator = ? AND id = ?', [
|
|
350
|
+
connection.run('UPDATE authored_pending SET batch = ?, files = ?, paths = ?, moving = ? WHERE locator = ? AND id = ?', [
|
|
351
|
+
batch,
|
|
352
|
+
owned([...JSON.parse(text(held.files)), ...files]),
|
|
353
|
+
JSON.stringify(paths),
|
|
354
|
+
moving ? 1 : 0,
|
|
355
|
+
locator,
|
|
356
|
+
id,
|
|
357
|
+
]);
|
|
286
358
|
}
|
|
287
359
|
}
|
|
288
|
-
async function kept(connection, { writes, files, whole
|
|
360
|
+
async function kept(connection, { writes, files, whole }) {
|
|
289
361
|
const refused = writes.find(({ locator }) => fenced(connection, locator));
|
|
290
362
|
if (refused !== undefined && whole)
|
|
291
363
|
return refused.locator;
|
|
@@ -294,8 +366,6 @@ async function kept(connection, { writes, files, whole, discards }) {
|
|
|
294
366
|
if (!fenced(connection, write.locator))
|
|
295
367
|
keptRows(connection, write);
|
|
296
368
|
}
|
|
297
|
-
for (const locator of discards ?? [])
|
|
298
|
-
roomWork(connection, locator);
|
|
299
369
|
unowned(connection);
|
|
300
370
|
return refused?.locator ?? null;
|
|
301
371
|
}
|
|
@@ -365,11 +435,15 @@ function fence(connection, locators) {
|
|
|
365
435
|
return fenceRooms(connection, locators);
|
|
366
436
|
}
|
|
367
437
|
function erased(connection, { locator, limit }) {
|
|
368
|
-
|
|
369
|
-
|
|
438
|
+
return erase(connection, locator, limit);
|
|
439
|
+
}
|
|
440
|
+
function unfenced(connection, locators) {
|
|
441
|
+
const erased = locators.filter((locator) => connection.rows('SELECT 1 FROM replica_erasing WHERE locator = ? LIMIT 1', [locator])
|
|
442
|
+
.length === 0);
|
|
443
|
+
for (const locator of erased) {
|
|
370
444
|
connection.run('DELETE FROM authored_fences WHERE locator = ?', [locator]);
|
|
371
445
|
}
|
|
372
|
-
return
|
|
446
|
+
return erased;
|
|
373
447
|
}
|
|
374
448
|
function claim(connection, holder) {
|
|
375
449
|
const held = fact(connection, 'holder');
|
|
@@ -432,9 +506,9 @@ function keptOpened(connection, { key, sha256, byteLength, parts }) {
|
|
|
432
506
|
if (fetched === null)
|
|
433
507
|
return false;
|
|
434
508
|
const [held] = connection.rows('SELECT count(*) AS parts, min(part) AS first, max(part) AS last, coalesce(sum(length(bytes)), 0) AS bytes FROM file_parts WHERE key = ?', [key]);
|
|
435
|
-
const whole = count(held
|
|
436
|
-
count(held
|
|
437
|
-
(parts === 0 || (count(held
|
|
509
|
+
const whole = count(held.parts) === parts &&
|
|
510
|
+
count(held.bytes) === byteLength &&
|
|
511
|
+
(parts === 0 || (count(held.first) === 0 && count(held.last) === parts - 1));
|
|
438
512
|
if (!whole) {
|
|
439
513
|
dropped(connection, key);
|
|
440
514
|
return false;
|
|
@@ -448,56 +522,82 @@ function keptOpened(connection, { key, sha256, byteLength, parts }) {
|
|
|
448
522
|
unowned(connection);
|
|
449
523
|
return true;
|
|
450
524
|
}
|
|
525
|
+
const UNSENT = [
|
|
526
|
+
['pending-change', 'authored_pending'],
|
|
527
|
+
['call', 'authored_calls'],
|
|
528
|
+
['room-draft', 'authored_room_drafts'],
|
|
529
|
+
['chat-draft', 'authored_chat_drafts'],
|
|
530
|
+
];
|
|
531
|
+
function unsent(connection) {
|
|
532
|
+
const [held] = connection.rows(`SELECT ${UNSENT.map(([kind, table]) => `(SELECT count(*) FROM ${table}) AS "${kind}"`).join(', ')}`);
|
|
533
|
+
return UNSENT.map(([kind]) => ({ kind, count: count(held[kind]) })).filter((work) => work.count > 0);
|
|
534
|
+
}
|
|
535
|
+
function cleanable(connection) {
|
|
536
|
+
const [held] = connection.rows(CLEANABLE_BYTES);
|
|
537
|
+
return count(held.bytes);
|
|
538
|
+
}
|
|
451
539
|
function cleaned(connection) {
|
|
452
540
|
connection.run('DELETE FROM opened_files');
|
|
453
|
-
const
|
|
541
|
+
const freed = cleanable(connection);
|
|
454
542
|
unowned(connection);
|
|
455
|
-
return
|
|
543
|
+
return freed;
|
|
544
|
+
}
|
|
545
|
+
function openedHeld(connection) {
|
|
546
|
+
return {
|
|
547
|
+
rooms: connection
|
|
548
|
+
.rows('SELECT locator, count(*) AS files, sum(byte_length) AS bytes FROM opened_files WHERE byte_length IS NOT NULL GROUP BY locator ORDER BY locator')
|
|
549
|
+
.map((row) => ({ room: text(row.locator), count: count(row.files), size: count(row.bytes) })),
|
|
550
|
+
cleanable: cleanable(connection),
|
|
551
|
+
};
|
|
456
552
|
}
|
|
457
553
|
async function committed(connection, { authored, rooms }) {
|
|
458
554
|
const refused = authored === undefined ? null : await kept(connection, authored);
|
|
459
555
|
if (refused !== null && authored?.whole === true) {
|
|
460
|
-
return { fenced: refused,
|
|
556
|
+
return { fenced: refused, changed: {}, indexed: {} };
|
|
461
557
|
}
|
|
462
558
|
return {
|
|
463
559
|
fenced: refused,
|
|
464
560
|
...commit(connection, rooms.filter(({ locator }) => !fenced(connection, locator))),
|
|
465
561
|
};
|
|
466
562
|
}
|
|
467
|
-
function receivedParts(connection, key, count) {
|
|
468
|
-
return connection
|
|
469
|
-
.rows('SELECT value FROM replica_received_parts WHERE key = ? AND part < ? ORDER BY part', [
|
|
470
|
-
key,
|
|
471
|
-
count,
|
|
472
|
-
])
|
|
473
|
-
.map((row) => JSON.parse(text(row.value)));
|
|
474
|
-
}
|
|
475
|
-
function receive(connection, { key, head, part }) {
|
|
476
|
-
connection.run('INSERT OR REPLACE INTO replica_received (key, head) VALUES (?, ?)', [key, head]);
|
|
477
|
-
if (part !== undefined) {
|
|
478
|
-
connection.run('INSERT OR REPLACE INTO replica_received_parts (key, part, value) VALUES (?, ?, ?)', [key, part.index, part.value]);
|
|
479
|
-
}
|
|
480
|
-
return null;
|
|
481
|
-
}
|
|
482
|
-
function unreceive(connection, keys) {
|
|
483
|
-
for (const key of keys) {
|
|
484
|
-
connection.run('DELETE FROM replica_received WHERE key = ?', [key]);
|
|
485
|
-
connection.run('DELETE FROM replica_received_parts WHERE key = ?', [key]);
|
|
486
|
-
}
|
|
487
|
-
return null;
|
|
488
|
-
}
|
|
489
563
|
export function answerRuntime(connection, request, spool) {
|
|
490
564
|
switch (request.kind) {
|
|
491
|
-
case 'authored.
|
|
492
|
-
return
|
|
565
|
+
case 'authored.status':
|
|
566
|
+
return status(connection);
|
|
567
|
+
case 'authored.moving':
|
|
568
|
+
return {
|
|
569
|
+
queues: queued(connection),
|
|
570
|
+
pending: connection
|
|
571
|
+
.rows('SELECT locator, id, batch, state FROM authored_pending WHERE moving = 1 ORDER BY locator')
|
|
572
|
+
.map((row) => ({
|
|
573
|
+
locator: text(row.locator),
|
|
574
|
+
id: text(row.id),
|
|
575
|
+
batch: text(row.batch),
|
|
576
|
+
state: text(row.state),
|
|
577
|
+
})),
|
|
578
|
+
};
|
|
579
|
+
case 'authored.pending':
|
|
580
|
+
return pendingOf(connection, request.locator, request.id);
|
|
581
|
+
case 'authored.batch': {
|
|
582
|
+
const [held] = connection.rows('SELECT batch FROM authored_pending WHERE locator = ? AND id = ?', [request.locator, request.id]);
|
|
583
|
+
return held === undefined ? null : text(held.batch);
|
|
584
|
+
}
|
|
585
|
+
case 'authored.order':
|
|
586
|
+
return heldOrder(connection, request.locator);
|
|
587
|
+
case 'authored.queued':
|
|
588
|
+
return texts(connection.rows('SELECT locator FROM authored_queues'), 'locator');
|
|
493
589
|
case 'authored.roomDrafts':
|
|
494
|
-
return
|
|
590
|
+
return roomDraftRecords(connection, request.locator, request.paths);
|
|
591
|
+
case 'authored.chatDraft.read':
|
|
592
|
+
return chatDraftRecord(connection, request.conversation);
|
|
495
593
|
case 'authored.chatDrafts':
|
|
496
594
|
return texts(connection.rows('SELECT record FROM authored_chat_drafts'), 'record');
|
|
497
595
|
case 'authored.calls':
|
|
498
596
|
return texts(connection.rows('SELECT record FROM authored_calls'), 'record');
|
|
499
597
|
case 'authored.fences':
|
|
500
598
|
return texts(connection.rows('SELECT locator FROM authored_fences'), 'locator');
|
|
599
|
+
case 'authored.unsent':
|
|
600
|
+
return unsent(connection);
|
|
501
601
|
case 'authored.fact':
|
|
502
602
|
return fact(connection, request.name);
|
|
503
603
|
case 'authored.file':
|
|
@@ -518,37 +618,43 @@ export function answerRuntime(connection, request, spool) {
|
|
|
518
618
|
return end(connection, request.holder);
|
|
519
619
|
case 'replica.open':
|
|
520
620
|
return opened(connection);
|
|
621
|
+
case 'replica.rooms':
|
|
622
|
+
return heldRooms(connection, request.locators);
|
|
623
|
+
case 'replica.room':
|
|
624
|
+
return heldWork(connection, request.locator);
|
|
625
|
+
case 'replica.covering':
|
|
626
|
+
return {
|
|
627
|
+
rooms: covering(connection),
|
|
628
|
+
queues: queued(connection),
|
|
629
|
+
};
|
|
630
|
+
case 'replica.offline':
|
|
631
|
+
return offlineMode(connection, request.locator);
|
|
632
|
+
case 'replica.held':
|
|
633
|
+
return { held: heldLocators(connection), staged: stagedLocators(connection) };
|
|
634
|
+
case 'replica.demote':
|
|
635
|
+
return demoted(connection);
|
|
636
|
+
case 'replica.facts':
|
|
637
|
+
return facts(connection);
|
|
638
|
+
case 'replica.presentation':
|
|
639
|
+
return presentation(connection, request.app);
|
|
521
640
|
case 'replica.query':
|
|
522
641
|
return answerQuery(connection, request.plan, request.rooms, request.budget);
|
|
642
|
+
case 'replica.tallies':
|
|
643
|
+
return roomTallies(connection, request.totals, request.rooms, request.since);
|
|
523
644
|
case 'replica.entries':
|
|
524
645
|
return entries(connection, request.key, request.view, request.paths);
|
|
525
646
|
case 'replica.typed':
|
|
526
647
|
return typed(connection, request.key, request.view, request.paths);
|
|
527
648
|
case 'replica.referrers':
|
|
528
|
-
return referrers(connection, request.key, request.view, request.targets
|
|
529
|
-
case 'replica.walk':
|
|
530
|
-
return walk(connection, request.key, request.view, request.after, request.bytes);
|
|
531
|
-
case 'replica.files':
|
|
532
|
-
return files(connection, request.key, request.view, request.after, request.limit);
|
|
649
|
+
return referrers(connection, request.key, request.view, request.targets);
|
|
533
650
|
case 'replica.folders':
|
|
534
|
-
return folders(connection, request.key, request.
|
|
651
|
+
return folders(connection, request.key, request.paths);
|
|
535
652
|
case 'replica.typedWithin':
|
|
536
653
|
return typedWithin(connection, request.key, request.view, request.roots, request.within);
|
|
537
|
-
case 'replica.counts':
|
|
538
|
-
return counts(connection, request.rooms);
|
|
539
|
-
case 'replica.search': {
|
|
540
|
-
const { kind: _kind, ...ask } = request;
|
|
541
|
-
return searched(connection, ask);
|
|
542
|
-
}
|
|
543
|
-
case 'replica.received':
|
|
544
|
-
return connection.rows('SELECT key, head FROM replica_received').map((row) => ({
|
|
545
|
-
key: text(row.key),
|
|
546
|
-
head: JSON.parse(text(row.head)),
|
|
547
|
-
}));
|
|
548
|
-
case 'replica.receivedParts':
|
|
549
|
-
return receivedParts(connection, request.key, request.count);
|
|
550
654
|
case 'replica.stage':
|
|
551
655
|
return fenced(connection, request.locator) ? null : stage(connection, request);
|
|
656
|
+
case 'replica.resume':
|
|
657
|
+
return fenced(connection, request.locator) ? null : resume(connection, request);
|
|
552
658
|
case 'replica.refresh':
|
|
553
659
|
return refreshing(connection, request);
|
|
554
660
|
case 'replica.unrefresh':
|
|
@@ -561,6 +667,8 @@ export function answerRuntime(connection, request, spool) {
|
|
|
561
667
|
return erased(connection, request);
|
|
562
668
|
case 'replica.abandon':
|
|
563
669
|
return abandon(connection, request.locator);
|
|
670
|
+
case 'replica.unfence':
|
|
671
|
+
return unfenced(connection, request.locators);
|
|
564
672
|
case 'replica.release':
|
|
565
673
|
return release(connection, request.key);
|
|
566
674
|
case 'replica.rederive':
|
|
@@ -577,10 +685,6 @@ export function answerRuntime(connection, request, spool) {
|
|
|
577
685
|
request.value,
|
|
578
686
|
]);
|
|
579
687
|
return null;
|
|
580
|
-
case 'replica.receive':
|
|
581
|
-
return receive(connection, request);
|
|
582
|
-
case 'replica.unreceive':
|
|
583
|
-
return unreceive(connection, request.keys);
|
|
584
688
|
case 'opened.find':
|
|
585
689
|
return openedFile(connection, request);
|
|
586
690
|
case 'opened.begin':
|
|
@@ -593,20 +697,26 @@ export function answerRuntime(connection, request, spool) {
|
|
|
593
697
|
return dropped(connection, request.key);
|
|
594
698
|
case 'opened.clean':
|
|
595
699
|
return cleaned(connection);
|
|
700
|
+
case 'opened.held':
|
|
701
|
+
return openedHeld(connection);
|
|
596
702
|
case 'file.part':
|
|
597
703
|
return filePart(connection, request.key, request.part);
|
|
598
704
|
case 'conversation.held':
|
|
599
|
-
return heldConversations(connection);
|
|
705
|
+
return heldConversations(connection, request.conversations);
|
|
600
706
|
case 'conversation.keep': {
|
|
601
707
|
const { kind: _kind, ...write } = request;
|
|
602
708
|
return keptMessages(connection, write);
|
|
603
709
|
}
|
|
604
710
|
case 'conversation.window':
|
|
605
|
-
return messageWindow(connection, request.conversation, request.limit, request.before);
|
|
711
|
+
return messageWindow(connection, request.conversation, request.limit, request.before, request.phrase);
|
|
606
712
|
case 'conversation.count':
|
|
607
|
-
return messageCount(connection, request.conversation);
|
|
713
|
+
return messageCount(connection, request.conversation, request.phrase);
|
|
608
714
|
case 'conversation.turn':
|
|
609
715
|
return turnArrived(connection, request.conversation, request.turn);
|
|
716
|
+
case 'conversation.rows':
|
|
717
|
+
return conversationRows(connection, request.conversations);
|
|
718
|
+
case 'conversation.tallies':
|
|
719
|
+
return conversationTallies(connection, request.conversations, request.since);
|
|
610
720
|
case 'conversation.drop':
|
|
611
721
|
chatDraft(connection, {
|
|
612
722
|
kind: 'authored.chatDraft',
|
|
@@ -617,5 +727,11 @@ export function answerRuntime(connection, request, spool) {
|
|
|
617
727
|
return null;
|
|
618
728
|
case 'space.probe':
|
|
619
729
|
return spool.probe(PROBE_BYTES).then(() => null);
|
|
730
|
+
case 'read.stored':
|
|
731
|
+
return storedRead(connection, request);
|
|
732
|
+
case 'read.keep':
|
|
733
|
+
return keptRead(connection, request, request.answer);
|
|
734
|
+
case 'read.builds':
|
|
735
|
+
return readsOfOtherBuildsForgotten(connection, request.build);
|
|
620
736
|
}
|
|
621
737
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type QueryRoom } from './compile.js';
|
|
2
|
+
import type { GroupTotal, Plan } from './query.js';
|
|
3
|
+
import type { Connection } from './tables.js';
|
|
4
|
+
export type RoomTally = {
|
|
5
|
+
readonly key: number;
|
|
6
|
+
readonly documents: GroupTotal;
|
|
7
|
+
readonly files: GroupTotal;
|
|
8
|
+
readonly documentTimes: readonly (readonly [string | null, string | null])[];
|
|
9
|
+
readonly chatTimes: readonly string[];
|
|
10
|
+
readonly messageTimes: readonly string[];
|
|
11
|
+
};
|
|
12
|
+
export type ConversationTally = {
|
|
13
|
+
readonly conversation: string;
|
|
14
|
+
readonly said: readonly string[];
|
|
15
|
+
};
|
|
16
|
+
export declare function roomTallies(connection: Connection, totals: Plan, rooms: readonly QueryRoom[], since: string): RoomTally[];
|
|
17
|
+
export declare function conversationTallies(connection: Connection, conversations: readonly string[] | null, since: string): ConversationTally[];
|
|
18
|
+
//# sourceMappingURL=tallies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tallies.d.ts","sourceRoot":"","sources":["../src/tallies.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE5E,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAI1D,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC;IAC7E,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAmHpG,wBAAgB,WAAW,CACzB,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,KAAK,EAAE,MAAM,GACZ,SAAS,EAAE,CAwBb;AA0BD,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,EACvC,KAAK,EAAE,MAAM,GACZ,iBAAiB,EAAE,CAerB"}
|
package/dist/tallies.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { instantKey, sql } from '@agentshouse/mdmodel';
|
|
2
|
+
import { CHAT_MESSAGE_TYPE, CHAT_TYPE } from './chat-types.js';
|
|
3
|
+
import { answerQuery, VISIBLE, within } from './compile.js';
|
|
4
|
+
import { HOUSE_DIRECTORY } from './figures.js';
|
|
5
|
+
const NONE = { count: 0, size: 0 };
|
|
6
|
+
const { all, fragment, joined } = sql;
|
|
7
|
+
function instant(value) {
|
|
8
|
+
return typeof value === 'string' ? value : null;
|
|
9
|
+
}
|
|
10
|
+
function held(alias, keys) {
|
|
11
|
+
const reserved = within(alias, HOUSE_DIRECTORY);
|
|
12
|
+
return all([
|
|
13
|
+
fragment(`${alias}.key IN (SELECT value FROM json_each(?))`, [JSON.stringify(keys)]),
|
|
14
|
+
fragment(VISIBLE(alias)),
|
|
15
|
+
fragment(`NOT ${reserved.sql}`, reserved.bind),
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
function valued(alias, document, field) {
|
|
19
|
+
return joined([
|
|
20
|
+
fragment(`${alias}.doc = ${document}.id AND `),
|
|
21
|
+
sql.grouped(sql.placed(alias, field, 'exact')),
|
|
22
|
+
fragment(` AND ${alias}.item = -1`),
|
|
23
|
+
], '');
|
|
24
|
+
}
|
|
25
|
+
function inboxed(card) {
|
|
26
|
+
return joined([
|
|
27
|
+
fragment('EXISTS (SELECT 1 FROM replica_values i WHERE '),
|
|
28
|
+
valued('i', card, '/inbox'),
|
|
29
|
+
fragment(" AND i.kind = 'string')"),
|
|
30
|
+
], '');
|
|
31
|
+
}
|
|
32
|
+
function rowsOf(connection, query) {
|
|
33
|
+
return connection.rows(query.sql, query.bind);
|
|
34
|
+
}
|
|
35
|
+
function documentTimes(connection, keys, since) {
|
|
36
|
+
return rowsOf(connection, joined([
|
|
37
|
+
fragment('SELECT d.key AS key, d.created_instant AS created, d.changed_instant AS changed FROM replica_entries d WHERE '),
|
|
38
|
+
held('d', keys),
|
|
39
|
+
fragment(" AND d.binary IS NULL AND COALESCE(d.type, '') NOT IN (?, ?) AND (d.created_instant >= ? OR d.changed_instant >= ?)", [CHAT_TYPE, CHAT_MESSAGE_TYPE, since, since]),
|
|
40
|
+
], ''));
|
|
41
|
+
}
|
|
42
|
+
function chatTimes(connection, keys, since) {
|
|
43
|
+
return rowsOf(connection, joined([
|
|
44
|
+
fragment('SELECT d.key AS key, d.created_instant AS at FROM replica_entries d WHERE '),
|
|
45
|
+
held('d', keys),
|
|
46
|
+
fragment(' AND d.type = ? AND d.created_instant >= ? AND ', [CHAT_TYPE, since]),
|
|
47
|
+
inboxed('d'),
|
|
48
|
+
], ''));
|
|
49
|
+
}
|
|
50
|
+
function messageTimes(connection, keys, since) {
|
|
51
|
+
return rowsOf(connection, joined([
|
|
52
|
+
fragment('SELECT m.key AS key, s.instant AS at FROM replica_entries m JOIN replica_values s ON '),
|
|
53
|
+
valued('s', 'm', '/sent_at'),
|
|
54
|
+
fragment(' AND s.instant >= ? JOIN replica_values r ON ', [since]),
|
|
55
|
+
valued('r', 'm', '/direction'),
|
|
56
|
+
fragment(" AND r.kind = 'string' AND r.value = 'in' WHERE "),
|
|
57
|
+
held('m', keys),
|
|
58
|
+
fragment(` AND m.type = ? AND EXISTS (SELECT 1 FROM replica_entries c WHERE c.key = m.key AND c.type = ? AND ${VISIBLE('c')} AND c.folder = m.folder AND `, [CHAT_MESSAGE_TYPE, CHAT_TYPE]),
|
|
59
|
+
inboxed('c'),
|
|
60
|
+
fragment(')'),
|
|
61
|
+
], ''));
|
|
62
|
+
}
|
|
63
|
+
function byKey(rows, read) {
|
|
64
|
+
const kept = new Map();
|
|
65
|
+
for (const row of rows) {
|
|
66
|
+
const key = Number(row.key);
|
|
67
|
+
const list = kept.get(key) ?? [];
|
|
68
|
+
list.push(read(row));
|
|
69
|
+
kept.set(key, list);
|
|
70
|
+
}
|
|
71
|
+
return kept;
|
|
72
|
+
}
|
|
73
|
+
export function roomTallies(connection, totals, rooms, since) {
|
|
74
|
+
const keys = rooms.map(({ key }) => key);
|
|
75
|
+
const from = instantKey(since);
|
|
76
|
+
const answered = answerQuery(connection, totals, rooms);
|
|
77
|
+
const summed = new Map(('groups' in answered ? answered.groups : []).map((group) => [String(group.key[0]), group]));
|
|
78
|
+
const documents = byKey(documentTimes(connection, keys, from), (row) => [instant(row.created), instant(row.changed)]);
|
|
79
|
+
const chats = byKey(chatTimes(connection, keys, from), (row) => instant(row.at));
|
|
80
|
+
const messages = byKey(messageTimes(connection, keys, from), (row) => instant(row.at));
|
|
81
|
+
return rooms.map(({ locator, key }) => {
|
|
82
|
+
const total = summed.get(locator);
|
|
83
|
+
return {
|
|
84
|
+
key,
|
|
85
|
+
documents: total?.documents ?? NONE,
|
|
86
|
+
files: total?.files ?? NONE,
|
|
87
|
+
documentTimes: documents.get(key) ?? [],
|
|
88
|
+
chatTimes: chats.get(key) ?? [],
|
|
89
|
+
messageTimes: messages.get(key) ?? [],
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const ACCEPTED = "message ->> '$.accepted_at'";
|
|
94
|
+
const NEWER = 'ORDER BY n.position DESC, n.identity DESC LIMIT 1';
|
|
95
|
+
const SAID = `WITH RECURSIVE
|
|
96
|
+
named(conversation) AS (SELECT value FROM json_each(?)),
|
|
97
|
+
walk(conversation, position, identity, at, role) AS (
|
|
98
|
+
SELECT m.conversation, m.position, m.identity, m.${ACCEPTED}, m.message ->> '$.role'
|
|
99
|
+
FROM named JOIN conversation_messages m ON m.id = (
|
|
100
|
+
SELECT n.id FROM conversation_messages n WHERE n.conversation = named.conversation ${NEWER}
|
|
101
|
+
)
|
|
102
|
+
UNION ALL
|
|
103
|
+
SELECT m.conversation, m.position, m.identity, m.${ACCEPTED}, m.message ->> '$.role'
|
|
104
|
+
FROM walk JOIN conversation_messages m ON m.id = (
|
|
105
|
+
SELECT n.id FROM conversation_messages n WHERE n.conversation = walk.conversation
|
|
106
|
+
AND (n.position < walk.position OR (n.position = walk.position AND n.identity < walk.identity))
|
|
107
|
+
${NEWER}
|
|
108
|
+
)
|
|
109
|
+
WHERE julianday(walk.at) >= julianday(?)
|
|
110
|
+
)
|
|
111
|
+
SELECT walk.conversation AS conversation, walk.at AS at
|
|
112
|
+
FROM walk
|
|
113
|
+
WHERE walk.role IN ('user', 'assistant') AND julianday(walk.at) >= julianday(?)`;
|
|
114
|
+
export function conversationTallies(connection, conversations, since) {
|
|
115
|
+
const named = conversations ??
|
|
116
|
+
connection
|
|
117
|
+
.rows('SELECT DISTINCT conversation FROM conversation_messages')
|
|
118
|
+
.map((row) => String(row.conversation));
|
|
119
|
+
const from = instantKey(since);
|
|
120
|
+
const said = new Map();
|
|
121
|
+
for (const row of connection.rows(SAID, [JSON.stringify(named), since, since])) {
|
|
122
|
+
const at = instantKey(row.at);
|
|
123
|
+
if (at === null || at < from)
|
|
124
|
+
continue;
|
|
125
|
+
const conversation = String(row.conversation);
|
|
126
|
+
said.set(conversation, [...(said.get(conversation) ?? []), at]);
|
|
127
|
+
}
|
|
128
|
+
return named.map((conversation) => ({ conversation, said: said.get(conversation) ?? [] }));
|
|
129
|
+
}
|