@agentshouse/mdruntime 0.1.0-c5f333dfa0583 → 0.1.0-c5fe3b2cddda7

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