@agentshouse/mdruntime 0.1.0-cae97ad2e9142 → 0.1.0-caf080a9a9c60

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 (315) hide show
  1. package/README.md +14 -14
  2. package/dist/acceptance.d.ts +3 -0
  3. package/dist/acceptance.d.ts.map +1 -0
  4. package/dist/acceptance.js +318 -0
  5. package/dist/act-lanes.d.ts +29 -0
  6. package/dist/act-lanes.d.ts.map +1 -0
  7. package/dist/act-lanes.js +177 -0
  8. package/dist/actions.d.ts +25 -0
  9. package/dist/actions.d.ts.map +1 -0
  10. package/dist/actions.js +261 -0
  11. package/dist/adapter.d.ts +126 -107
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +3 -10
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +29 -47
  16. package/dist/bootstrap.d.ts +17 -19
  17. package/dist/bootstrap.d.ts.map +1 -1
  18. package/dist/bootstrap.js +266 -135
  19. package/dist/cell.d.ts +6 -0
  20. package/dist/cell.d.ts.map +1 -0
  21. package/dist/cell.js +9 -0
  22. package/dist/chain.d.ts +2 -1
  23. package/dist/chain.d.ts.map +1 -1
  24. package/dist/change-set.d.ts +4 -0
  25. package/dist/change-set.d.ts.map +1 -1
  26. package/dist/change-set.js +6 -0
  27. package/dist/change.d.ts +1 -0
  28. package/dist/change.d.ts.map +1 -1
  29. package/dist/change.js +4 -2
  30. package/dist/chat-types.d.ts +5 -0
  31. package/dist/chat-types.d.ts.map +1 -0
  32. package/dist/chat-types.js +13 -0
  33. package/dist/client.d.ts +28 -18
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +84 -20
  36. package/dist/collection.d.ts +28 -7
  37. package/dist/collection.d.ts.map +1 -1
  38. package/dist/collection.js +35 -19
  39. package/dist/compile.d.ts +8 -6
  40. package/dist/compile.d.ts.map +1 -1
  41. package/dist/compile.js +289 -332
  42. package/dist/connection.d.ts +6 -141
  43. package/dist/connection.d.ts.map +1 -1
  44. package/dist/connection.js +111 -5012
  45. package/dist/context.d.ts +2 -0
  46. package/dist/context.d.ts.map +1 -0
  47. package/dist/context.js +7 -0
  48. package/dist/conversation-live.d.ts +138 -0
  49. package/dist/conversation-live.d.ts.map +1 -0
  50. package/dist/conversation-live.js +249 -0
  51. package/dist/conversation-row.d.ts +33 -0
  52. package/dist/conversation-row.d.ts.map +1 -0
  53. package/dist/conversation-row.js +53 -0
  54. package/dist/conversation.d.ts +59 -50
  55. package/dist/conversation.d.ts.map +1 -1
  56. package/dist/conversation.js +938 -832
  57. package/dist/declaration.d.ts +10 -0
  58. package/dist/declaration.d.ts.map +1 -0
  59. package/dist/declaration.js +24 -0
  60. package/dist/discovery.d.ts +10 -0
  61. package/dist/discovery.d.ts.map +1 -0
  62. package/dist/discovery.js +153 -0
  63. package/dist/durability.d.ts +18 -1
  64. package/dist/durability.d.ts.map +1 -1
  65. package/dist/entry.d.ts +3 -2
  66. package/dist/entry.d.ts.map +1 -1
  67. package/dist/entry.js +19 -9
  68. package/dist/expectation.d.ts +26 -13
  69. package/dist/expectation.d.ts.map +1 -1
  70. package/dist/expectation.js +72 -19
  71. package/dist/failure.d.ts +3 -0
  72. package/dist/failure.d.ts.map +1 -1
  73. package/dist/failure.js +6 -0
  74. package/dist/figures.d.ts +49 -0
  75. package/dist/figures.d.ts.map +1 -0
  76. package/dist/figures.js +197 -0
  77. package/dist/file.d.ts +2 -11
  78. package/dist/file.d.ts.map +1 -1
  79. package/dist/file.js +6 -4
  80. package/dist/holdings.d.ts +29 -0
  81. package/dist/holdings.d.ts.map +1 -0
  82. package/dist/holdings.js +95 -0
  83. package/dist/host.d.ts +20 -8
  84. package/dist/host.d.ts.map +1 -1
  85. package/dist/host.js +70 -40
  86. package/dist/identity.d.ts +0 -1
  87. package/dist/identity.d.ts.map +1 -1
  88. package/dist/identity.js +0 -3
  89. package/dist/index.d.ts +33 -12
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +14 -3
  92. package/dist/install.d.ts +54 -0
  93. package/dist/install.d.ts.map +1 -0
  94. package/dist/install.js +539 -0
  95. package/dist/lifecycle.d.ts +7 -0
  96. package/dist/lifecycle.d.ts.map +1 -0
  97. package/dist/lifecycle.js +279 -0
  98. package/dist/listing.d.ts +48 -0
  99. package/dist/listing.d.ts.map +1 -0
  100. package/dist/listing.js +139 -0
  101. package/dist/live.d.ts +5 -4
  102. package/dist/live.d.ts.map +1 -1
  103. package/dist/live.js +64 -23
  104. package/dist/locks.d.ts +7 -0
  105. package/dist/locks.d.ts.map +1 -0
  106. package/dist/locks.js +33 -0
  107. package/dist/log.d.ts +1 -0
  108. package/dist/log.d.ts.map +1 -1
  109. package/dist/lost.d.ts +5 -0
  110. package/dist/lost.d.ts.map +1 -0
  111. package/dist/lost.js +50 -0
  112. package/dist/media.d.ts +8 -0
  113. package/dist/media.d.ts.map +1 -0
  114. package/dist/media.js +218 -0
  115. package/dist/memory.d.ts +15 -6
  116. package/dist/memory.d.ts.map +1 -1
  117. package/dist/memory.js +251 -98
  118. package/dist/messages.d.ts +24 -3
  119. package/dist/messages.d.ts.map +1 -1
  120. package/dist/messages.js +92 -32
  121. package/dist/model.d.ts +8 -11
  122. package/dist/model.d.ts.map +1 -1
  123. package/dist/model.js +5 -22
  124. package/dist/models.d.ts +10 -0
  125. package/dist/models.d.ts.map +1 -0
  126. package/dist/models.js +156 -0
  127. package/dist/observation.d.ts +3 -2
  128. package/dist/observation.d.ts.map +1 -1
  129. package/dist/observation.js +15 -15
  130. package/dist/opened.d.ts +1 -1
  131. package/dist/opened.d.ts.map +1 -1
  132. package/dist/opened.js +5 -5
  133. package/dist/opening.d.ts +4 -0
  134. package/dist/opening.d.ts.map +1 -0
  135. package/dist/opening.js +59 -0
  136. package/dist/outcome.d.ts +20 -6
  137. package/dist/outcome.d.ts.map +1 -1
  138. package/dist/outcome.js +34 -2
  139. package/dist/overlay.d.ts +6 -1
  140. package/dist/overlay.d.ts.map +1 -1
  141. package/dist/overlay.js +47 -21
  142. package/dist/page-metadata.d.ts +8 -0
  143. package/dist/page-metadata.d.ts.map +1 -0
  144. package/dist/page-metadata.js +19 -0
  145. package/dist/parts.d.ts +3 -0
  146. package/dist/parts.d.ts.map +1 -0
  147. package/dist/parts.js +10 -0
  148. package/dist/paths.d.ts +2 -0
  149. package/dist/paths.d.ts.map +1 -1
  150. package/dist/paths.js +26 -0
  151. package/dist/preparation.d.ts +20 -0
  152. package/dist/preparation.d.ts.map +1 -0
  153. package/dist/preparation.js +233 -0
  154. package/dist/presence.d.ts +52 -0
  155. package/dist/presence.d.ts.map +1 -0
  156. package/dist/presence.js +220 -0
  157. package/dist/queries.d.ts +16 -0
  158. package/dist/queries.d.ts.map +1 -0
  159. package/dist/queries.js +285 -0
  160. package/dist/query.d.ts +14 -210
  161. package/dist/query.d.ts.map +1 -1
  162. package/dist/query.js +3 -505
  163. package/dist/questions.d.ts +29 -0
  164. package/dist/questions.d.ts.map +1 -0
  165. package/dist/questions.js +115 -0
  166. package/dist/queue.d.ts +40 -0
  167. package/dist/queue.d.ts.map +1 -0
  168. package/dist/queue.js +465 -0
  169. package/dist/reach.d.ts +15 -12
  170. package/dist/reach.d.ts.map +1 -1
  171. package/dist/reach.js +228 -145
  172. package/dist/react.d.ts +15 -2
  173. package/dist/react.d.ts.map +1 -1
  174. package/dist/react.js +33 -1
  175. package/dist/read.d.ts +7 -0
  176. package/dist/read.d.ts.map +1 -0
  177. package/dist/read.js +17 -0
  178. package/dist/readiness.d.ts +3 -18
  179. package/dist/readiness.d.ts.map +1 -1
  180. package/dist/readiness.js +4 -10
  181. package/dist/reads.d.ts +38 -10
  182. package/dist/reads.d.ts.map +1 -1
  183. package/dist/reads.js +163 -85
  184. package/dist/recovery.d.ts +3 -0
  185. package/dist/recovery.d.ts.map +1 -1
  186. package/dist/recovery.js +57 -1
  187. package/dist/refresh.d.ts +7 -5
  188. package/dist/refresh.d.ts.map +1 -1
  189. package/dist/refresh.js +35 -7
  190. package/dist/refusal.d.ts +5 -0
  191. package/dist/refusal.d.ts.map +1 -0
  192. package/dist/refusal.js +57 -0
  193. package/dist/replica.d.ts +13 -19
  194. package/dist/replica.d.ts.map +1 -1
  195. package/dist/replica.js +66 -35
  196. package/dist/retried.d.ts +30 -0
  197. package/dist/retried.d.ts.map +1 -0
  198. package/dist/retried.js +72 -0
  199. package/dist/room-draft.d.ts +24 -10
  200. package/dist/room-draft.d.ts.map +1 -1
  201. package/dist/room-draft.js +142 -106
  202. package/dist/room-drafts.d.ts +24 -0
  203. package/dist/room-drafts.d.ts.map +1 -0
  204. package/dist/room-drafts.js +217 -0
  205. package/dist/rows.d.ts +16 -21
  206. package/dist/rows.d.ts.map +1 -1
  207. package/dist/rows.js +46 -174
  208. package/dist/runtime.d.ts +36 -0
  209. package/dist/runtime.d.ts.map +1 -0
  210. package/dist/runtime.js +1 -0
  211. package/dist/save.d.ts +42 -84
  212. package/dist/save.d.ts.map +1 -1
  213. package/dist/save.js +349 -170
  214. package/dist/saves.d.ts +32 -0
  215. package/dist/saves.d.ts.map +1 -0
  216. package/dist/saves.js +413 -0
  217. package/dist/search.d.ts +12 -63
  218. package/dist/search.d.ts.map +1 -1
  219. package/dist/search.js +9 -52
  220. package/dist/seed.d.ts +11 -2
  221. package/dist/seed.d.ts.map +1 -1
  222. package/dist/seed.js +71 -1
  223. package/dist/shared.d.ts +1 -7
  224. package/dist/shared.d.ts.map +1 -1
  225. package/dist/shared.js +13 -105
  226. package/dist/shown.d.ts +32 -0
  227. package/dist/shown.d.ts.map +1 -0
  228. package/dist/shown.js +290 -0
  229. package/dist/socket/admission.d.ts +7 -0
  230. package/dist/socket/admission.d.ts.map +1 -0
  231. package/dist/socket/admission.js +39 -0
  232. package/dist/socket/answers.d.ts +6 -0
  233. package/dist/socket/answers.d.ts.map +1 -0
  234. package/dist/socket/answers.js +20 -0
  235. package/dist/socket/lanes.d.ts +21 -0
  236. package/dist/socket/lanes.d.ts.map +1 -0
  237. package/dist/socket/lanes.js +80 -0
  238. package/dist/socket/reads.d.ts +10 -0
  239. package/dist/socket/reads.d.ts.map +1 -0
  240. package/dist/socket/reads.js +31 -0
  241. package/dist/socket/session.d.ts +38 -0
  242. package/dist/socket/session.d.ts.map +1 -0
  243. package/dist/socket/session.js +23 -0
  244. package/dist/socket.d.ts +68 -0
  245. package/dist/socket.d.ts.map +1 -0
  246. package/dist/socket.js +171 -0
  247. package/dist/source.d.ts +54 -0
  248. package/dist/source.d.ts.map +1 -0
  249. package/dist/source.js +82 -0
  250. package/dist/status.d.ts +4 -5
  251. package/dist/status.d.ts.map +1 -1
  252. package/dist/status.js +3 -7
  253. package/dist/store/installs.d.ts +30 -0
  254. package/dist/store/installs.d.ts.map +1 -0
  255. package/dist/store/installs.js +34 -0
  256. package/dist/store/readiness.d.ts +10 -0
  257. package/dist/store/readiness.d.ts.map +1 -0
  258. package/dist/store/readiness.js +52 -0
  259. package/dist/store/records.d.ts +212 -0
  260. package/dist/store/records.d.ts.map +1 -0
  261. package/dist/store/records.js +430 -0
  262. package/dist/store/room-held.d.ts +8 -0
  263. package/dist/store/room-held.d.ts.map +1 -0
  264. package/dist/store/room-held.js +17 -0
  265. package/dist/store/space.d.ts +11 -0
  266. package/dist/store/space.d.ts.map +1 -0
  267. package/dist/store/space.js +41 -0
  268. package/dist/store/watchers.d.ts +17 -0
  269. package/dist/store/watchers.d.ts.map +1 -0
  270. package/dist/store/watchers.js +56 -0
  271. package/dist/store/writes.d.ts +24 -0
  272. package/dist/store/writes.d.ts.map +1 -0
  273. package/dist/store/writes.js +125 -0
  274. package/dist/store.d.ts +110 -158
  275. package/dist/store.d.ts.map +1 -1
  276. package/dist/store.js +167 -403
  277. package/dist/stored.d.ts +65 -59
  278. package/dist/stored.d.ts.map +1 -1
  279. package/dist/stored.js +356 -271
  280. package/dist/surface.d.ts +88 -0
  281. package/dist/surface.d.ts.map +1 -0
  282. package/dist/surface.js +223 -0
  283. package/dist/sync.d.ts +19 -0
  284. package/dist/sync.d.ts.map +1 -0
  285. package/dist/sync.js +540 -0
  286. package/dist/tables.d.ts +127 -69
  287. package/dist/tables.d.ts.map +1 -1
  288. package/dist/tables.js +218 -105
  289. package/dist/tallies.d.ts +18 -0
  290. package/dist/tallies.d.ts.map +1 -0
  291. package/dist/tallies.js +129 -0
  292. package/dist/transfer.d.ts +0 -5
  293. package/dist/transfer.d.ts.map +1 -1
  294. package/dist/validation.d.ts +3 -4
  295. package/dist/validation.d.ts.map +1 -1
  296. package/dist/validation.js +42 -100
  297. package/dist/windows.d.ts +1 -12
  298. package/dist/windows.d.ts.map +1 -1
  299. package/dist/windows.js +2 -75
  300. package/dist/wire.d.ts +63 -11
  301. package/dist/wire.d.ts.map +1 -1
  302. package/dist/wire.js +21 -5
  303. package/package.json +3 -2
  304. package/dist/attempt.d.ts +0 -16
  305. package/dist/attempt.d.ts.map +0 -1
  306. package/dist/attempt.js +0 -70
  307. package/dist/fence.d.ts +0 -6
  308. package/dist/fence.d.ts.map +0 -1
  309. package/dist/fence.js +0 -10
  310. package/dist/fulltext.d.ts +0 -27
  311. package/dist/fulltext.d.ts.map +0 -1
  312. package/dist/fulltext.js +0 -368
  313. package/dist/words.d.ts +0 -19
  314. package/dist/words.d.ts.map +0 -1
  315. package/dist/words.js +0 -150
