@agentshouse/mdruntime 0.1.0-alpha.8 → 0.1.0-c436a939f2119

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 (121) hide show
  1. package/AGENTS.md +210 -0
  2. package/README.md +44 -0
  3. package/dist/adapter.d.ts +223 -25
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +2 -3
  6. package/dist/attachment.d.ts +3 -0
  7. package/dist/attachment.d.ts.map +1 -0
  8. package/dist/attachment.js +8 -0
  9. package/dist/bootstrap.d.ts +6 -7
  10. package/dist/bootstrap.d.ts.map +1 -1
  11. package/dist/bootstrap.js +32 -28
  12. package/dist/change-set.d.ts +33 -0
  13. package/dist/change-set.d.ts.map +1 -0
  14. package/dist/change-set.js +87 -0
  15. package/dist/change.d.ts +9 -0
  16. package/dist/change.d.ts.map +1 -1
  17. package/dist/change.js +6 -5
  18. package/dist/client.d.ts +75 -0
  19. package/dist/client.d.ts.map +1 -0
  20. package/dist/client.js +171 -0
  21. package/dist/collection.d.ts +24 -15
  22. package/dist/collection.d.ts.map +1 -1
  23. package/dist/collection.js +69 -77
  24. package/dist/connection.d.ts +79 -36
  25. package/dist/connection.d.ts.map +1 -1
  26. package/dist/connection.js +1699 -953
  27. package/dist/conversation.d.ts +79 -0
  28. package/dist/conversation.d.ts.map +1 -0
  29. package/dist/conversation.js +557 -0
  30. package/dist/durability.d.ts +8 -3
  31. package/dist/durability.d.ts.map +1 -1
  32. package/dist/durability.js +7 -61
  33. package/dist/file.d.ts +20 -0
  34. package/dist/file.d.ts.map +1 -0
  35. package/dist/file.js +126 -0
  36. package/dist/host.d.ts +14 -0
  37. package/dist/host.d.ts.map +1 -0
  38. package/dist/host.js +198 -0
  39. package/dist/identity.d.ts +1 -0
  40. package/dist/identity.d.ts.map +1 -1
  41. package/dist/identity.js +10 -9
  42. package/dist/index.d.ts +14 -9
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +1 -2
  45. package/dist/log.js +5 -6
  46. package/dist/memory.d.ts +17 -2
  47. package/dist/memory.d.ts.map +1 -1
  48. package/dist/memory.js +269 -113
  49. package/dist/model.d.ts +10 -25
  50. package/dist/model.d.ts.map +1 -1
  51. package/dist/model.js +18 -21
  52. package/dist/observation.d.ts +25 -0
  53. package/dist/observation.d.ts.map +1 -0
  54. package/dist/observation.js +85 -0
  55. package/dist/outcome.d.ts +22 -18
  56. package/dist/outcome.d.ts.map +1 -1
  57. package/dist/outcome.js +1 -13
  58. package/dist/overlay.d.ts +9 -2
  59. package/dist/overlay.d.ts.map +1 -1
  60. package/dist/overlay.js +187 -43
  61. package/dist/paths.d.ts +0 -1
  62. package/dist/paths.d.ts.map +1 -1
  63. package/dist/paths.js +12 -19
  64. package/dist/query.d.ts +210 -9
  65. package/dist/query.d.ts.map +1 -1
  66. package/dist/query.js +420 -15
  67. package/dist/read-side.d.ts +14 -0
  68. package/dist/read-side.d.ts.map +1 -0
  69. package/dist/read-side.js +371 -0
  70. package/dist/refresh.d.ts +4 -5
  71. package/dist/refresh.d.ts.map +1 -1
  72. package/dist/refresh.js +45 -30
  73. package/dist/replica.d.ts +27 -6
  74. package/dist/replica.d.ts.map +1 -1
  75. package/dist/replica.js +237 -30
  76. package/dist/room-draft.d.ts +124 -0
  77. package/dist/room-draft.d.ts.map +1 -0
  78. package/dist/room-draft.js +327 -0
  79. package/dist/rows.d.ts +41 -0
  80. package/dist/rows.d.ts.map +1 -0
  81. package/dist/rows.js +100 -0
  82. package/dist/save.d.ts +10 -6
  83. package/dist/save.d.ts.map +1 -1
  84. package/dist/save.js +267 -333
  85. package/dist/search.d.ts +61 -0
  86. package/dist/search.d.ts.map +1 -0
  87. package/dist/search.js +125 -0
  88. package/dist/status.d.ts +9 -2
  89. package/dist/status.d.ts.map +1 -1
  90. package/dist/status.js +11 -14
  91. package/dist/store.d.ts +85 -18
  92. package/dist/store.d.ts.map +1 -1
  93. package/dist/store.js +380 -97
  94. package/dist/transfer.d.ts +5 -0
  95. package/dist/transfer.d.ts.map +1 -1
  96. package/dist/transfer.js +1 -5
  97. package/dist/wire.d.ts +64 -0
  98. package/dist/wire.d.ts.map +1 -0
  99. package/dist/wire.js +124 -0
  100. package/package.json +15 -13
  101. package/dist/adapter.js.map +0 -1
  102. package/dist/bootstrap.js.map +0 -1
  103. package/dist/change.js.map +0 -1
  104. package/dist/collection.js.map +0 -1
  105. package/dist/connection.js.map +0 -1
  106. package/dist/durability.js.map +0 -1
  107. package/dist/identity.js.map +0 -1
  108. package/dist/index.js.map +0 -1
  109. package/dist/log.js.map +0 -1
  110. package/dist/memory.js.map +0 -1
  111. package/dist/model.js.map +0 -1
  112. package/dist/outcome.js.map +0 -1
  113. package/dist/overlay.js.map +0 -1
  114. package/dist/paths.js.map +0 -1
  115. package/dist/query.js.map +0 -1
  116. package/dist/refresh.js.map +0 -1
  117. package/dist/replica.js.map +0 -1
  118. package/dist/save.js.map +0 -1
  119. package/dist/status.js.map +0 -1
  120. package/dist/store.js.map +0 -1
  121. package/dist/transfer.js.map +0 -1
