@agentshouse/mdruntime 0.1.0-c9b1e59e5baeb → 0.1.0-ca10e63188fc5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/README.md +18 -15
  2. package/dist/adapter.d.ts +58 -32
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/attached-model.d.ts +5 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +21 -4
  7. package/dist/binary.d.ts +0 -5
  8. package/dist/binary.d.ts.map +1 -1
  9. package/dist/binary.js +1 -1
  10. package/dist/bootstrap.d.ts +30 -8
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +187 -85
  13. package/dist/chain.d.ts +11 -0
  14. package/dist/chain.d.ts.map +1 -0
  15. package/dist/chain.js +64 -0
  16. package/dist/change-set.d.ts +6 -16
  17. package/dist/change-set.d.ts.map +1 -1
  18. package/dist/change-set.js +11 -94
  19. package/dist/change.d.ts +31 -1
  20. package/dist/change.d.ts.map +1 -1
  21. package/dist/change.js +10 -1
  22. package/dist/client.d.ts +9 -5
  23. package/dist/client.d.ts.map +1 -1
  24. package/dist/client.js +80 -6
  25. package/dist/collection.d.ts +11 -20
  26. package/dist/collection.d.ts.map +1 -1
  27. package/dist/collection.js +53 -354
  28. package/dist/compile.d.ts +16 -0
  29. package/dist/compile.d.ts.map +1 -0
  30. package/dist/compile.js +765 -0
  31. package/dist/connection.d.ts +17 -9
  32. package/dist/connection.d.ts.map +1 -1
  33. package/dist/connection.js +2431 -953
  34. package/dist/conversation.d.ts +4 -3
  35. package/dist/conversation.d.ts.map +1 -1
  36. package/dist/conversation.js +81 -68
  37. package/dist/digest.d.ts +7 -0
  38. package/dist/digest.d.ts.map +1 -0
  39. package/dist/digest.js +113 -0
  40. package/dist/durability.d.ts +3 -5
  41. package/dist/durability.d.ts.map +1 -1
  42. package/dist/durability.js +5 -0
  43. package/dist/entry.d.ts +3 -1
  44. package/dist/entry.d.ts.map +1 -1
  45. package/dist/entry.js +18 -24
  46. package/dist/file.d.ts +2 -19
  47. package/dist/file.d.ts.map +1 -1
  48. package/dist/file.js +7 -122
  49. package/dist/fulltext.d.ts +27 -0
  50. package/dist/fulltext.d.ts.map +1 -0
  51. package/dist/fulltext.js +368 -0
  52. package/dist/host.d.ts +4 -4
  53. package/dist/host.d.ts.map +1 -1
  54. package/dist/host.js +45 -15
  55. package/dist/identity.d.ts +0 -1
  56. package/dist/identity.d.ts.map +1 -1
  57. package/dist/identity.js +0 -3
  58. package/dist/index.d.ts +11 -9
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +4 -1
  61. package/dist/live.d.ts +22 -0
  62. package/dist/live.d.ts.map +1 -0
  63. package/dist/live.js +124 -0
  64. package/dist/media.d.ts +8 -0
  65. package/dist/media.d.ts.map +1 -0
  66. package/dist/media.js +205 -0
  67. package/dist/memory.d.ts +2 -1
  68. package/dist/memory.d.ts.map +1 -1
  69. package/dist/memory.js +63 -22
  70. package/dist/messages.d.ts +28 -0
  71. package/dist/messages.d.ts.map +1 -0
  72. package/dist/messages.js +90 -0
  73. package/dist/model.d.ts +6 -0
  74. package/dist/model.d.ts.map +1 -1
  75. package/dist/model.js +7 -1
  76. package/dist/name.d.ts +4 -0
  77. package/dist/name.d.ts.map +1 -0
  78. package/dist/name.js +122 -0
  79. package/dist/observation.d.ts +13 -0
  80. package/dist/observation.d.ts.map +1 -1
  81. package/dist/observation.js +84 -0
  82. package/dist/opened.d.ts +22 -0
  83. package/dist/opened.d.ts.map +1 -0
  84. package/dist/opened.js +107 -0
  85. package/dist/outcome.d.ts +40 -5
  86. package/dist/outcome.d.ts.map +1 -1
  87. package/dist/outcome.js +38 -2
  88. package/dist/overlay.d.ts +1 -4
  89. package/dist/overlay.d.ts.map +1 -1
  90. package/dist/overlay.js +22 -148
  91. package/dist/query.d.ts +11 -1
  92. package/dist/query.d.ts.map +1 -1
  93. package/dist/query.js +13 -1
  94. package/dist/reach.d.ts +11 -3
  95. package/dist/reach.d.ts.map +1 -1
  96. package/dist/reach.js +198 -69
  97. package/dist/readiness.d.ts +20 -9
  98. package/dist/readiness.d.ts.map +1 -1
  99. package/dist/readiness.js +6 -6
  100. package/dist/reads.d.ts.map +1 -1
  101. package/dist/reads.js +4 -2
  102. package/dist/recovery.d.ts +2 -2
  103. package/dist/recovery.d.ts.map +1 -1
  104. package/dist/recovery.js +8 -7
  105. package/dist/refresh.d.ts +15 -14
  106. package/dist/refresh.d.ts.map +1 -1
  107. package/dist/refresh.js +113 -75
  108. package/dist/replica.d.ts +56 -39
  109. package/dist/replica.d.ts.map +1 -1
  110. package/dist/replica.js +278 -197
  111. package/dist/room-draft.d.ts +4 -1
  112. package/dist/room-draft.d.ts.map +1 -1
  113. package/dist/room-draft.js +54 -13
  114. package/dist/rows.d.ts +38 -31
  115. package/dist/rows.d.ts.map +1 -1
  116. package/dist/rows.js +173 -101
  117. package/dist/save.d.ts +49 -14
  118. package/dist/save.d.ts.map +1 -1
  119. package/dist/save.js +352 -98
  120. package/dist/search.d.ts +11 -43
  121. package/dist/search.d.ts.map +1 -1
  122. package/dist/search.js +0 -213
  123. package/dist/shared.d.ts +4 -3
  124. package/dist/shared.d.ts.map +1 -1
  125. package/dist/shared.js +67 -34
  126. package/dist/store.d.ts +92 -96
  127. package/dist/store.d.ts.map +1 -1
  128. package/dist/store.js +329 -720
  129. package/dist/stored.d.ts +152 -0
  130. package/dist/stored.d.ts.map +1 -0
  131. package/dist/stored.js +571 -0
  132. package/dist/tables.d.ts +354 -0
  133. package/dist/tables.d.ts.map +1 -0
  134. package/dist/tables.js +624 -0
  135. package/dist/turn.d.ts +1 -1
  136. package/dist/turn.d.ts.map +1 -1
  137. package/dist/turn.js +31 -20
  138. package/dist/validation.d.ts +30 -0
  139. package/dist/validation.d.ts.map +1 -0
  140. package/dist/validation.js +162 -0
  141. package/dist/windows.d.ts +2 -6
  142. package/dist/windows.d.ts.map +1 -1
  143. package/dist/windows.js +30 -34
  144. package/dist/wire.d.ts +17 -1
  145. package/dist/wire.d.ts.map +1 -1
  146. package/dist/wire.js +5 -1
  147. package/dist/words.d.ts +19 -0
  148. package/dist/words.d.ts.map +1 -0
  149. package/dist/words.js +150 -0
  150. package/package.json +18 -19
  151. package/AGENTS.md +0 -299
  152. package/dist/chat/acts.d.ts +0 -33
  153. package/dist/chat/acts.d.ts.map +0 -1
  154. package/dist/chat/acts.js +0 -36
  155. package/dist/chat/context.d.ts +0 -3
  156. package/dist/chat/context.d.ts.map +0 -1
  157. package/dist/chat/context.js +0 -10
  158. package/dist/chat/earlier.d.ts +0 -10
  159. package/dist/chat/earlier.d.ts.map +0 -1
  160. package/dist/chat/earlier.js +0 -54
  161. package/dist/chat/input.d.ts +0 -9
  162. package/dist/chat/input.d.ts.map +0 -1
  163. package/dist/chat/input.js +0 -99
  164. package/dist/chat/kit.d.ts +0 -61
  165. package/dist/chat/kit.d.ts.map +0 -1
  166. package/dist/chat/kit.js +0 -123
  167. package/dist/chat/lasting.d.ts +0 -6
  168. package/dist/chat/lasting.d.ts.map +0 -1
  169. package/dist/chat/lasting.js +0 -19
  170. package/dist/chat/list.d.ts +0 -28
  171. package/dist/chat/list.d.ts.map +0 -1
  172. package/dist/chat/list.js +0 -99
  173. package/dist/chat/markdown.d.ts +0 -21
  174. package/dist/chat/markdown.d.ts.map +0 -1
  175. package/dist/chat/markdown.js +0 -246
  176. package/dist/chat/message.d.ts +0 -6
  177. package/dist/chat/message.d.ts.map +0 -1
  178. package/dist/chat/message.js +0 -199
  179. package/dist/chat/messages.d.ts +0 -22
  180. package/dist/chat/messages.d.ts.map +0 -1
  181. package/dist/chat/messages.js +0 -175
  182. package/dist/chat/name.d.ts +0 -6
  183. package/dist/chat/name.d.ts.map +0 -1
  184. package/dist/chat/name.js +0 -37
  185. package/dist/chat/opened.d.ts +0 -11
  186. package/dist/chat/opened.d.ts.map +0 -1
  187. package/dist/chat/opened.js +0 -17
  188. package/dist/chat/overlay.d.ts +0 -32
  189. package/dist/chat/overlay.d.ts.map +0 -1
  190. package/dist/chat/overlay.js +0 -107
  191. package/dist/chat/parts.d.ts +0 -57
  192. package/dist/chat/parts.d.ts.map +0 -1
  193. package/dist/chat/parts.js +0 -119
  194. package/dist/chat/pieces.d.ts +0 -62
  195. package/dist/chat/pieces.d.ts.map +0 -1
  196. package/dist/chat/pieces.js +0 -1110
  197. package/dist/chat/process.d.ts +0 -20
  198. package/dist/chat/process.d.ts.map +0 -1
  199. package/dist/chat/process.js +0 -32
  200. package/dist/chat/provider.d.ts +0 -64
  201. package/dist/chat/provider.d.ts.map +0 -1
  202. package/dist/chat/provider.js +0 -637
  203. package/dist/chat/question.d.ts +0 -9
  204. package/dist/chat/question.d.ts.map +0 -1
  205. package/dist/chat/question.js +0 -69
  206. package/dist/chat/questions.d.ts +0 -31
  207. package/dist/chat/questions.d.ts.map +0 -1
  208. package/dist/chat/questions.js +0 -111
  209. package/dist/chat/read.d.ts +0 -5
  210. package/dist/chat/read.d.ts.map +0 -1
  211. package/dist/chat/read.js +0 -13
  212. package/dist/chat/ready.d.ts +0 -34
  213. package/dist/chat/ready.d.ts.map +0 -1
  214. package/dist/chat/ready.js +0 -91
  215. package/dist/chat/steady.d.ts +0 -3
  216. package/dist/chat/steady.d.ts.map +0 -1
  217. package/dist/chat/steady.js +0 -26
  218. package/dist/chat/style.d.ts +0 -4
  219. package/dist/chat/style.d.ts.map +0 -1
  220. package/dist/chat/style.js +0 -302
  221. package/dist/chat.d.ts +0 -14
  222. package/dist/chat.d.ts.map +0 -1
  223. package/dist/chat.js +0 -8
  224. package/dist/read-side.d.ts +0 -27
  225. package/dist/read-side.d.ts.map +0 -1
  226. package/dist/read-side.js +0 -826