package/dist/messages.js CHANGED
@@ -1,24 +1,58 @@
1
- import { indexMessage, unindexMessages } from './fulltext.js';
1
+ import { sql } from '@agentshouse/mdmodel';
2
+ import { EXCERPT } from './read.js';
3
+ const SAID_BY_HOUSE = `json_extract(message, '$.role') = 'house'`;
4
+ const ANSWERS_THE_TURN = `json_extract(message, '$.role') = 'assistant'`;
2
5
  export const MESSAGE_TABLES = [
3
6
  'CREATE TABLE conversation_reads (conversation TEXT PRIMARY KEY, read TEXT, partial INTEGER NOT NULL) WITHOUT ROWID',
4
- 'CREATE TABLE conversation_messages (id INTEGER PRIMARY KEY, conversation TEXT NOT NULL, identity TEXT NOT NULL, turn TEXT NOT NULL, position TEXT NOT NULL, message TEXT NOT NULL, text TEXT NOT NULL)',
7
+ 'CREATE TABLE conversation_messages (id INTEGER PRIMARY KEY, conversation TEXT NOT NULL, identity TEXT NOT NULL, turn TEXT NOT NULL, position TEXT NOT NULL, change TEXT NOT NULL, message TEXT NOT NULL, text TEXT NOT NULL)',
5
8
  'CREATE UNIQUE INDEX conversation_messages_identity ON conversation_messages (conversation, identity)',
6
9
  'CREATE INDEX conversation_messages_position ON conversation_messages (conversation, position, identity)',
7
10
  'CREATE INDEX conversation_messages_turn ON conversation_messages (conversation, turn)',
11
+ `CREATE INDEX conversation_messages_house ON conversation_messages (conversation, position, identity) WHERE ${SAID_BY_HOUSE}`,
8
12
  ];