package/dist/memory.js CHANGED
@@ -1,16 +1,15 @@
1
- import { ROOM_CONTRACT_VERSION } from './adapter.js';
1
+ import { ROOM_CONTRACT_VERSION, } from './adapter.js';
2
2
  import { MD_MODEL } from './collection.js';
3
+ import { sameChange } from './overlay.js';
3
4
  const FIXTURE_RETENTION = {
4
- history: {
5
- kind: 'duration',
6
- seconds: 1
7
- },
5
+ history: { kind: 'duration', seconds: 1 },
8
6
  outcome: 1,
9
- refreshHorizon: 1
7
+ refreshHorizon: 1,
10
8
  };
11
9
  function declaredRetention(value) {
12
10
  const retention = value ?? FIXTURE_RETENTION;
13
- if (retention.history.kind === 'no-declared-time-bound') return retention;
11
+ if (retention.history.kind === 'no-declared-time-bound')
12
+ return retention;
14
13
  if (Number.isFinite(retention.history.seconds) && retention.history.seconds > 0) {
15
14
  return retention;
16
15
  }
@@ -18,36 +17,68 @@ function declaredRetention(value) {
18
17
  }
19
18
  function named(source, paths) {
20
19
  const taken = {};
21
- for (const path of paths){
20
+ for (const path of paths) {
22
21
  const value = source[path];
23
- if (value !== undefined) taken[path] = value;
22
+ if (value !== undefined)
23
+ taken[path] = value;
24
24
  }
25
25
  return taken;
26
26
  }
27
27
  async function resolveScript(answer, fallback, request) {
28
- if (answer === undefined) return fallback();
28
+ if (answer === undefined)
29
+ return fallback();
29
30
  return typeof answer === 'function' ? answer(request) : answer;
30
31
  }
31
32
  export function createMemoryAdapter(options = {}) {
32
- let rooms = options.rooms === undefined ? [] : [
33
- ...options.rooms
34
- ];
33
+ let rooms = options.rooms === undefined ? [] : [...options.rooms];
35
34
  const mdModel = options.mdModel ?? MD_MODEL;
36
- const supportedVersions = options.supportedVersions ?? [
37
- ROOM_CONTRACT_VERSION
38
- ];
35
+ const supportedVersions = options.supportedVersions ?? [ROOM_CONTRACT_VERSION];
39
36
  const capabilities = options.capabilities ?? [];
40
37
  const providerLimits = options.providerLimits ?? [];
41
38
  const retention = declaredRetention(options.retention);
42
- const origins = options.origins ?? [
43
- 'https://origin.example'
44
- ];
45
39
  const pageSize = options.pageSize;
46
40
  const scripts = {};
47
41
  const served = new Map();
48
42
  const refreshPages = new Map();
43
+ const observers = new Set();
44
+ const listeners = new Set();
45
+ const modeObservers = new Set();
46
+ const scripted = new Map();
47
+ const unsealed = new Map();
48
+ const sealed = new Set();
49
+ const historyPageSize = options.historyPageSize;
50
+ let selected = [];
51
+ let replicated = [];
52
+ let issued = 0;
53
+ function scriptConversations(entries) {
54
+ scripted.clear();
55
+ for (const entry of entries)
56
+ scripted.set(entry.conversation, entry);
57
+ }
58
+ scriptConversations(options.conversations ?? []);
59
+ const ordinals = new Map();
60
+ function note(locator, answer) {
61
+ const roomVersion = answer.roomVersion;
62
+ const key = `${locator}\u0000${String(roomVersion)}`;
63
+ if (typeof roomVersion === 'string' && !ordinals.has(key))
64
+ ordinals.set(key, ordinals.size);
65
+ return answer;
66
+ }
67
+ function reached(locator, roomVersion, target) {
68
+ const scripted = scripts.reached;
69
+ if (typeof scripted === 'boolean')
70
+ return scripted;
71
+ if (scripted !== undefined)
72
+ return scripted(locator, roomVersion, target);
73
+ if (roomVersion === target)
74
+ return true;
75
+ const held = ordinals.get(`${locator}\u0000${roomVersion}`);
76
+ const wanted = ordinals.get(`${locator}\u0000${target}`);
77
+ return held !== undefined && wanted !== undefined && held >= wanted;
78
+ }
49
79
  function retain(entries) {
50
- for (const room of entries){
80
+ for (const room of entries) {
81
+ note(room.locator, room);
51
82
  const versions = served.get(room.locator) ?? new Map();
52
83
  versions.set(room.roomVersion, room);
53
84
  served.set(room.locator, versions);
@@ -58,12 +89,13 @@ export function createMemoryAdapter(options = {}) {
58
89
  return {
59
90
  name: room.name,
60
91
  locator: room.locator,
61
- collectionRoot: room.collectionRoot,
62
92
  roomVersion: room.roomVersion,
63
93
  operations: room.operations,
64
94
  replica: room.replica,
65
95
  attachedModel: room.attachedModel,
66
- providerOwnedPaths: room.providerOwnedPaths
96
+ ...(room.typedSelection === undefined ? {} : { typedSelection: room.typedSelection }),
97
+ ...(room.untypedFolders === undefined ? {} : { untypedFolders: room.untypedFolders }),
98
+ providerOwnedPaths: room.providerOwnedPaths,
67
99
  };
68
100
  }
69
101
  function page(room, from) {
@@ -71,15 +103,16 @@ export function createMemoryAdapter(options = {}) {
71
103
  const size = pageSize ?? paths.length;
72
104
  const taken = paths.slice(from, from + size);
73
105
  const next = from + taken.length;
106
+ const targets = from === 0 ? (room.binaryTargets ?? []) : [];
74
107
  return {
75
108
  kind: 'bootstrap',
76
109
  roomVersion: room.roomVersion,
77
110
  documents: named(room.documents ?? {}, taken),
78
111
  revisions: named(room.revisions ?? {}, taken),
79
- binaryTargets: from === 0 ? room.binaryTargets ?? [] : [],
80
- ...next < paths.length ? {
81
- pageToken: String(next)
82
- } : {}
112
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
113
+ binaryTargets: targets,
114
+ ...(from === 0 && room.attachments !== undefined ? { attachments: room.attachments } : {}),
115
+ ...(next < paths.length ? { pageToken: String(next) } : {}),
83
116
  };
84
117
  }
85
118
  function advancement(room, from, at) {
@@ -87,36 +120,108 @@ export function createMemoryAdapter(options = {}) {
87
120
  const previous = from.documents ?? {};
88
121
  const currentTargets = new Set(room.binaryTargets ?? []);
89
122
  const previousTargets = new Set(from.binaryTargets ?? []);
90
- const changed = Object.keys(current).filter((path)=>current[path] !== previous[path]).sort();
123
+ const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
124
+ !sameChange(room.changes?.[path], from.changes?.[path]);
125
+ const changed = Object.keys(current)
126
+ .filter((path) => current[path] !== previous[path] || headMoved(path))
127
+ .sort();
91
128
  const size = pageSize ?? changed.length;
92
129
  const taken = changed.slice(at, at + size);
93
130
  const next = at + taken.length;
94
131
  const opening = at === 0;
95
132
  const pageToken = next < changed.length ? `refresh-${refreshPages.size}` : undefined;
96
- if (pageToken !== undefined) refreshPages.set(pageToken, {
97
- room,
98
- from,
99
- at: next
100
- });
133
+ if (pageToken !== undefined)
134
+ refreshPages.set(pageToken, { room, from, at: next });
135
+ const targets = opening
136
+ ? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
137
+ : [];
138
+ const attachments = room.attachments ?? [];
139
+ const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
101
140
  return {
102
141
  kind: 'net-advancement',
103
142
  roomVersion: room.roomVersion,
104
143
  documents: named(current, taken),
105
144
  revisions: named(room.revisions ?? {}, taken),
106
- binaryTargets: opening ? [
107
- ...currentTargets
108
- ].filter((target)=>!previousTargets.has(target)) : [],
109
- removals: opening ? [
110
- ...Object.keys(previous).filter((path)=>!(path in current) && !currentTargets.has(path)),
111
- ...[
112
- ...previousTargets
113
- ].filter((target)=>!currentTargets.has(target) && !(target in current))
114
- ].sort() : [],
115
- ...pageToken === undefined ? {} : {
116
- pageToken
117
- }
145
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
146
+ binaryTargets: targets,
147
+ removals: opening
148
+ ? [
149
+ ...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
150
+ ...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
151
+ ].sort()
152
+ : [],
153
+ ...(declared ? { attachments } : {}),
154
+ ...(pageToken === undefined ? {} : { pageToken }),
118
155
  };
119
156
  }
157
+ function pageOf(conversation, after) {
158
+ const messages = conversation.messages ?? [];
159
+ const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
160
+ const from = first === -1 ? messages.length : first;
161
+ const page = messages.slice(from, from + (historyPageSize ?? messages.length));
162
+ const last = page.at(-1);
163
+ return {
164
+ conversation: conversation.conversation,
165
+ messages: page,
166
+ ...(last !== undefined && from + page.length < messages.length
167
+ ? { next: last.position }
168
+ : {}),
169
+ };
170
+ }
171
+ function historiesOf(input) {
172
+ const asked = input?.conversations;
173
+ if (!Array.isArray(asked))
174
+ return { kind: 'rejected', code: 'invalid_request', fields: {} };
175
+ const histories = [];
176
+ for (const entry of asked) {
177
+ const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
178
+ if (conversation === undefined)
179
+ continue;
180
+ const outcome = conversation.outcomes?.['conversation.history'];
181
+ if (outcome !== undefined)
182
+ return outcome;
183
+ histories.push(pageOf(conversation, entry.after));
184
+ }
185
+ const result = { histories };
186
+ return { kind: 'action', result };
187
+ }
188
+ function conversationAction(request) {
189
+ const name = request.name;
190
+ const input = (request.input ?? {});
191
+ if (name === 'conversation.history')
192
+ return historiesOf(request.input);
193
+ if (name === 'conversation.create') {
194
+ issued += 1;
195
+ const conversation = `conversation-${issued}`;
196
+ scripted.set(conversation, { conversation });
197
+ return { kind: 'action', result: { conversation } };
198
+ }
199
+ const named = typeof input.conversation === 'string' ? input.conversation : '';
200
+ const conversation = scripted.get(named);
201
+ if (conversation === undefined) {
202
+ return { kind: 'rejected', code: 'unknown-conversation', fields: { conversation: named } };
203
+ }
204
+ const outcome = conversation.outcomes?.[name];
205
+ if (outcome !== undefined)
206
+ return outcome;
207
+ if (name === 'conversation.send') {
208
+ issued += 1;
209
+ const turn = `turn-${issued}`;
210
+ unsealed.set(turn, named);
211
+ return { kind: 'action', result: { turn } };
212
+ }
213
+ if (name === 'conversation.cancel') {
214
+ const turn = typeof input.turn === 'string' ? input.turn : '';
215
+ if (sealed.has(turn) || !unsealed.has(turn)) {
216
+ return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
217
+ }
218
+ unsealed.delete(turn);
219
+ return { kind: 'action', result: { turn, cancelled: true } };
220
+ }
221
+ if (name === 'conversation.delete')
222
+ scripted.delete(named);
223
+ return { kind: 'action', result: { conversation: named } };
224
+ }
120
225
  function discovery() {
121
226
  return {
122
227
  kind: 'discovery',
@@ -126,110 +231,161 @@ export function createMemoryAdapter(options = {}) {
126
231
  capabilities,
127
232
  providerLimits,
128
233
  retention,
129
- origins
130
234
  };
131
235
  }
132
236
  return {
133
- setRooms (next) {
134
- rooms = [
135
- ...next
136
- ];
237
+ setRooms(next) {
238
+ rooms = [...next];
137
239
  retain(rooms);
138
240
  },
139
- script (operation, answer) {
140
- if (answer === undefined) delete scripts[operation];
141
- else scripts[operation] = answer;
241
+ setConversations(next) {
242
+ scriptConversations(next);
243
+ },
244
+ notifyRoomVersion(notification) {
245
+ for (const observer of observers)
246
+ observer(notification);
142
247
  },
143
- async model (_authorization, request) {
144
- return resolveScript(scripts.model, ()=>rooms.find((room)=>room.locator === request.locator)?.model ?? {
145
- kind: 'model-unavailable',
146
- reason: 'not-readable'
147
- }, request);
248
+ notifyConversation(event) {
249
+ if (event.kind === 'accepted-message') {
250
+ sealed.add(event.message.turn);
251
+ unsealed.delete(event.message.turn);
252
+ }
253
+ for (const listener of listeners)
254
+ listener(event);
148
255
  },
149
- async authorize () {
150
- return resolveScript(scripts.authorize, ()=>({}), undefined);
256
+ notifyServiceMode(mode) {
257
+ for (const observer of modeObservers)
258
+ observer(mode);
151
259
  },
152
- async discover (_authorization) {
153
- return resolveScript(scripts.discover, discovery, undefined);
260
+ selectedRooms() {
261
+ return selected;
154
262
  },
155
- async bootstrap (_authorization, request) {
156
- return resolveScript(scripts.bootstrap, ()=>{
157
- const room = rooms.find((entry)=>entry.locator === request.locator);
263
+ replicatedConversations() {
264
+ return replicated;
265
+ },
266
+ conversations: {
267
+ replicate(next) {
268
+ replicated = [...next];
269
+ },
270
+ observe(notify) {
271
+ listeners.add(notify);
272
+ return () => {
273
+ listeners.delete(notify);
274
+ };
275
+ },
276
+ },
277
+ serviceMode: {
278
+ observe(notify) {
279
+ modeObservers.add(notify);
280
+ return () => {
281
+ modeObservers.delete(notify);
282
+ };
283
+ },
284
+ },
285
+ roomVersions: {
286
+ select(locators) {
287
+ selected = [...locators];
288
+ },
289
+ observe(notify) {
290
+ observers.add(notify);
291
+ return () => {
292
+ observers.delete(notify);
293
+ };
294
+ },
295
+ },
296
+ script(operation, answer) {
297
+ if (answer === undefined)
298
+ delete scripts[operation];
299
+ else
300
+ scripts[operation] = answer;
301
+ },
302
+ async model(_authorization, request) {
303
+ return resolveScript(scripts.model, () => {
304
+ const room = rooms.find((entry) => entry.locator === request.locator);
305
+ const answer = request.attached === 'collection' ? room?.model : room?.selectionModel;
306
+ return answer ?? { kind: 'model-unavailable', reason: 'not-readable' };
307
+ }, request);
308
+ },
309
+ async authorize() {
310
+ return resolveScript(scripts.authorize, () => ({}), undefined);
311
+ },
312
+ async discover(_authorization) {
313
+ return resolveScript(scripts.discover, discovery, undefined).then((answer) => {
314
+ if (answer.kind === 'discovery')
315
+ for (const room of answer.rooms)
316
+ note(room.locator, room);
317
+ return answer;
318
+ });
319
+ },
320
+ reached,
321
+ async bootstrap(_authorization, request) {
322
+ return resolveScript(scripts.bootstrap, () => {
323
+ const room = rooms.find((entry) => entry.locator === request.locator);
158
324
  if (room === undefined) {
159
- return {
160
- kind: 'room-not-readable',
161
- locator: request.locator
162
- };
325
+ return { kind: 'room-not-readable', locator: request.locator };
163
326
  }
164
327
  return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));
165
- }, request);
328
+ }, request).then((answer) => note(request.locator, answer));
166
329
  },
167
- async refresh (_authorization, request) {
168
- return resolveScript(scripts.refresh, ()=>{
169
- const room = rooms.find((entry)=>entry.locator === request.locator);
330
+ async refresh(_authorization, request) {
331
+ return resolveScript(scripts.refresh, () => {
332
+ const room = rooms.find((entry) => entry.locator === request.locator);
170
333
  if (room === undefined) {
171
- return {
172
- kind: 'room-not-readable',
173
- locator: request.locator
174
- };
334
+ return { kind: 'room-not-readable', locator: request.locator };
175
335
  }
176
336
  if (request.pageToken !== undefined) {
177
337
  const continuation = refreshPages.get(request.pageToken);
178
- if (continuation === undefined || continuation.room.locator !== request.locator || continuation.from.roomVersion !== request.fromRoomVersion) {
338
+ if (continuation === undefined ||
339
+ continuation.room.locator !== request.locator ||
340
+ continuation.from.roomVersion !== request.fromRoomVersion) {
179
341
  throw new Error('Invalid Refresh Page Token');
180
342
  }
181
343
  return advancement(continuation.room, continuation.from, continuation.at);
182
344
  }
345
+ if (request.minPosition !== undefined &&
346
+ !reached(room.locator, room.roomVersion, request.minPosition)) {
347
+ return { kind: 'retryable-refusal', code: 'replica_behind', fields: {} };
348
+ }
183
349
  if (request.fromRoomVersion === room.roomVersion) {
184
- return {
185
- kind: 'still-current'
186
- };
350
+ return { kind: 'still-current' };
187
351
  }
188
352
  const from = served.get(room.locator)?.get(request.fromRoomVersion);
189
- if (from === undefined) return {
190
- kind: 'beyond-horizon'
191
- };
353
+ if (from === undefined)
354
+ return { kind: 'beyond-horizon' };
192
355
  return advancement(room, from, 0);
193
- }, request);
356
+ }, request).then((answer) => note(request.locator, answer));
194
357
  },
195
- async mutate (_authorization, request) {
196
- return resolveScript(scripts.mutate, ()=>{
197
- const room = rooms.find((entry)=>entry.locator === request.locator);
358
+ async mutate(_authorization, request) {
359
+ return resolveScript(scripts.mutate, () => {
360
+ const room = rooms.find((entry) => entry.locator === request.locator);
198
361
  if (room === undefined) {
199
- return {
200
- kind: 'room-not-readable',
201
- locator: request.locator
202
- };
362
+ return { kind: 'room-not-readable', locator: request.locator };
203
363
  }
204
- return {
205
- kind: 'rejected',
206
- text: '',
207
- affected: {}
208
- };
209
- }, request);
364
+ return { kind: 'rejected', code: 'unscripted-mutation', fields: {}, affected: {} };
365
+ }, request).then((answer) => note(request.locator, answer));
210
366
  },
211
- async history (_authorization, request) {
212
- return resolveScript(scripts.history, ()=>{
213
- const room = rooms.find((entry)=>entry.locator === request.locator);
367
+ async history(_authorization, request) {
368
+ return resolveScript(scripts.history, () => {
369
+ const room = rooms.find((entry) => entry.locator === request.locator);
214
370
  if (room === undefined) {
215
- return {
216
- kind: 'room-not-readable',
217
- locator: request.locator
218
- };
371
+ return { kind: 'room-not-readable', locator: request.locator };
219
372
  }
220
373
  return {
221
374
  kind: 'history',
222
- revisions: []
375
+ revisions: [],
223
376
  };
224
377
  }, request);
225
378
  },
226
- async action (_authorization, request) {
227
- return resolveScript(scripts.action, ()=>({
228
- kind: 'rejected',
229
- text: ''
230
- }), request);
231
- }
379
+ async action(_authorization, request) {
380
+ return resolveScript(scripts.action, () => {
381
+ if (request.name.startsWith('conversation.'))
382
+ return conversationAction(request);
383
+ return { kind: 'rejected', code: 'unscripted-action', fields: {} };
384
+ }, request).then((answer) => {
385
+ if (answer.kind === 'action' && answer.at !== undefined)
386
+ note(answer.at.locator, answer.at);
387
+ return answer;
388
+ });
389
+ },
232
390
  };
233
391
  }
234
-
235
- //# sourceMappingURL=memory.js.map
package/dist/model.d.ts CHANGED
@@ -1,13 +1,12 @@
1
- import type { Validation } from '@agentshouse/mdmodel';
2
- import type { MdType } from './collection.js';
1
+ import type { Definition, FieldSpec, SectionSpec, VerifiedModel } from '@agentshouse/mdmodel';
3
2
  export type ModelIdentity = {
4
3
  identity: string;
5
4
  version: string;
6
5
  };
7
6
  export type ModelSnapshot = ModelIdentity & {
8
- definitions: Readonly<Record<string, string>>;
7
+ schema: string | null;
9
8
  };
10
- export type ModelUnavailableReason = 'not-readable' | 'revoked' | 'not-acquired' | 'version-changed' | 'invalid' | 'binding-unavailable';
9
+ export type ModelUnavailableReason = 'not-readable' | 'revoked' | 'not-acquired' | 'version-changed' | 'invalid';
11
10
  export type ModelResult = {
12
11
  kind: 'model';
13
12
  snapshot: ModelSnapshot;
@@ -19,6 +18,11 @@ export type ModelResult = {
19
18
  } | {
20
19
  kind: 'revoked-authorization';
21
20
  };
21
+ export type MdType = {
22
+ name: string;
23
+ fields: Readonly<Record<string, FieldSpec>>;
24
+ sections: Readonly<Record<string, SectionSpec>>;
25
+ };
22
26
  export type ModelState = {
23
27
  status: 'unavailable';
24
28
  reason: ModelUnavailableReason;
@@ -26,7 +30,7 @@ export type ModelState = {
26
30
  status: 'current' | 'cached';
27
31
  snapshot: ModelSnapshot;
28
32
  verifiedWith: ModelIdentity;
29
- types: readonly MdType[];
33
+ types: VerifiedModel['types'];
30
34
  };
31
35
  export type TypesResult = {
32
36
  status: 'unavailable';
@@ -38,32 +42,13 @@ export type TypesResult = {
38
42
  verifiedWith: ModelIdentity;
39
43
  types: readonly MdType[];
40
44
  };
41
- export type ModelValidation = {
42
- verdict: 'accept';
43
- } | (Extract<Validation, {
44
- verdict: 'refuse';
45
- }> & {
46
- source: 'content' | 'model';
47
- });
48
- export type AttachedModelBinding = {
49
- verify(snapshot: ModelSnapshot): {
50
- kind: 'verified';
51
- types: readonly MdType[];
52
- } | {
53
- kind: 'invalid';
54
- };
55
- validate(input: {
56
- model: ModelSnapshot;
57
- documents: Readonly<Record<string, string>>;
58
- binaryTargets: readonly string[];
59
- }): ModelValidation;
60
- };
61
45
  export type ValidationReceipt = {
62
46
  identity: string;
63
47
  version: string;
64
48
  source: 'current' | 'cached';
65
49
  };
66
50
  export declare const NO_MODEL: ModelState;
51
+ export declare function definitionOf(state: ModelState, type: string | undefined): Definition | undefined;
67
52
  export declare function modelTypes(state: ModelState): TypesResult;
68
53
  export declare function cached(state: ModelState): ModelState;
69
54
  export declare function sameModel(left: ModelIdentity, right: ModelIdentity): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,CAAC;AAC9F,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,SAAS,GACT,qBAAqB,CAAC;AAC1B,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,GAC7D;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,CAAC;AACtC,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,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AACN,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,GACrB,CAAC,OAAO,CAAC,UAAU,EAAE;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC,GAAG;IAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAA;CAAE,CAAC,CAAC;AACnF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,CACJ,QAAQ,EAAE,aAAa,GACtB;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;IACxE,QAAQ,CAAC,KAAK,EAAE;QACd,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5C,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;KAClC,GAAG,eAAe,CAAC;CACrB,CAAC;AACF,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC;AACpG,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAUzD;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE9F,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,CAAA;CAAE,CAAC;AACtE,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,SAAS,CAAC;AACd,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,GAC7D;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,CAAC;AACtC,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAC5C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACjD,CAAC;AACF,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;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC;AACpG,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"}
package/dist/model.js CHANGED
@@ -1,28 +1,25 @@
1
- export const NO_MODEL = {
2
- status: 'unavailable',
3
- reason: 'not-acquired'
4
- };
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
+ }
5
7
  export function modelTypes(state) {
6
- return state.status === 'unavailable' ? {
7
- ...state
8
- } : {
9
- status: state.status,
10
- identity: state.snapshot.identity,
11
- version: state.snapshot.version,
12
- verifiedWith: {
13
- ...state.verifiedWith
14
- },
15
- types: structuredClone(state.types)
16
- };
8
+ return state.status === 'unavailable'
9
+ ? { ...state }
10
+ : {
11
+ status: state.status,
12
+ identity: state.snapshot.identity,
13
+ version: state.snapshot.version,
14
+ verifiedWith: { ...state.verifiedWith },
15
+ types: structuredClone(Object.values(state.types)
16
+ .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0))
17
+ .map(({ name, fields, sections }) => ({ name, fields, sections }))),
18
+ };
17
19
  }
18
20
  export function cached(state) {
19
- return state.status === 'unavailable' ? state : {
20
- ...state,
21
- status: 'cached'
22
- };
21
+ return state.status === 'unavailable' ? state : { ...state, status: 'cached' };
23
22
  }
24
23
  export function sameModel(left, right) {
25
24
  return left.identity === right.identity && left.version === right.version;
26
25
  }
27
-
28
- //# sourceMappingURL=model.js.map
@@ -0,0 +1,25 @@
1
+ import type { QueryDocument, QueryGroup, QueryResult } from './query.js';
2
+ export type Observation<T> = {
3
+ current(): T;
4
+ subscribe(listener: (value: T) => void): () => void;
5
+ close(): void;
6
+ };
7
+ export type RowKey = string | number;
8
+ export type KeyedResult = {
9
+ result: QueryResult;
10
+ keys: readonly RowKey[];
11
+ };
12
+ export type QueryChange = {
13
+ changed: readonly (readonly [RowKey, QueryDocument | QueryGroup])[];
14
+ removed: readonly RowKey[];
15
+ order: readonly RowKey[] | null;
16
+ };
17
+ export type Observed = {
18
+ observation: Observation<unknown>;
19
+ receive(message: unknown): void;
20
+ end(): void;
21
+ };
22
+ export declare function rowsOf(result: QueryResult): readonly (QueryDocument | QueryGroup)[];
23
+ export declare function observed(first: unknown, stop: () => void, keyed: boolean): Observed;
24
+ export declare function opened(watch: (deliver: (message: unknown) => void) => () => void, keyed: boolean): Promise<Observation<unknown>>;
25
+ //# sourceMappingURL=observation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,OAAO,IAAI,CAAC,CAAC;IACb,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACpD,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC;IACpE,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,GAAG,IAAI,IAAI,CAAC;CACb,CAAC;AAEF,wBAAgB,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC,aAAa,GAAG,UAAU,CAAC,EAAE,CAEnF;AA0BD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAkCnF;AAED,wBAAgB,MAAM,CACpB,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,MAAM,IAAI,EAC1D,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAiB/B"}