package/dist/stored.js ADDED
@@ -0,0 +1,571 @@
1
+ import { composedOf } from './collection.js';
2
+ import { indexDocument, unindexAll, unindexDocuments } from './fulltext.js';
3
+ import { described, derived } from './rows.js';
4
+ export const REPLICA_TABLES = [
5
+ 'CREATE TABLE replica_keys (key INTEGER PRIMARY KEY AUTOINCREMENT, locator TEXT NOT NULL, transfer TEXT NOT NULL, fingerprint TEXT NOT NULL, rederiving INTEGER, searching INTEGER)',
6
+ 'CREATE TABLE replica_rooms (locator TEXT PRIMARY KEY, key INTEGER NOT NULL, record TEXT NOT NULL) WITHOUT ROWID',
7
+ 'CREATE TABLE replica_transfers (locator TEXT PRIMARY KEY, key INTEGER NOT NULL, record TEXT NOT NULL) WITHOUT ROWID',
8
+ 'CREATE TABLE replica_transfer_parts (locator TEXT NOT NULL, token TEXT NOT NULL, part BLOB NOT NULL)',
9
+ 'CREATE INDEX replica_transfer_parts_locator ON replica_transfer_parts (locator)',
10
+ 'CREATE TABLE replica_entries (id INTEGER PRIMARY KEY, key INTEGER NOT NULL, layer INTEGER NOT NULL, path TEXT NOT NULL, visible INTEGER NOT NULL, present INTEGER NOT NULL, queried INTEGER NOT NULL, binary TEXT, revision TEXT, file_id TEXT, change TEXT, written TEXT, type TEXT, declared TEXT, folder TEXT NOT NULL, fields TEXT, content TEXT)',
11
+ 'CREATE UNIQUE INDEX replica_entries_path ON replica_entries (key, layer, path)',
12
+ 'CREATE INDEX replica_entries_visible ON replica_entries (key, visible, path)',
13
+ 'CREATE INDEX replica_entries_folder ON replica_entries (key, folder, path)',
14
+ 'CREATE TABLE replica_values (doc INTEGER NOT NULL, key INTEGER NOT NULL, keys TEXT NOT NULL, places TEXT NOT NULL, item INTEGER NOT NULL, kind TEXT NOT NULL, value, size INTEGER, PRIMARY KEY (doc, keys, places, item)) WITHOUT ROWID',
15
+ 'CREATE INDEX replica_values_lookup ON replica_values (key, keys, kind, value)',
16
+ 'CREATE TABLE replica_links (doc INTEGER NOT NULL, key INTEGER NOT NULL, kind TEXT NOT NULL, keys TEXT NOT NULL, places TEXT NOT NULL, target TEXT NOT NULL, field TEXT NOT NULL, PRIMARY KEY (doc, kind, keys, places, target)) WITHOUT ROWID',
17
+ 'CREATE INDEX replica_links_target ON replica_links (key, target, kind, keys)',
18
+ 'CREATE TABLE replica_folders (key INTEGER NOT NULL, layer INTEGER NOT NULL, path TEXT NOT NULL, present INTEGER NOT NULL, PRIMARY KEY (key, layer, path)) WITHOUT ROWID',
19
+ 'CREATE TABLE replica_erasing (key INTEGER PRIMARY KEY, locator TEXT NOT NULL)',
20
+ 'CREATE TABLE replica_received (key TEXT PRIMARY KEY, head TEXT NOT NULL) WITHOUT ROWID',
21
+ 'CREATE TABLE replica_received_parts (key TEXT NOT NULL, part INTEGER NOT NULL, value TEXT NOT NULL, PRIMARY KEY (key, part)) WITHOUT ROWID',
22
+ 'CREATE TABLE replica_facts (name TEXT PRIMARY KEY, value TEXT NOT NULL) WITHOUT ROWID',
23
+ 'CREATE TABLE replica_presentation (app TEXT PRIMARY KEY, value TEXT NOT NULL) WITHOUT ROWID',
24
+ ];
25
+ const CONFIRMED = 0;
26
+ const OVERLAY = 1;
27
+ const REFRESHED = 2;
28
+ const DERIVED_ROWS = 64;
29
+ const ENTRY_WEIGHT = 256;
30
+ const ABSENT = {
31
+ type: null,
32
+ declared: null,
33
+ queried: false,
34
+ folder: '',
35
+ fields: null,
36
+ values: [],
37
+ links: [],
38
+ };
39
+ function text(value) {
40
+ return typeof value === 'string' ? value : null;
41
+ }
42
+ function number(value) {
43
+ return typeof value === 'bigint' ? Number(value) : value;
44
+ }
45
+ function json(value) {
46
+ return typeof value === 'string' ? JSON.parse(value) : null;
47
+ }
48
+ function flag(value) {
49
+ return value ? 1 : 0;
50
+ }
51
+ function paths(list) {
52
+ return JSON.stringify(list);
53
+ }
54
+ function dropDerived(connection, doc) {
55
+ connection.run('DELETE FROM replica_values WHERE doc = ?', [doc]);
56
+ connection.run('DELETE FROM replica_links WHERE doc = ?', [doc]);
57
+ }
58
+ function writeDerived(connection, doc, key, made) {
59
+ for (const value of made.values) {
60
+ connection.run('INSERT INTO replica_values (doc, key, keys, places, item, kind, value, size) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [doc, key, value.keys, value.places, value.item, value.kind, value.value, value.size]);
61
+ }
62
+ for (const link of made.links) {
63
+ connection.run('INSERT OR IGNORE INTO replica_links (doc, key, kind, keys, places, target, field) VALUES (?, ?, ?, ?, ?, ?, ?)', [doc, key, link.kind, link.keys, link.places, link.target, link.field]);
64
+ }
65
+ }
66
+ function entryId(connection, key, layer, path) {
67
+ const [row] = connection.rows('SELECT id FROM replica_entries WHERE key = ? AND layer = ? AND path = ?', [key, layer, path]);
68
+ return row === undefined ? null : number(row.id);
69
+ }
70
+ function removeEntry(connection, key, layer, path) {
71
+ const id = entryId(connection, key, layer, path);
72
+ if (id === null)
73
+ return;
74
+ dropDerived(connection, id);
75
+ unindexDocuments(connection, [id]);
76
+ connection.run('DELETE FROM replica_entries WHERE id = ?', [id]);
77
+ }
78
+ function heldIds(connection, sql, bind) {
79
+ return connection.rows(sql, bind).map((row) => number(row.id));
80
+ }
81
+ function insertEntry(connection, key, layer, entry, present, made) {
82
+ connection.run('INSERT INTO replica_entries (key, layer, path, visible, present, queried, content, binary, revision, file_id, change, written, type, declared, folder, fields) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', [
83
+ key,
84
+ layer,
85
+ entry.path,
86
+ flag(present && layer !== REFRESHED),
87
+ flag(present),
88
+ flag(made.queried),
89
+ entry.binary === null ? entry.content : null,
90
+ entry.binary === null ? null : JSON.stringify(entry.binary),
91
+ entry.revision,
92
+ entry.fileId,
93
+ entry.change === null ? null : JSON.stringify(entry.change),
94
+ entry.written,
95
+ made.type,
96
+ made.declared,
97
+ made.folder,
98
+ made.fields,
99
+ ]);
100
+ }
101
+ function textOf(entry) {
102
+ return entry.binary === null ? entry.content : null;
103
+ }
104
+ function putEntry(connection, key, layer, entry, present, composition, searched = true) {
105
+ removeEntry(connection, key, layer, entry.path);
106
+ const content = textOf(entry);
107
+ const made = present ? derived(entry.path, content, composition) : ABSENT;
108
+ insertEntry(connection, key, layer, entry, present, made);
109
+ if (!present)
110
+ return;
111
+ const id = entryId(connection, key, layer, entry.path);
112
+ writeDerived(connection, id, key, made);
113
+ if (searched && content !== null && made.queried) {
114
+ indexDocument(connection, id, entry.path, content);
115
+ }
116
+ }
117
+ function placeEntry(connection, key, entry) {
118
+ removeEntry(connection, key, CONFIRMED, entry.path);
119
+ insertEntry(connection, key, CONFIRMED, entry, true, described(entry.path, textOf(entry)));
120
+ }
121
+ function revealed(connection, key, touched) {
122
+ if (touched.length === 0)
123
+ return;
124
+ connection.run(`UPDATE replica_entries SET visible = CASE WHEN layer = ${OVERLAY} THEN present ELSE NOT EXISTS (SELECT 1 FROM replica_entries o WHERE o.key = replica_entries.key AND o.layer = ${OVERLAY} AND o.path = replica_entries.path) END WHERE key = ? AND layer IN (${CONFIRMED}, ${OVERLAY}) AND path IN (SELECT value FROM json_each(?))`, [key, paths(touched)]);
125
+ }
126
+ function newKey(connection, locator, transfer, fingerprint, built) {
127
+ const owed = built ? null : 0;
128
+ connection.run('INSERT INTO replica_keys (locator, transfer, fingerprint, rederiving, searching) VALUES (?, ?, ?, ?, ?)', [locator, transfer, fingerprint, owed, owed]);
129
+ const [row] = connection.rows('SELECT last_insert_rowid() AS key');
130
+ return number(row.key);
131
+ }
132
+ function recomposed(connection, key, fingerprint) {
133
+ const [row] = connection.rows('SELECT fingerprint FROM replica_keys WHERE key = ?', [key]);
134
+ if (row === undefined || text(row.fingerprint) === fingerprint)
135
+ return;
136
+ const held = connection.rows('SELECT 1 FROM replica_entries WHERE key = ? LIMIT 1', [key]);
137
+ connection.run(`UPDATE replica_keys SET fingerprint = ?${held.length === 0 ? '' : ', rederiving = 0'} WHERE key = ?`, [fingerprint, key]);
138
+ }
139
+ export function entered(connection, locator, composition, rows) {
140
+ const key = newKey(connection, locator, '', composedOf(composition).fingerprint, true);
141
+ for (const entry of rows)
142
+ putEntry(connection, key, CONFIRMED, entry, true, composition, false);
143
+ return key;
144
+ }
145
+ function dropTransfer(connection, locator) {
146
+ connection.run('DELETE FROM replica_transfers WHERE locator = ?', [locator]);
147
+ connection.run('DELETE FROM replica_transfer_parts WHERE locator = ?', [locator]);
148
+ }
149
+ export function stage(connection, request) {
150
+ const [held] = connection.rows('SELECT key FROM replica_transfers WHERE locator = ?', [
151
+ request.locator,
152
+ ]);
153
+ const key = request.key ??
154
+ (held === undefined
155
+ ? newKey(connection, request.locator, request.transfer, request.fingerprint, false)
156
+ : number(held.key));
157
+ recomposed(connection, key, request.fingerprint);
158
+ connection.run('UPDATE replica_keys SET rederiving = coalesce(rederiving, last), searching = coalesce(searching, last) FROM (SELECT coalesce(max(id), 0) AS last FROM replica_entries) WHERE key = ?', [key]);
159
+ connection.run('INSERT OR REPLACE INTO replica_transfers (locator, key, record) VALUES (?, ?, ?)', [request.locator, key, request.record]);
160
+ if (request.written !== undefined) {
161
+ connection.run('DELETE FROM replica_transfer_parts WHERE locator = ? AND token = ?', [
162
+ request.locator,
163
+ request.written,
164
+ ]);
165
+ }
166
+ for (const entry of request.entries)
167
+ placeEntry(connection, key, entry);
168
+ for (const path of request.folders) {
169
+ connection.run('INSERT OR REPLACE INTO replica_folders (key, layer, path, present) VALUES (?, ?, ?, 1)', [key, CONFIRMED, path]);
170
+ }
171
+ return key;
172
+ }
173
+ export function refreshing(connection, request) {
174
+ const held = connection.rows('SELECT 1 FROM replica_rooms WHERE key = ? UNION ALL SELECT 1 FROM replica_transfers WHERE key = ?', [request.key, request.key]);
175
+ if (held.length === 0)
176
+ return null;
177
+ recomposed(connection, request.key, request.composed.fingerprint);
178
+ const composition = request.composed.composition;
179
+ for (const entry of request.entries) {
180
+ putEntry(connection, request.key, REFRESHED, entry, true, composition);
181
+ }
182
+ for (const path of request.removals) {
183
+ putEntry(connection, request.key, REFRESHED, {
184
+ path,
185
+ content: null,
186
+ binary: null,
187
+ revision: null,
188
+ fileId: null,
189
+ change: null,
190
+ written: null,
191
+ }, false, composition);
192
+ }
193
+ for (const [list, present] of [
194
+ [request.folders, 1],
195
+ [request.folderRemovals, 0],
196
+ ]) {
197
+ for (const path of list) {
198
+ connection.run('INSERT OR REPLACE INTO replica_folders (key, layer, path, present) VALUES (?, ?, ?, ?)', [request.key, REFRESHED, path, present]);
199
+ }
200
+ }
201
+ return null;
202
+ }
203
+ function dropLayer(connection, key, layer) {
204
+ unindexDocuments(connection, heldIds(connection, 'SELECT id FROM replica_entries WHERE key = ? AND layer = ?', [key, layer]));
205
+ for (const table of ['replica_values', 'replica_links']) {
206
+ connection.run(`DELETE FROM ${table} WHERE doc IN (SELECT id FROM replica_entries WHERE key = ? AND layer = ?)`, [key, layer]);
207
+ }
208
+ connection.run('DELETE FROM replica_entries WHERE key = ? AND layer = ?', [key, layer]);
209
+ connection.run('DELETE FROM replica_folders WHERE key = ? AND layer = ?', [key, layer]);
210
+ }
211
+ export function unrefresh(connection, key) {
212
+ dropLayer(connection, key, REFRESHED);
213
+ return null;
214
+ }
215
+ function refreshedPaths(connection, key) {
216
+ return connection
217
+ .rows('SELECT path FROM replica_entries WHERE key = ? AND layer = ?', [key, REFRESHED])
218
+ .map((row) => text(row.path));
219
+ }
220
+ function applyRefresh(connection, key) {
221
+ const touched = refreshedPaths(connection, key);
222
+ const replaced = `SELECT c.id FROM replica_entries c JOIN replica_entries r ON r.key = c.key AND r.layer = ${REFRESHED} AND r.path = c.path WHERE c.key = ? AND c.layer = ${CONFIRMED}`;
223
+ unindexDocuments(connection, heldIds(connection, replaced, [key]));
224
+ for (const table of ['replica_values', 'replica_links']) {
225
+ connection.run(`DELETE FROM ${table} WHERE doc IN (${replaced})`, [key]);
226
+ }
227
+ connection.run(`DELETE FROM replica_entries WHERE id IN (${replaced})`, [key]);
228
+ connection.run('DELETE FROM replica_entries WHERE key = ? AND layer = ? AND present = 0', [
229
+ key,
230
+ REFRESHED,
231
+ ]);
232
+ connection.run('UPDATE replica_entries SET layer = ? WHERE key = ? AND layer = ?', [
233
+ CONFIRMED,
234
+ key,
235
+ REFRESHED,
236
+ ]);
237
+ connection.run(`DELETE FROM replica_folders WHERE key = ? AND layer = ${CONFIRMED} AND path IN (SELECT path FROM replica_folders WHERE key = ? AND layer = ${REFRESHED})`, [key, key]);
238
+ connection.run(`UPDATE replica_folders SET layer = ${CONFIRMED} WHERE key = ? AND layer = ${REFRESHED} AND present = 1`, [key]);
239
+ connection.run('DELETE FROM replica_folders WHERE key = ? AND layer = ?', [key, REFRESHED]);
240
+ return touched;
241
+ }
242
+ function counted(connection, key, roots) {
243
+ const outside = roots.map(() => '(path = ? OR (path >= ? AND path < ?))').join(' OR ');
244
+ const bind = [key];
245
+ for (const root of roots)
246
+ bind.push(root, `${root}/`, `${root}0`);
247
+ const [row] = connection.rows(`SELECT count(*) AS held FROM replica_entries WHERE key = ? AND visible = 1 AND present = 1 AND (binary IS NOT NULL OR substr(path, -3) = '.md')${roots.length === 0 ? '' : ` AND NOT (${outside})`}`, bind);
248
+ return number(row.held);
249
+ }
250
+ export function counts(connection, rooms) {
251
+ return rooms.map(({ key, roots }) => counted(connection, key, roots));
252
+ }
253
+ function erasing(connection, key, locator) {
254
+ connection.run('INSERT OR REPLACE INTO replica_erasing (key, locator) VALUES (?, ?)', [
255
+ key,
256
+ locator,
257
+ ]);
258
+ }
259
+ function commitRoom(connection, room) {
260
+ const touched = new Set();
261
+ recomposed(connection, room.key, room.composed.fingerprint);
262
+ const composition = room.composed.composition;
263
+ if (room.published !== undefined) {
264
+ if (room.published.from !== null && room.published.from !== room.key) {
265
+ erasing(connection, room.published.from, room.locator);
266
+ }
267
+ dropTransfer(connection, room.locator);
268
+ }
269
+ if (room.refreshed === true) {
270
+ for (const path of applyRefresh(connection, room.key))
271
+ touched.add(path);
272
+ }
273
+ for (const entry of room.confirmed?.set ?? []) {
274
+ putEntry(connection, room.key, CONFIRMED, entry, true, composition);
275
+ touched.add(entry.path);
276
+ }
277
+ for (const path of room.confirmed?.removed ?? []) {
278
+ removeEntry(connection, room.key, CONFIRMED, path);
279
+ touched.add(path);
280
+ }
281
+ for (const entry of room.overlay?.set ?? []) {
282
+ putEntry(connection, room.key, OVERLAY, entry, entry.present, composition);
283
+ touched.add(entry.path);
284
+ }
285
+ for (const path of room.overlay?.cleared ?? []) {
286
+ removeEntry(connection, room.key, OVERLAY, path);
287
+ touched.add(path);
288
+ }
289
+ const changed = [...touched];
290
+ revealed(connection, room.key, changed);
291
+ if (room.record !== undefined) {
292
+ connection.run('INSERT OR REPLACE INTO replica_rooms (locator, key, record) VALUES (?, ?, ?)', [
293
+ room.locator,
294
+ room.key,
295
+ room.record,
296
+ ]);
297
+ }
298
+ return room.published === undefined ? changed : null;
299
+ }
300
+ export function commit(connection, rooms) {
301
+ const counted = {};
302
+ const changed = {};
303
+ const indexed = {};
304
+ for (const room of rooms) {
305
+ changed[room.locator] = commitRoom(connection, room);
306
+ counted[room.locator] = counts(connection, [
307
+ { key: room.key, roots: room.roots ?? rootsOf(connection, room.locator) },
308
+ ])[0];
309
+ const [held] = connection.rows('SELECT rederiving, searching FROM replica_keys WHERE key = ?', [
310
+ room.key,
311
+ ]);
312
+ indexed[room.locator] =
313
+ held !== undefined && held.rederiving === null && held.searching === null;
314
+ }
315
+ return { counts: counted, changed, indexed };
316
+ }
317
+ function rootsOf(connection, locator) {
318
+ const [row] = connection.rows('SELECT record FROM replica_rooms WHERE locator = ?', [locator]);
319
+ const record = json(row?.record);
320
+ return record?.typedSelection?.roots ?? [];
321
+ }
322
+ export function fenceRooms(connection, locators) {
323
+ for (const locator of locators) {
324
+ for (const row of connection.rows('SELECT key FROM replica_keys WHERE locator = ? UNION SELECT key FROM replica_rooms WHERE locator = ? UNION SELECT key FROM replica_transfers WHERE locator = ?', [locator, locator, locator])) {
325
+ erasing(connection, number(row.key), locator);
326
+ }
327
+ connection.run('DELETE FROM replica_rooms WHERE locator = ?', [locator]);
328
+ dropTransfer(connection, locator);
329
+ }
330
+ return null;
331
+ }
332
+ export function abandon(connection, locator, kept) {
333
+ const [held] = connection.rows('SELECT key FROM replica_transfers WHERE locator = ?', [locator]);
334
+ dropTransfer(connection, locator);
335
+ if (held === undefined)
336
+ return null;
337
+ if (!kept)
338
+ erasing(connection, number(held.key), locator);
339
+ return number(held.key);
340
+ }
341
+ export function release(connection, key) {
342
+ const [held] = connection.rows(`SELECT k.locator FROM replica_keys k WHERE k.key = ?
343
+ AND NOT EXISTS (SELECT 1 FROM replica_rooms r WHERE r.key = k.key)
344
+ AND NOT EXISTS (SELECT 1 FROM replica_transfers t WHERE t.key = k.key)`, [key]);
345
+ if (held !== undefined)
346
+ erasing(connection, key, text(held.locator));
347
+ return null;
348
+ }
349
+ export function erase(connection, locator, limit) {
350
+ const [held] = connection.rows(`SELECT key FROM replica_erasing${locator === null ? '' : ' WHERE locator = ?'} ORDER BY key LIMIT 1`, locator === null ? [] : [locator]);
351
+ if (held === undefined)
352
+ return { remaining: false };
353
+ const key = number(held.key);
354
+ const batch = 'SELECT id FROM replica_entries WHERE key = ? ORDER BY id LIMIT ?';
355
+ unindexDocuments(connection, heldIds(connection, batch, [key, limit]));
356
+ for (const table of ['replica_values', 'replica_links']) {
357
+ connection.run(`DELETE FROM ${table} WHERE doc IN (${batch})`, [key, limit]);
358
+ }
359
+ connection.run(`DELETE FROM replica_entries WHERE id IN (${batch})`, [key, limit]);
360
+ const left = connection.rows('SELECT 1 FROM replica_entries WHERE key = ? LIMIT 1', [key]).length > 0;
361
+ if (!left) {
362
+ connection.run('DELETE FROM replica_folders WHERE key = ?', [key]);
363
+ connection.run('DELETE FROM replica_erasing WHERE key = ?', [key]);
364
+ connection.run('DELETE FROM replica_keys WHERE key = ?', [key]);
365
+ }
366
+ const [more] = connection.rows(`SELECT 1 FROM replica_erasing${locator === null ? '' : ' WHERE locator = ?'} LIMIT 1`, locator === null ? [] : [locator]);
367
+ return { remaining: more !== undefined };
368
+ }
369
+ function cursor(value) {
370
+ return value === null || value === undefined ? null : number(value);
371
+ }
372
+ export function rederive(connection, key, composed, bytes) {
373
+ recomposed(connection, key, composed.fingerprint);
374
+ const [held] = connection.rows('SELECT rederiving, searching FROM replica_keys WHERE key = ?', [
375
+ key,
376
+ ]);
377
+ const deriving = cursor(held?.rederiving);
378
+ const searching = cursor(held?.searching);
379
+ if (deriving === null && searching === null)
380
+ return { done: true };
381
+ const composition = composed.composition;
382
+ let last = Math.min(deriving ?? Infinity, searching ?? Infinity);
383
+ let spent = 0;
384
+ const reached = (done) => {
385
+ const next = (from) => (from === null || done ? null : Math.max(from, last));
386
+ connection.run('UPDATE replica_keys SET rederiving = ?, searching = ? WHERE key = ?', [
387
+ next(deriving),
388
+ next(searching),
389
+ key,
390
+ ]);
391
+ return { done };
392
+ };
393
+ for (;;) {
394
+ const rows = connection.rows('SELECT id, path, content FROM replica_entries WHERE key = ? AND present = 1 AND id > ? ORDER BY id LIMIT ?', [key, last, DERIVED_ROWS]);
395
+ for (const row of rows) {
396
+ const id = number(row.id);
397
+ const path = text(row.path);
398
+ const content = text(row.content);
399
+ const owedRows = deriving !== null && id > deriving;
400
+ const owedWords = searching !== null && id > searching && content !== null;
401
+ if (owedRows) {
402
+ const made = derived(path, content, composition);
403
+ dropDerived(connection, id);
404
+ writeDerived(connection, id, key, made);
405
+ }
406
+ if (owedWords && described(path, content).queried) {
407
+ indexDocument(connection, id, path, content);
408
+ }
409
+ last = id;
410
+ spent += ENTRY_WEIGHT + (content?.length ?? 0);
411
+ if (spent >= bytes)
412
+ return reached(false);
413
+ }
414
+ if (rows.length < DERIVED_ROWS)
415
+ return reached(true);
416
+ }
417
+ }
418
+ function heldEntry(row) {
419
+ return {
420
+ path: text(row.path),
421
+ content: text(row.content),
422
+ binary: json(row.binary),
423
+ revision: text(row.revision),
424
+ fileId: text(row.file_id),
425
+ change: json(row.change),
426
+ written: text(row.written),
427
+ type: text(row.type),
428
+ };
429
+ }
430
+ const ENTRY_COLUMNS = 'e.path, e.content, e.binary, e.revision, e.file_id, e.change, e.written, e.type';
431
+ function viewed(view, alias) {
432
+ if (view === 'visible')
433
+ return `${alias}.visible = 1 AND ${alias}.present = 1`;
434
+ if (view === 'confirmed')
435
+ return `${alias}.layer = ${CONFIRMED}`;
436
+ return `${alias}.present = 1 AND (${alias}.layer = ${REFRESHED} OR (${alias}.layer = ${CONFIRMED} AND NOT EXISTS (SELECT 1 FROM replica_entries r WHERE r.key = ${alias}.key AND r.layer = ${REFRESHED} AND r.path = ${alias}.path)))`;
437
+ }
438
+ export function entries(connection, key, view, list) {
439
+ if (list.length === 0)
440
+ return [];
441
+ return connection
442
+ .rows(`SELECT ${ENTRY_COLUMNS} FROM replica_entries e WHERE e.key = ? AND ${viewed(view, 'e')} AND e.path IN (SELECT value FROM json_each(?))`, [key, paths(list)])
443
+ .map(heldEntry);
444
+ }
445
+ export function typed(connection, key, view, list) {
446
+ if (list.length === 0)
447
+ return [];
448
+ return connection
449
+ .rows(`SELECT e.path, e.declared, e.binary IS NOT NULL AS binary FROM replica_entries e WHERE e.key = ? AND ${viewed(view, 'e')} AND e.path IN (SELECT value FROM json_each(?))`, [key, paths(list)])
450
+ .map((row) => ({
451
+ path: text(row.path),
452
+ type: text(row.declared),
453
+ binary: number(row.binary) === 1,
454
+ }));
455
+ }
456
+ export function referrers(connection, key, view, targets, kinds) {
457
+ if (targets.length === 0)
458
+ return [];
459
+ return connection
460
+ .rows(`SELECT DISTINCT e.path, l.target, l.kind FROM replica_links l JOIN replica_entries e ON e.id = l.doc WHERE l.key = ? AND l.target IN (SELECT value FROM json_each(?)) AND l.kind IN (SELECT value FROM json_each(?)) AND ${viewed(view, 'e')}`, [key, paths(targets), JSON.stringify(kinds)])
461
+ .map((row) => ({
462
+ path: text(row.path),
463
+ target: text(row.target),
464
+ kind: text(row.kind),
465
+ }));
466
+ }
467
+ export function walk(connection, key, view, after, bytes) {
468
+ const found = [];
469
+ let spent = 0;
470
+ let from = after;
471
+ for (;;) {
472
+ const rows = connection.rows(`SELECT ${ENTRY_COLUMNS} FROM replica_entries e WHERE e.key = ? AND ${viewed(view, 'e')}${from === null ? '' : ' AND e.path > ?'} ORDER BY e.path LIMIT 64`, from === null ? [key] : [key, from]);
473
+ for (const row of rows) {
474
+ const entry = heldEntry(row);
475
+ found.push(entry);
476
+ spent += 256 + (entry.content?.length ?? 0) * 2;
477
+ if (spent >= bytes)
478
+ return { entries: found, next: entry.path };
479
+ }
480
+ if (rows.length < 64)
481
+ return { entries: found, next: null };
482
+ from = found.at(-1).path;
483
+ }
484
+ }
485
+ export function files(connection, key, view, after, limit) {
486
+ return connection
487
+ .rows(`SELECT e.path, e.revision FROM replica_entries e WHERE e.key = ? AND ${viewed(view, 'e')} AND e.content IS NOT NULL AND e.revision IS NOT NULL${after === null ? '' : ' AND e.path > ?'} ORDER BY e.path LIMIT ?`, after === null ? [key, limit] : [key, after, limit])
488
+ .map((row) => ({ path: text(row.path), revision: text(row.revision) }));
489
+ }
490
+ export function typedWithin(connection, key, view, roots, within) {
491
+ const inside = roots.map(() => '(e.path = ? OR (e.path >= ? AND e.path < ?))').join(' OR ');
492
+ const bind = [key];
493
+ for (const root of roots)
494
+ bind.push(root, `${root}/`, `${root}0`);
495
+ const placed = roots.length === 0 ? (within ? ' AND 0' : '') : ` AND ${within ? '' : 'NOT '}(${inside})`;
496
+ return (connection.rows(`SELECT 1 FROM replica_entries e WHERE e.key = ? AND ${viewed(view, 'e')} AND e.declared IS NOT NULL AND e.declared <> 'any'${placed} LIMIT 1`, bind).length > 0);
497
+ }
498
+ export function transferPart(connection, locator, token) {
499
+ const [held] = connection.rows('SELECT part FROM replica_transfer_parts WHERE locator = ? AND token = ?', [locator, token]);
500
+ return held?.part instanceof Uint8Array ? held.part : null;
501
+ }
502
+ export function keepParts(connection, parts) {
503
+ for (const { locator, token, part } of parts) {
504
+ connection.run('DELETE FROM replica_transfer_parts WHERE locator = ? AND token = ?', [
505
+ locator,
506
+ token,
507
+ ]);
508
+ connection.run('INSERT INTO replica_transfer_parts (locator, token, part) SELECT ?, ?, ? WHERE EXISTS (SELECT 1 FROM replica_transfers WHERE locator = ?)', [locator, token, part, locator]);
509
+ }
510
+ return null;
511
+ }
512
+ export function opened(connection) {
513
+ const facts = {};
514
+ for (const row of connection.rows('SELECT name, value FROM replica_facts')) {
515
+ facts[text(row.name)] = text(row.value);
516
+ }
517
+ return {
518
+ rooms: connection.rows('SELECT locator, key, record FROM replica_rooms').map((row) => ({
519
+ locator: text(row.locator),
520
+ key: number(row.key),
521
+ record: text(row.record),
522
+ })),
523
+ transfers: connection.rows('SELECT locator, key, record FROM replica_transfers').map((row) => ({
524
+ locator: text(row.locator),
525
+ key: number(row.key),
526
+ record: text(row.record),
527
+ })),
528
+ kept: connection
529
+ .rows('SELECT locator, token, length(part) AS bytes FROM replica_transfer_parts')
530
+ .map((row) => ({
531
+ locator: text(row.locator),
532
+ token: text(row.token),
533
+ bytes: number(row.bytes),
534
+ })),
535
+ keys: connection
536
+ .rows('SELECT key, locator, transfer, rederiving, searching FROM replica_keys')
537
+ .map((row) => ({
538
+ key: number(row.key),
539
+ locator: text(row.locator),
540
+ transfer: text(row.transfer),
541
+ rederiving: cursor(row.rederiving),
542
+ searching: cursor(row.searching),
543
+ })),
544
+ facts,
545
+ presentation: connection.rows('SELECT app, value FROM replica_presentation').map((row) => ({
546
+ app: text(row.app),
547
+ value: text(row.value),
548
+ })),
549
+ overlaid: connection
550
+ .rows(`SELECT key, path FROM replica_entries WHERE layer = ${OVERLAY}`)
551
+ .map((row) => ({ key: number(row.key), path: text(row.path) })),
552
+ orphans: connection
553
+ .rows(`SELECT k.key FROM replica_keys k
554
+ WHERE NOT EXISTS (SELECT 1 FROM replica_rooms r WHERE r.key = k.key)
555
+ AND NOT EXISTS (SELECT 1 FROM replica_transfers t WHERE t.key = k.key)
556
+ AND NOT EXISTS (SELECT 1 FROM replica_erasing e WHERE e.key = k.key)`)
557
+ .map((row) => number(row.key)),
558
+ erasing: connection.rows('SELECT key, locator FROM replica_erasing').map((row) => ({
559
+ key: number(row.key),
560
+ locator: text(row.locator),
561
+ })),
562
+ };
563
+ }
564
+ export function ended(connection) {
565
+ for (const statement of REPLICA_TABLES) {
566
+ const table = /^CREATE TABLE (\w+)/u.exec(statement)?.[1];
567
+ if (table !== undefined)
568
+ connection.run(`DELETE FROM ${table}`);
569
+ }
570
+ unindexAll(connection);
571
+ }