13
+ const NEWEST_FIRST = 'ORDER BY position DESC, identity DESC LIMIT 1';
14
+ const OLDEST_FIRST = 'ORDER BY position, identity LIMIT 1';
15
+ const OF_THE_ROW = 'SELECT id FROM conversation_messages WHERE conversation = listed.value';
16
+ export const ROWS = `WITH chosen AS (
17
+ SELECT listed.value AS conversation,
18
+ (${OF_THE_ROW} AND ${ANSWERS_THE_TURN} ${NEWEST_FIRST}) AS answer,
19
+ (${OF_THE_ROW} AND text <> '' ${NEWEST_FIRST}) AS said,
20
+ (${OF_THE_ROW} AND ${SAID_BY_HOUSE} ${OLDEST_FIRST}) AS opened,
21
+ (${OF_THE_ROW} AND ${SAID_BY_HOUSE} AND json_extract(message, '$.waiting') = 1 ${OLDEST_FIRST}) AS asking
22
+ FROM json_each(?) AS listed
23
+ )
24
+ SELECT chosen.conversation AS conversation,
25
+ substr(said.text, 1, ${EXCERPT}) AS said_text,
26
+ json_extract(said.message, '$.role') AS said_role,
27
+ json_extract(said.message, '$.accepted_at') AS said_at,
28
+ substr(json_extract(answer.message, '$.failure'), 1, ${EXCERPT}) AS failure,
29
+ json_extract(opened.message, '$.source') AS opened_source,
30
+ json_extract(opened.message, '$.sender') AS opened_sender,
31
+ asking.identity AS asking_identity,
32
+ asking.text AS asking_text,
33
+ json_extract(asking.message, '$.accepted_at') AS asking_at,
34
+ json_extract(asking.message, '$.source') AS asking_source,
35
+ json_extract(asking.message, '$.sender') AS asking_sender
36
+ FROM chosen
37
+ LEFT JOIN conversation_messages said ON said.id = chosen.said
38
+ LEFT JOIN conversation_messages answer ON answer.id = chosen.answer
39
+ LEFT JOIN conversation_messages opened ON opened.id = chosen.opened
40
+ LEFT JOIN conversation_messages asking ON asking.id = chosen.asking`;
9
41
  function text(value) {
10
42
  return typeof value === 'string' ? value : String(value);
11
43
  }
