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

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 +208 -0
  2. package/README.md +44 -0
  3. package/dist/adapter.d.ts +215 -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 +31 -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 +83 -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 +69 -0
  19. package/dist/client.d.ts.map +1 -0
  20. package/dist/client.js +165 -0
  21. package/dist/collection.d.ts +22 -15
  22. package/dist/collection.d.ts.map +1 -1
  23. package/dist/collection.js +60 -78
  24. package/dist/connection.d.ts +68 -40
  25. package/dist/connection.d.ts.map +1 -1
  26. package/dist/connection.js +1597 -961
  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 +13 -0
  37. package/dist/host.d.ts.map +1 -0
  38. package/dist/host.js +175 -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 -10
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +1 -3
  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 +268 -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 +12 -24
  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 +233 -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 +266 -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 +75 -18
  92. package/dist/store.d.ts.map +1 -1
  93. package/dist/store.js +358 -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 +118 -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,12 @@ 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
+ providerOwnedPaths: room.providerOwnedPaths,
67
98
  };
68
99
  }
69
100
  function page(room, from) {
@@ -71,15 +102,16 @@ export function createMemoryAdapter(options = {}) {
71
102
  const size = pageSize ?? paths.length;
72
103
  const taken = paths.slice(from, from + size);
73
104
  const next = from + taken.length;
105
+ const targets = from === 0 ? (room.binaryTargets ?? []) : [];
74
106
  return {
75
107
  kind: 'bootstrap',
76
108
  roomVersion: room.roomVersion,
77
109
  documents: named(room.documents ?? {}, taken),
78
110
  revisions: named(room.revisions ?? {}, taken),
79
- binaryTargets: from === 0 ? room.binaryTargets ?? [] : [],
80
- ...next < paths.length ? {
81
- pageToken: String(next)
82
- } : {}
111
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
112
+ binaryTargets: targets,
113
+ ...(from === 0 && room.attachments !== undefined ? { attachments: room.attachments } : {}),
114
+ ...(next < paths.length ? { pageToken: String(next) } : {}),
83
115
  };
84
116
  }
85
117
  function advancement(room, from, at) {
@@ -87,36 +119,108 @@ export function createMemoryAdapter(options = {}) {
87
119
  const previous = from.documents ?? {};
88
120
  const currentTargets = new Set(room.binaryTargets ?? []);
89
121
  const previousTargets = new Set(from.binaryTargets ?? []);
90
- const changed = Object.keys(current).filter((path)=>current[path] !== previous[path]).sort();
122
+ const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
123
+ !sameChange(room.changes?.[path], from.changes?.[path]);
124
+ const changed = Object.keys(current)
125
+ .filter((path) => current[path] !== previous[path] || headMoved(path))
126
+ .sort();
91
127
  const size = pageSize ?? changed.length;
92
128
  const taken = changed.slice(at, at + size);
93
129
  const next = at + taken.length;
94
130
  const opening = at === 0;
95
131
  const pageToken = next < changed.length ? `refresh-${refreshPages.size}` : undefined;
96
- if (pageToken !== undefined) refreshPages.set(pageToken, {
97
- room,
98
- from,
99
- at: next
100
- });
132
+ if (pageToken !== undefined)
133
+ refreshPages.set(pageToken, { room, from, at: next });
134
+ const targets = opening
135
+ ? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
136
+ : [];
137
+ const attachments = room.attachments ?? [];
138
+ const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
101
139
  return {
102
140
  kind: 'net-advancement',
103
141
  roomVersion: room.roomVersion,
104
142
  documents: named(current, taken),
105
143
  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
- }
144
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
145
+ binaryTargets: targets,
146
+ removals: opening
147
+ ? [
148
+ ...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
149
+ ...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
150
+ ].sort()
151
+ : [],
152
+ ...(declared ? { attachments } : {}),
153
+ ...(pageToken === undefined ? {} : { pageToken }),
118
154
  };
119
155
  }
156
+ function pageOf(conversation, after) {
157
+ const messages = conversation.messages ?? [];
158
+ const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
159
+ const from = first === -1 ? messages.length : first;
160
+ const page = messages.slice(from, from + (historyPageSize ?? messages.length));
161
+ const last = page.at(-1);
162
+ return {
163
+ conversation: conversation.conversation,
164
+ messages: page,
165
+ ...(last !== undefined && from + page.length < messages.length
166
+ ? { next: last.position }
167
+ : {}),
168
+ };
169
+ }
170
+ function historiesOf(input) {
171
+ const asked = input?.conversations;
172
+ if (!Array.isArray(asked))
173
+ return { kind: 'rejected', code: 'invalid_request', fields: {} };
174
+ const histories = [];
175
+ for (const entry of asked) {
176
+ const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
177
+ if (conversation === undefined)
178
+ continue;
179
+ const outcome = conversation.outcomes?.['conversation.history'];
180
+ if (outcome !== undefined)
181
+ return outcome;
182
+ histories.push(pageOf(conversation, entry.after));
183
+ }
184
+ const result = { histories };
185
+ return { kind: 'action', result };
186
+ }
187
+ function conversationAction(request) {
188
+ const name = request.name;
189
+ const input = (request.input ?? {});
190
+ if (name === 'conversation.history')
191
+ return historiesOf(request.input);
192
+ if (name === 'conversation.create') {
193
+ issued += 1;
194
+ const conversation = `conversation-${issued}`;
195
+ scripted.set(conversation, { conversation });
196
+ return { kind: 'action', result: { conversation } };
197
+ }
198
+ const named = typeof input.conversation === 'string' ? input.conversation : '';
199
+ const conversation = scripted.get(named);
200
+ if (conversation === undefined) {
201
+ return { kind: 'rejected', code: 'unknown-conversation', fields: { conversation: named } };
202
+ }
203
+ const outcome = conversation.outcomes?.[name];
204
+ if (outcome !== undefined)
205
+ return outcome;
206
+ if (name === 'conversation.send') {
207
+ issued += 1;
208
+ const turn = `turn-${issued}`;
209
+ unsealed.set(turn, named);
210
+ return { kind: 'action', result: { turn } };
211
+ }
212
+ if (name === 'conversation.cancel') {
213
+ const turn = typeof input.turn === 'string' ? input.turn : '';
214
+ if (sealed.has(turn) || !unsealed.has(turn)) {
215
+ return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
216
+ }
217
+ unsealed.delete(turn);
218
+ return { kind: 'action', result: { turn, cancelled: true } };
219
+ }
220
+ if (name === 'conversation.delete')
221
+ scripted.delete(named);
222
+ return { kind: 'action', result: { conversation: named } };
223
+ }
120
224
  function discovery() {
121
225
  return {
122
226
  kind: 'discovery',
@@ -126,110 +230,161 @@ export function createMemoryAdapter(options = {}) {
126
230
  capabilities,
127
231
  providerLimits,
128
232
  retention,
129
- origins
130
233
  };
131
234
  }
132
235
  return {
133
- setRooms (next) {
134
- rooms = [
135
- ...next
136
- ];
236
+ setRooms(next) {
237
+ rooms = [...next];
137
238
  retain(rooms);
138
239
  },
139
- script (operation, answer) {
140
- if (answer === undefined) delete scripts[operation];
141
- else scripts[operation] = answer;
240
+ setConversations(next) {
241
+ scriptConversations(next);
242
+ },
243
+ notifyRoomVersion(notification) {
244
+ for (const observer of observers)
245
+ observer(notification);
142
246
  },
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);
247
+ notifyConversation(event) {
248
+ if (event.kind === 'accepted-message') {
249
+ sealed.add(event.message.turn);
250
+ unsealed.delete(event.message.turn);
251
+ }
252
+ for (const listener of listeners)
253
+ listener(event);
148
254
  },
149
- async authorize () {
150
- return resolveScript(scripts.authorize, ()=>({}), undefined);
255
+ notifyServiceMode(mode) {
256
+ for (const observer of modeObservers)
257
+ observer(mode);
151
258
  },
152
- async discover (_authorization) {
153
- return resolveScript(scripts.discover, discovery, undefined);
259
+ selectedRooms() {
260
+ return selected;
154
261
  },
155
- async bootstrap (_authorization, request) {
156
- return resolveScript(scripts.bootstrap, ()=>{
157
- const room = rooms.find((entry)=>entry.locator === request.locator);
262
+ replicatedConversations() {
263
+ return replicated;
264
+ },
265
+ conversations: {
266
+ replicate(next) {
267
+ replicated = [...next];
268
+ },
269
+ observe(notify) {
270
+ listeners.add(notify);
271
+ return () => {
272
+ listeners.delete(notify);
273
+ };
274
+ },
275
+ },
276
+ serviceMode: {
277
+ observe(notify) {
278
+ modeObservers.add(notify);
279
+ return () => {
280
+ modeObservers.delete(notify);
281
+ };
282
+ },
283
+ },
284
+ roomVersions: {
285
+ select(locators) {
286
+ selected = [...locators];
287
+ },
288
+ observe(notify) {
289
+ observers.add(notify);
290
+ return () => {
291
+ observers.delete(notify);
292
+ };
293
+ },
294
+ },
295
+ script(operation, answer) {
296
+ if (answer === undefined)
297
+ delete scripts[operation];
298
+ else
299
+ scripts[operation] = answer;
300
+ },
301
+ async model(_authorization, request) {
302
+ return resolveScript(scripts.model, () => {
303
+ const room = rooms.find((entry) => entry.locator === request.locator);
304
+ const answer = request.attached === 'collection' ? room?.model : room?.selectionModel;
305
+ return answer ?? { kind: 'model-unavailable', reason: 'not-readable' };
306
+ }, request);
307
+ },
308
+ async authorize() {
309
+ return resolveScript(scripts.authorize, () => ({}), undefined);
310
+ },
311
+ async discover(_authorization) {
312
+ return resolveScript(scripts.discover, discovery, undefined).then((answer) => {
313
+ if (answer.kind === 'discovery')
314
+ for (const room of answer.rooms)
315
+ note(room.locator, room);
316
+ return answer;
317
+ });
318
+ },
319
+ reached,
320
+ async bootstrap(_authorization, request) {
321
+ return resolveScript(scripts.bootstrap, () => {
322
+ const room = rooms.find((entry) => entry.locator === request.locator);
158
323
  if (room === undefined) {
159
- return {
160
- kind: 'room-not-readable',
161
- locator: request.locator
162
- };
324
+ return { kind: 'room-not-readable', locator: request.locator };
163
325
  }
164
326
  return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));
165
- }, request);
327
+ }, request).then((answer) => note(request.locator, answer));
166
328
  },
167
- async refresh (_authorization, request) {
168
- return resolveScript(scripts.refresh, ()=>{
169
- const room = rooms.find((entry)=>entry.locator === request.locator);
329
+ async refresh(_authorization, request) {
330
+ return resolveScript(scripts.refresh, () => {
331
+ const room = rooms.find((entry) => entry.locator === request.locator);
170
332
  if (room === undefined) {
171
- return {
172
- kind: 'room-not-readable',
173
- locator: request.locator
174
- };
333
+ return { kind: 'room-not-readable', locator: request.locator };
175
334
  }
176
335
  if (request.pageToken !== undefined) {
177
336
  const continuation = refreshPages.get(request.pageToken);
178
- if (continuation === undefined || continuation.room.locator !== request.locator || continuation.from.roomVersion !== request.fromRoomVersion) {
337
+ if (continuation === undefined ||
338
+ continuation.room.locator !== request.locator ||
339
+ continuation.from.roomVersion !== request.fromRoomVersion) {
179
340
  throw new Error('Invalid Refresh Page Token');
180
341
  }
181
342
  return advancement(continuation.room, continuation.from, continuation.at);
182
343
  }
344
+ if (request.minPosition !== undefined &&
345
+ !reached(room.locator, room.roomVersion, request.minPosition)) {
346
+ return { kind: 'retryable-refusal', code: 'replica_behind', fields: {} };
347
+ }
183
348
  if (request.fromRoomVersion === room.roomVersion) {
184
- return {
185
- kind: 'still-current'
186
- };
349
+ return { kind: 'still-current' };
187
350
  }
188
351
  const from = served.get(room.locator)?.get(request.fromRoomVersion);
189
- if (from === undefined) return {
190
- kind: 'beyond-horizon'
191
- };
352
+ if (from === undefined)
353
+ return { kind: 'beyond-horizon' };
192
354
  return advancement(room, from, 0);
193
- }, request);
355
+ }, request).then((answer) => note(request.locator, answer));
194
356
  },
195
- async mutate (_authorization, request) {
196
- return resolveScript(scripts.mutate, ()=>{
197
- const room = rooms.find((entry)=>entry.locator === request.locator);
357
+ async mutate(_authorization, request) {
358
+ return resolveScript(scripts.mutate, () => {
359
+ const room = rooms.find((entry) => entry.locator === request.locator);
198
360
  if (room === undefined) {
199
- return {
200
- kind: 'room-not-readable',
201
- locator: request.locator
202
- };
361
+ return { kind: 'room-not-readable', locator: request.locator };
203
362
  }
204
- return {
205
- kind: 'rejected',
206
- text: '',
207
- affected: {}
208
- };
209
- }, request);
363
+ return { kind: 'rejected', code: 'unscripted-mutation', fields: {}, affected: {} };
364
+ }, request).then((answer) => note(request.locator, answer));
210
365
  },
211
- async history (_authorization, request) {
212
- return resolveScript(scripts.history, ()=>{
213
- const room = rooms.find((entry)=>entry.locator === request.locator);
366
+ async history(_authorization, request) {
367
+ return resolveScript(scripts.history, () => {
368
+ const room = rooms.find((entry) => entry.locator === request.locator);
214
369
  if (room === undefined) {
215
- return {
216
- kind: 'room-not-readable',
217
- locator: request.locator
218
- };
370
+ return { kind: 'room-not-readable', locator: request.locator };
219
371
  }
220
372
  return {
221
373
  kind: 'history',
222
- revisions: []
374
+ revisions: [],
223
375
  };
224
376
  }, request);
225
377
  },
226
- async action (_authorization, request) {
227
- return resolveScript(scripts.action, ()=>({
228
- kind: 'rejected',
229
- text: ''
230
- }), request);
231
- }
378
+ async action(_authorization, request) {
379
+ return resolveScript(scripts.action, () => {
380
+ if (request.name.startsWith('conversation.'))
381
+ return conversationAction(request);
382
+ return { kind: 'rejected', code: 'unscripted-action', fields: {} };
383
+ }, request).then((answer) => {
384
+ if (answer.kind === 'action' && answer.at !== undefined)
385
+ note(answer.at.locator, answer.at);
386
+ return answer;
387
+ });
388
+ },
232
389
  };
233
390
  }
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"}