12
- export function heldConversations(connection) {
44
+ export function heldConversations(connection, conversations) {
45
+ const named = conversations === null ? '' : ' AND conversation IN (SELECT value FROM json_each(?))';
46
+ const bound = conversations === null ? [] : [JSON.stringify(conversations)];
13
47
  const held = new Map();
14
- for (const row of connection.rows('SELECT conversation, read, partial FROM conversation_reads')) {
48
+ for (const row of connection.rows(`SELECT conversation, read, partial FROM conversation_reads WHERE 1 = 1${named}`, bound)) {
15
49
  held.set(text(row.conversation), {
16
50
  conversation: text(row.conversation),
17
51
  read: row.read === null ? null : text(row.read),
18
52
  partial: Number(row.partial) === 1,
19
53
  });
20
54
  }
21
- for (const row of connection.rows('SELECT DISTINCT conversation FROM conversation_messages WHERE conversation NOT IN (SELECT conversation FROM conversation_reads)')) {
55
+ for (const row of connection.rows(`SELECT DISTINCT conversation FROM conversation_messages WHERE conversation NOT IN (SELECT conversation FROM conversation_reads)${named}`, bound)) {
22
56
  held.set(text(row.conversation), {
23
57
  conversation: text(row.conversation),
24
58
  read: undefined,
@@ -29,24 +63,15 @@ export function heldConversations(connection) {
29
63
  }
30
64
  export function keptMessages(connection, { conversation, messages, read }) {
31
65
  for (const message of messages) {
32
- const [held] = connection.rows('SELECT id FROM conversation_messages WHERE conversation = ? AND identity = ?', [conversation, message.identity]);
33
- const record = [
66
+ connection.run('INSERT INTO conversation_messages (conversation, identity, turn, position, change, message, text) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT (conversation, identity) DO UPDATE SET turn = excluded.turn, position = excluded.position, change = excluded.change, message = excluded.message, text = excluded.text', [
67
+ conversation,
68
+ message.identity,
34
69
  message.turn,
35
70
  message.position,
71
+ message.change,
36
72
  JSON.stringify(message.message ?? null),
37
73
  message.text,
38
- ];
39
- let id;
40
- if (held === undefined) {
41
- connection.run('INSERT INTO conversation_messages (conversation, identity, turn, position, message, text) VALUES (?, ?, ?, ?, ?, ?)', [conversation, message.identity, ...record]);
42
- id = Number(connection.rows('SELECT last_insert_rowid() AS id')[0].id);
43
- }
44
- else {
45
- id = Number(held.id);
46
- unindexMessages(connection, [id]);
47
- connection.run('UPDATE conversation_messages SET turn = ?, position = ?, message = ?, text = ? WHERE id = ?', [...record, id]);
48
- }
49
- indexMessage(connection, id, message.text);
74
+ ]);
50
75
  }
51
76
  if (read !== undefined) {
52
77
  connection.run('INSERT OR REPLACE INTO conversation_reads (conversation, read, partial) VALUES (?, ?, ?)', [conversation, read.at, read.partial ? 1 : 0]);
@@ -58,31 +83,66 @@ function accepted(row) {
58
83
  identity: text(row.identity),
59
84
  turn: text(row.turn),
60
85
  position: text(row.position),
86
+ change: text(row.change),
61
87
  text: text(row.text),
62
88
  message: JSON.parse(text(row.message)),
63
89
  };
64
90
  }
65
- export function messageWindow(connection, conversation, limit, before) {
66
- const rows = connection.rows(`SELECT identity, turn, position, message, text FROM conversation_messages WHERE conversation = ?${before === null ? '' : ' AND (position < ? OR (position = ? AND identity < ?))'} ORDER BY position DESC, identity DESC LIMIT ?`, before === null
67
- ? [conversation, limit + 1]
68
- : [conversation, before[0], before[0], before[1], limit + 1]);
91
+ function holding(phrase) {
92
+ return phrase === null
93
+ ? { sql: '', bind: [] }
94
+ : { sql: ` AND ${sql.HOLDS_PHRASE}(text, ?)`, bind: [phrase.toLowerCase()] };
95
+ }
96
+ export function messageWindow(connection, conversation, limit, before, phrase) {
97
+ const held = holding(phrase);
98
+ const rows = connection.rows(`SELECT identity, turn, position, change, message, text FROM conversation_messages WHERE conversation = ?${held.sql}${before === null ? '' : ' AND (position < ? OR (position = ? AND identity < ?))'} ORDER BY position DESC, identity DESC LIMIT ?`, before === null
99
+ ? [conversation, ...held.bind, limit + 1]
100
+ : [conversation, ...held.bind, before[0], before[0], before[1], limit + 1]);
69
101
  return { messages: rows.slice(0, limit).map(accepted).reverse(), more: rows.length > limit };
70
102
  }
71
- export function messageCount(connection, conversation) {
72
- const [counted] = connection.rows('SELECT count(*) AS held FROM conversation_messages WHERE conversation = ?', [conversation]);
103
+ export function messageCount(connection, conversation, phrase) {
104
+ const held = holding(phrase);
105
+ const [counted] = connection.rows(`SELECT count(*) AS held FROM conversation_messages WHERE conversation = ?${held.sql}`, [conversation, ...held.bind]);
73
106
  return Number(counted?.held ?? 0);
74
107
  }
108
+ function textOrNull(value) {
109
+ return value === null ? null : text(value);
110
+ }
111
+ function heldSource(source, sender) {
112
+ return {
113
+ source: source === null ? null : JSON.parse(text(source)),
114
+ sender: textOrNull(sender),
115
+ };
116
+ }
117
+ export function conversationRows(connection, conversations) {
118
+ return connection.rows(ROWS, [JSON.stringify(conversations)]).map((row) => ({
119
+ conversation: text(row.conversation),
120
+ said: row.said_text === null
121
+ ? null
122
+ : {
123
+ text: text(row.said_text),
124
+ role: textOrNull(row.said_role),
125
+ at: textOrNull(row.said_at),
126
+ },
127
+ failure: textOrNull(row.failure),
128
+ opened: row.opened_source === null ? null : heldSource(row.opened_source, row.opened_sender),
129
+ asking: row.asking_identity === null
130
+ ? null
131
+ : {
132
+ ...heldSource(row.asking_source, row.asking_sender),
133
+ identity: text(row.asking_identity),
134
+ text: text(row.asking_text),
135
+ at: textOrNull(row.asking_at),
136
+ },
137
+ }));
138
+ }
75
139
  export function turnArrived(connection, conversation, turn) {
76
140
  return (connection.rows('SELECT 1 FROM conversation_messages WHERE conversation = ? AND turn = ? LIMIT 1', [conversation, turn]).length > 0);
77
141
  }
78
142
  export function droppedMessages(connection, conversations) {
79
- for (const conversation of conversations) {
80
- unindexMessages(connection, connection
81
- .rows('SELECT id FROM conversation_messages WHERE conversation = ?', [conversation])
82
- .map((row) => Number(row.id)));
83
- connection.run('DELETE FROM conversation_messages WHERE conversation = ?', [conversation]);
84
- connection.run('DELETE FROM conversation_reads WHERE conversation = ?', [conversation]);
85
- }
143
+ const named = [JSON.stringify(conversations)];
144
+ connection.run('DELETE FROM conversation_messages WHERE conversation IN (SELECT value FROM json_each(?))', named);
145
+ connection.run('DELETE FROM conversation_reads WHERE conversation IN (SELECT value FROM json_each(?))', named);
86
146
  }
87
147
  export function forgottenMessages(connection) {
88
148
  connection.run('DELETE FROM conversation_messages');
package/dist/model.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Definition, ValueFacts, VerifiedModel } from '@agentshouse/mdmodel';
1
+ import type { Definition, VerifiedModel } from '@agentshouse/mdmodel';
2
2
  import type { Open } from './open.js';
3
3
  export type ModelIdentity = {
4
4
  identity: string;
@@ -8,7 +8,7 @@ export type ModelSnapshot = ModelIdentity & {
8
8
  schema: string | null;
9
9
  revision: string | null;
10
10
  };
11
- export type ModelUnavailableReason = Open<'not-readable' | 'revoked' | 'not-acquired' | 'invalid'>;
11
+ export type ModelUnavailableReason = Open<'not-readable' | 'revoked' | 'not-acquired'>;
12
12
  export type ModelResult = {
13
13
  kind: 'model';
14
14
  snapshot: ModelSnapshot;
@@ -20,20 +20,21 @@ export type MdType = Definition;
20
20
  export type ModelState = {
21
21
  status: 'unavailable';
22
22
  reason: ModelUnavailableReason;
23
- schema?: string | null;
24
- revision?: string | null;
25
23
  } | {
26
24
  status: 'current' | 'cached';
27
25
  snapshot: ModelSnapshot;
28
26
  verifiedWith: ModelIdentity;
29
27
  types: VerifiedModel['types'];
30
28
  };
29
+ export type StoredModel = Extract<ModelState, {
30
+ status: 'unavailable';
31
+ }> | Omit<Extract<ModelState, {
32
+ status: 'current' | 'cached';
33
+ }>, 'types'>;
31
34
  export type TypesResult = {
32
35
  status: Open<'unavailable'>;
33
36
  reason: ModelUnavailableReason;
34
37
  types: null;
35
- schema?: string | null;
36
- revision?: string | null;
37
38
  } | {
38
39
  status: Open<'current' | 'cached'>;
39
40
  identity: string;
@@ -49,10 +50,6 @@ export type ValidationReceipt = {
49
50
  source: Open<'current' | 'cached'>;
50
51
  };
51
52
  export declare const NO_MODEL: ModelState;
52
- export declare function definitionOf(state: ModelState, type: string | undefined): Definition | undefined;
53
53
  export declare function modelTypes(state: ModelState): TypesResult;
54
- export declare function cached(state: ModelState): ModelState;
55
- export declare function sameModel(left: ModelIdentity, right: ModelIdentity): boolean;
56
- export declare function sameTyping(left: ModelState, right: ModelState): boolean;
57
- export declare function referenceField(facts: ValueFacts | undefined): boolean;
54
+ export declare function storedModel(state: ModelState): StoredModel;
58
55
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;AACnG,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,UAAU,GAClB;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB;IACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAC5B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;CACpC,CAAC;AACF,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAGhG;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAczD;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E;AACD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CASvE;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAErE"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,cAAc,CAAC,CAAC;AACvF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB,OAAO,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,GAC9C,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACzE,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAC5E;IACE,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;CACpC,CAAC;AACF,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAczD;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAI1D"}
package/dist/model.js CHANGED
@@ -1,9 +1,4 @@
1
1
  export const NO_MODEL = { status: 'unavailable', reason: 'not-acquired' };
2
- export function definitionOf(state, type) {
3
- if (state.status === 'unavailable' || type === undefined)
4
- return undefined;
5
- return Object.hasOwn(state.types, type) ? state.types[type] : undefined;
6
- }
7
2
  export function modelTypes(state) {
8
3
  return state.status === 'unavailable'
9
4
  ? { ...state, types: null }
@@ -17,21 +12,9 @@ export function modelTypes(state) {
17
12
  types: Object.values(state.types).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0),
18
13
  };
19
14
  }
20
- export function cached(state) {
21
- return state.status === 'unavailable' ? state : { ...state, status: 'cached' };
22
- }
23
- export function sameModel(left, right) {
24
- return left.identity === right.identity && left.version === right.version;
25
- }
26
- export function sameTyping(left, right) {
27
- if (left === right)
28
- return true;
29
- if (left.status === 'unavailable' || right.status === 'unavailable') {
30
- return left.status === right.status;
31
- }
32
- return (left.snapshot.schema === right.snapshot.schema &&
33
- sameModel(left.verifiedWith, right.verifiedWith));
34
- }
35
- export function referenceField(facts) {
36
- return facts?.reference !== undefined || facts?.items?.reference !== undefined;
15
+ export function storedModel(state) {
16
+ if (state.status === 'unavailable')
17
+ return state;
18
+ const { types: _types, ...stored } = state;
19
+ return stored;
37
20
  }
@@ -0,0 +1,10 @@
1
+ import type { RoomDeclaration, ScopedRefusal } from './adapter.js';
2
+ import { type ModelState } from './model.js';
3
+ import type { Runtime } from './runtime.js';
4
+ import type { RuntimeStore } from './store.js';
5
+ export declare function revoked(model: ModelState | undefined): boolean;
6
+ export declare function retainModel(runtime: Runtime, locator: string, declaration: RoomDeclaration, given: ModelState | null, refused?: true): Promise<void>;
7
+ export declare function scoped(runtime: Runtime, result: ScopedRefusal, locator: string, declaration: RoomDeclaration): Promise<void>;
8
+ export declare function settleModels(runtime: Runtime, held: ReadonlyMap<string, RoomDeclaration>, status: 'current' | 'cached', local: RuntimeStore): Promise<void>;
9
+ export declare function cachedModels(runtime: Runtime, local: RuntimeStore): Promise<void>;
10
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAOnE,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAGvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAc,YAAY,EAAS,MAAM,YAAY,CAAC;AAMlE,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAE9D;AA0DD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,eAAe,EAC5B,KAAK,EAAE,UAAU,GAAG,IAAI,EACxB,OAAO,CAAC,EAAE,IAAI,iBA2Bf;AAED,wBAAsB,MAAM,CAC1B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,eAAe,iBAoB7B;AAED,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC1C,MAAM,EAAE,SAAS,GAAG,QAAQ,EAC5B,KAAK,EAAE,YAAY,iBA+CpB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBvF"}
package/dist/models.js ADDED
@@ -0,0 +1,156 @@
1
+ import { equalValue } from '@agentshouse/mdmodel';
2
+ import { changeSet } from './change-set.js';
3
+ import { composedOf } from './collection.js';
4
+ import { declared, sameDeclaration } from './declaration.js';
5
+ import { uncaught } from './failure.js';
6
+ import { declarationOf, listedLocators } from './listing.js';
7
+ import { loseRooms } from './lost.js';
8
+ import { NO_MODEL } from './model.js';
9
+ import { settle } from './queue.js';
10
+ import { storedRecord } from './replica.js';
11
+ import { emitRooms } from './shown.js';
12
+ function declaredAsHeld(held, declaration) {
13
+ return held === undefined || sameDeclaration(held.declaration, declaration);
14
+ }
15
+ export function revoked(model) {
16
+ return model?.status === 'unavailable' && model.reason === 'revoked';
17
+ }
18
+ function unheldModelOf({ presence }, locator) {
19
+ return presence.unheldModel(locator) ?? NO_MODEL;
20
+ }
21
+ async function modelNow(runtime, locator) {
22
+ return (await runtime.store.record(locator))?.model ?? unheldModelOf(runtime, locator);
23
+ }
24
+ function restands(held, model, declaration) {
25
+ return (JSON.stringify(held.model) !== JSON.stringify(model) ||
26
+ !equalValue(held.declaration.typedSelection, declaration.typedSelection));
27
+ }
28
+ function recordAlone(store, record) {
29
+ return {
30
+ locator: record.locator,
31
+ key: record.key,
32
+ record: storedRecord(record),
33
+ composed: composedOf(store.composed(record)),
34
+ };
35
+ }
36
+ function unheld(runtime, locator, model) {
37
+ runtime.presence.modelled(locator, model);
38
+ emitRooms(runtime);
39
+ }
40
+ function recorded(runtime, locator, declaration, model) {
41
+ const { store, socket } = runtime;
42
+ return store.exclusive(async () => {
43
+ if (!socket.continuing())
44
+ return;
45
+ const current = await store.record(locator);
46
+ if (current === undefined) {
47
+ unheld(runtime, locator, model);
48
+ return;
49
+ }
50
+ const answer = await (await store.open()).commit({ rooms: [recordAlone(store, { ...current, declaration, model })] });
51
+ void store.changed(changeSet(locator, {
52
+ documents: answer.changed[locator] ?? [],
53
+ room: true,
54
+ unindexed: answer.indexed[locator] === false,
55
+ }));
56
+ });
57
+ }
58
+ export async function retainModel(runtime, locator, declaration, given, refused) {
59
+ const { store, socket } = runtime;
60
+ const held = await store.record(locator);
61
+ const previous = held?.model ?? unheldModelOf(runtime, locator);
62
+ const next = given ?? previous;
63
+ if (JSON.stringify(previous) === JSON.stringify(next) && declaredAsHeld(held, declaration))
64
+ return;
65
+ if (held !== undefined && !restands(held, next, declaration)) {
66
+ await recorded(runtime, locator, declaration, next);
67
+ return;
68
+ }
69
+ await settle(runtime, [locator], async (works) => {
70
+ if (!socket.continuing())
71
+ return [];
72
+ const current = works.get(locator)?.replica;
73
+ if (current === undefined) {
74
+ unheld(runtime, locator, next);
75
+ return [];
76
+ }
77
+ return [
78
+ {
79
+ locator,
80
+ record: { ...current.record, declaration, model: next },
81
+ ...(refused === undefined ? {} : { refused }),
82
+ },
83
+ ];
84
+ });
85
+ }
86
+ export async function scoped(runtime, result, locator, declaration) {
87
+ const { socket, presence, journal } = runtime;
88
+ if (result.scope === 'content' && !result.retryable) {
89
+ journal.record(`scoped refusal ${locator} ${result.scope} ${result.code}`);
90
+ await loseRooms(runtime, [locator]);
91
+ return;
92
+ }
93
+ presence.refused(locator, result);
94
+ if (result.scope === 'model')
95
+ await retainModel(runtime, locator, declaration, { status: 'unavailable', reason: 'not-readable' }, true);
96
+ if (!socket.continuing())
97
+ return;
98
+ emitRooms(runtime);
99
+ journal.record(`scoped refusal ${locator} ${result.scope} ${result.code}`);
100
+ }
101
+ export async function settleModels(runtime, held, status, local) {
102
+ const { store, socket, presence, journal } = runtime;
103
+ const owed = (model) => model.status !== 'unavailable' && model.status !== status;
104
+ const declaredAnew = await store.exclusive(async () => {
105
+ if (!socket.continuing())
106
+ return [];
107
+ const stored = await store.rooms([...held.keys()]);
108
+ const unchanged = [...held].filter(([locator, declaration]) => {
109
+ const record = stored.get(locator)?.record;
110
+ return (owed(record?.model ?? unheldModelOf(runtime, locator)) &&
111
+ declaredAsHeld(record, declaration));
112
+ });
113
+ const records = unchanged.flatMap(([locator]) => {
114
+ const record = stored.get(locator)?.record;
115
+ return record === undefined
116
+ ? []
117
+ : [{ ...record, model: { ...record.model, status } }];
118
+ });
119
+ if (records.length > 0) {
120
+ try {
121
+ await local.commit({ rooms: records.map((record) => recordAlone(store, record)) });
122
+ }
123
+ catch (error) {
124
+ journal.record(`model ${status} persistence failed`);
125
+ uncaught(error);
126
+ }
127
+ }
128
+ for (const [locator] of unchanged) {
129
+ const unheldModel = presence.unheldModel(locator);
130
+ if (!stored.has(locator) && unheldModel !== null) {
131
+ presence.modelled(locator, { ...unheldModel, status });
132
+ }
133
+ }
134
+ if (unchanged.length > 0)
135
+ emitRooms(runtime);
136
+ const kept = new Set(unchanged.map(([locator]) => locator));
137
+ return [...held].filter(([locator]) => !kept.has(locator) &&
138
+ owed(stored.get(locator)?.record.model ?? unheldModelOf(runtime, locator)));
139
+ });
140
+ for (const [locator, declaration] of declaredAnew) {
141
+ const model = await modelNow(runtime, locator);
142
+ if (owed(model))
143
+ await retainModel(runtime, locator, declaration, { ...model, status });
144
+ }
145
+ }
146
+ export async function cachedModels(runtime, local) {
147
+ const { store, presence } = runtime;
148
+ const held = await store.rooms();
149
+ await settleModels(runtime, new Map(listedLocators(runtime, held).flatMap((locator) => {
150
+ const discovered = presence.room(locator);
151
+ const declaration = discovered === undefined
152
+ ? declarationOf(runtime, locator, held.get(locator))?.room
153
+ : declared(discovered);
154
+ return declaration === undefined ? [] : [[locator, declaration]];
155
+ })), 'cached', local);
156
+ }
@@ -27,8 +27,8 @@ export declare function rowsOf(result: QueryResult): readonly (QueryDocument | Q
27
27
  export declare function whole(message: QueryMessage): message is KeyedResult;
28
28
  export declare function applied(keyed: KeyedResult, message: QueryMessage): KeyedResult;
29
29
  export declare function observed(first: unknown, stop: () => void, keyed: boolean): Observed;
30
- export declare function opened(watch: (deliver: (message: unknown) => void) => () => void, keyed: boolean): Promise<Observation<unknown>>;
31
- export declare function observing<Topic extends string>(watch: (topic: Topic, input: readonly unknown[], deliver: (message: unknown) => void) => () => void): (topic: Topic, ...input: unknown[]) => Promise<Observation<unknown>>;
30
+ export declare function opened(watch: (deliver: (message: unknown) => void, fail: (error: unknown) => void) => () => void, keyed: boolean): Promise<Observation<unknown>>;
31
+ export declare function observing<Topic extends string>(watch: (topic: Topic, input: readonly unknown[], deliver: (message: unknown) => void, fail: (error: unknown) => void) => () => void): (topic: Topic, ...input: unknown[]) => Promise<Observation<unknown>>;
32
32
  export type Digest = {
33
33
  readonly pending: string;
34
34
  } | {
@@ -38,6 +38,7 @@ export type Digest = {
38
38
  readonly next: string | undefined;
39
39
  readonly total: number | undefined;
40
40
  };
41
+ export declare function hashed(text: string): number;
41
42
  export declare function digestOf({ result, keys }: KeyedResult): Digest;
42
43
  export declare function digestApplied(digest: Digest, message: QueryMessage): Digest;
43
44
  export declare function changeOf(previous: Digest, next: KeyedResult): QueryMessage | null;
@@ -1 +1 @@
1
- {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"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"}
@@ -90,27 +90,27 @@ export function opened(watch, keyed) {
90
90
  return new Promise((resolve, reject) => {
91
91
  let handle;
92
92
  let stop = () => { };
93
- try {
94
- stop = watch((message) => {
95
- if (handle !== undefined) {
96
- handle.receive(message);
97
- return;
98
- }
99
- handle = observed(message, () => stop(), keyed);
100
- resolve(handle.observation);
101
- });
102
- }
103
- catch (error) {
93
+ stop = watch((message) => {
94
+ if (handle !== undefined) {
95
+ handle.receive(message);
96
+ return;
97
+ }
98
+ handle = observed(message, () => stop(), keyed);
99
+ resolve(handle.observation);
100
+ }, (error) => {
101
+ if (handle !== undefined)
102
+ return;
103
+ stop();
104
104
  reject(error);
105
- }
105
+ });
106
106
  });
107
107
  }
108
108
  export function observing(watch) {
109
- return (topic, ...input) => opened((deliver) => watch(topic, input, (message) => {
109
+ return (topic, ...input) => opened((deliver, fail) => watch(topic, input, (message) => {
110
110
  deliver(structuredClone(message));
111
- }), topic === 'query');
111
+ }, fail), topic === 'query');
112
112
  }
113
- function hashed(text) {
113
+ export function hashed(text) {
114
114
  let first = 0xdeadbeef;
115
115
  let second = 0x41c6ce57;
116
116
  for (let index = 0; index < text.length; index += 1) {
package/dist/opened.d.ts CHANGED
@@ -18,5 +18,5 @@ export type OpenedFiles = {
18
18
  find(name: OpenedName): Promise<KeptBinary | null>;
19
19
  fetch(name: OpenedName, read: () => Promise<BinaryResult>): Promise<KeptResult>;
20
20
  };
21
- export declare function openedFiles(database: RuntimeDatabase, fenced: (locator: string) => boolean): OpenedFiles;
21
+ export declare function openedFiles(database: RuntimeDatabase, lost: (locator: string) => boolean): OpenedFiles;
22
22
  //# sourceMappingURL=opened.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"opened.d.ts","sourceRoot":"","sources":["../src/opened.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAoC,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAErF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAEhF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACjF,CAAC;AAsBF,wBAAgB,WAAW,CACzB,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GACnC,WAAW,CAsFb"}
1
+ {"version":3,"file":"opened.d.ts","sourceRoot":"","sources":["../src/opened.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAoC,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAErF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAEhF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IACnD,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACjF,CAAC;AAsBF,wBAAgB,WAAW,CACzB,QAAQ,EAAE,eAAe,EACzB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,GACjC,WAAW,CAsFb"}
package/dist/opened.js CHANGED
@@ -20,7 +20,7 @@ function taken(chunks, size) {
20
20
  }
21
21
  return part;
22
22
  }
23
- export function openedFiles(database, fenced) {
23
+ export function openedFiles(database, lost) {
24
24
  const fetching = new Map();
25
25
  async function find(name) {
26
26
  const held = await database.ask({ kind: 'opened.find', ...name });
@@ -36,14 +36,14 @@ export function openedFiles(database, fenced) {
36
36
  let part = 0;
37
37
  const write = async (bytes) => {
38
38
  if (!(await database.ask({ kind: 'opened.part', key, part, bytes }))) {
39
- throw new Error('the device no longer keeps this download');
39
+ throw new Error();
40
40
  }
41
41
  part += 1;
42
42
  };
43
43
  try {
44
- if (fenced(name.locator) ||
44
+ if (lost(name.locator) ||
45
45
  !(await database.ask({ kind: 'opened.begin', key, ...name, mediaType }))) {
46
- throw new Error('the device no longer reads this Room');
46
+ throw new Error();
47
47
  }
48
48
  for (;;) {
49
49
  const read = await reader.read();
@@ -61,7 +61,7 @@ export function openedFiles(database, fenced) {
61
61
  await write(taken(chunks, held));
62
62
  const received = hashed.hex();
63
63
  if (sha256 !== undefined && sha256 !== received) {
64
- throw new Error('the bytes are not the file the device asked for');
64
+ throw new Error();
65
65
  }
66
66
  const whole = await database.ask({
67
67
  kind: 'opened.keep',
@@ -0,0 +1,4 @@
1
+ import type { Runtime } from './runtime.js';
2
+ import type { RuntimeStore } from './store.js';
3
+ export declare function open(runtime: Runtime, opened: RuntimeStore): Promise<RuntimeStore>;
4
+ //# sourceMappingURL=opening.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opening.d.ts","sourceRoot":"","sources":["../src/opening.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA2CxF"}
@@ -0,0 +1,59 @@
1
+ import { conversationsOpened } from './conversation.js';
2
+ import { detectStorageLoss, nextGeneration, refusedForSpace } from './durability.js';
3
+ import { uncaught } from './failure.js';
4
+ import { sweep } from './install.js';
5
+ import { eraseFenced } from './lost.js';
6
+ import { prepare } from './preparation.js';
7
+ import { unpair } from './queue.js';
8
+ import { emitRooms, emitStorageLoss, statusShown } from './shown.js';
9
+ export async function open(runtime, opened) {
10
+ const { store, socket, journal, shell, conversations, build, usableWhenHeld } = runtime;
11
+ if (socket.closed())
12
+ throw new Error('runtime closed');
13
+ const interrupted = await opened.fences();
14
+ const kept = shell.generation;
15
+ const storedGeneration = await opened.generation();
16
+ const loss = detectStorageLoss(storedGeneration, kept);
17
+ const generation = nextGeneration(storedGeneration, kept);
18
+ if (generation !== storedGeneration)
19
+ await opened.rememberGeneration(generation);
20
+ if (generation !== kept)
21
+ await shell.keepGeneration(generation);
22
+ if (loss !== null) {
23
+ store.device.set({ storageLoss: loss });
24
+ emitStorageLoss(runtime);
25
+ }
26
+ const held = await opened.opened();
27
+ store.device.set({
28
+ heldWhenOpened: usableWhenHeld.length > 0 && (await opened.covering()).rooms.size > 0,
29
+ });
30
+ try {
31
+ await opened.demote();
32
+ await store.ask({ kind: 'read.builds', build });
33
+ for (const key of held.orphans)
34
+ await opened.release(key);
35
+ }
36
+ catch (error) {
37
+ if (!refusedForSpace(error))
38
+ throw error;
39
+ }
40
+ if (held.erasing || held.orphans.length > 0)
41
+ queueMicrotask(() => sweep(runtime));
42
+ await conversationsOpened(conversations, opened);
43
+ if (interrupted.length > 0) {
44
+ queueMicrotask(() => {
45
+ void eraseFenced(runtime, interrupted).catch((error) => {
46
+ journal.record('erasure failed');
47
+ uncaught(error);
48
+ });
49
+ });
50
+ }
51
+ statusShown(runtime);
52
+ prepare(runtime);
53
+ emitRooms(runtime);
54
+ void unpair(runtime).catch((error) => {
55
+ journal.record('unpair failed');
56
+ uncaught(error);
57
+ });
58
+ return opened;
59
+ }