@agentshouse/mdruntime 0.1.0-cfbf80d8d4644 → 0.1.0-cfcf93be6310b
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.
- package/README.md +24 -11
- package/dist/adapter.d.ts +182 -47
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +5 -1
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +53 -6
- package/dist/attempt.d.ts +16 -0
- package/dist/attempt.d.ts.map +1 -0
- package/dist/attempt.js +70 -0
- package/dist/binary.d.ts +18 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +8 -0
- package/dist/bootstrap.d.ts +33 -5
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +202 -48
- package/dist/chain.d.ts +11 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +9 -14
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -56
- package/dist/change.d.ts +45 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +34 -0
- package/dist/client.d.ts +38 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +156 -20
- package/dist/collection.d.ts +13 -14
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +52 -56
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +789 -0
- package/dist/connection.d.ts +59 -20
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +4080 -879
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation.d.ts +51 -20
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +732 -242
- package/dist/digest.d.ts +7 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +113 -0
- package/dist/durability.d.ts +4 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +20 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +152 -0
- package/dist/expectation.d.ts +21 -0
- package/dist/expectation.d.ts.map +1 -0
- package/dist/expectation.js +70 -0
- package/dist/failure.d.ts +13 -0
- package/dist/failure.d.ts.map +1 -0
- package/dist/failure.js +19 -0
- package/dist/fence.d.ts +6 -0
- package/dist/fence.d.ts.map +1 -0
- package/dist/fence.js +10 -0
- package/dist/file.d.ts +2 -19
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +7 -122
- package/dist/host.d.ts +11 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +128 -24
- package/dist/identity.d.ts +4 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +16 -1
- package/dist/index.d.ts +22 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/job.d.ts +14 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +28 -0
- package/dist/live.d.ts +23 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +127 -0
- package/dist/media.d.ts +8 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +218 -0
- package/dist/memory.d.ts +20 -7
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +253 -92
- package/dist/messages.d.ts +28 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +89 -0
- package/dist/model.d.ts +19 -4
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +10 -2
- package/dist/name.d.ts +4 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +122 -0
- package/dist/observation.d.ts +22 -4
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +120 -14
- package/dist/open.d.ts +2 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/open.js +1 -0
- package/dist/opened.d.ts +22 -0
- package/dist/opened.d.ts.map +1 -0
- package/dist/opened.js +107 -0
- package/dist/outcome.d.ts +72 -5
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +81 -1
- package/dist/overlay.d.ts +15 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +136 -180
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -0
- package/dist/phrase.d.ts +3 -0
- package/dist/phrase.d.ts.map +1 -0
- package/dist/phrase.js +8 -0
- package/dist/query.d.ts +75 -5
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +119 -26
- package/dist/reach.d.ts +18 -4
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +234 -69
- package/dist/react.d.ts +32 -19
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +13 -21
- package/dist/readiness.d.ts +50 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +27 -0
- package/dist/recovery.d.ts +26 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +224 -0
- package/dist/refresh.d.ts +20 -7
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +167 -59
- package/dist/replica.d.ts +59 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +324 -157
- package/dist/room-draft.d.ts +59 -11
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +276 -80
- package/dist/rows.d.ts +40 -34
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +202 -80
- package/dist/save.d.ts +73 -4
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +825 -152
- package/dist/search.d.ts +15 -54
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -121
- package/dist/seed.d.ts +16 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +75 -0
- package/dist/shared.d.ts +15 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +421 -0
- package/dist/status.d.ts +7 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -9
- package/dist/store.d.ts +118 -59
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +354 -344
- package/dist/stored.d.ts +162 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +549 -0
- package/dist/tables.d.ts +353 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +585 -0
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/turn.d.ts +9 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +75 -0
- package/dist/validation.d.ts +29 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +104 -0
- package/dist/windows.d.ts +22 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +89 -0
- package/dist/wire.d.ts +170 -33
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +69 -31
- package/package.json +26 -15
- package/AGENTS.md +0 -232
- package/dist/attachment.d.ts +0 -3
- package/dist/attachment.d.ts.map +0 -1
- package/dist/attachment.js +0 -8
- package/dist/read-side.d.ts +0 -18
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -377
package/dist/memory.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { sameChange } from './overlay.js';
|
|
2
|
+
const ATTACHMENTS = 'attachments';
|
|
3
|
+
function lastName(path) {
|
|
4
|
+
return path.slice(path.lastIndexOf('/') + 1);
|
|
5
|
+
}
|
|
2
6
|
const FIXTURE_RETENTION = {
|
|
3
7
|
history: { kind: 'duration', seconds: 1 },
|
|
4
|
-
outcome:
|
|
8
|
+
outcome: 604_800,
|
|
5
9
|
refreshHorizon: 1,
|
|
6
10
|
};
|
|
7
11
|
function declaredRetention(value) {
|
|
@@ -15,12 +19,7 @@ function declaredRetention(value) {
|
|
|
15
19
|
}
|
|
16
20
|
const MODEL_ABSENT = { kind: 'model-unavailable', reason: 'not-readable' };
|
|
17
21
|
function modelsOf(room) {
|
|
18
|
-
return {
|
|
19
|
-
collection: room.model ?? MODEL_ABSENT,
|
|
20
|
-
...(room.typedSelection === undefined
|
|
21
|
-
? {}
|
|
22
|
-
: { selection: room.selectionModel ?? MODEL_ABSENT }),
|
|
23
|
-
};
|
|
22
|
+
return { collection: room.model ?? MODEL_ABSENT };
|
|
24
23
|
}
|
|
25
24
|
function changedModels(room, from) {
|
|
26
25
|
const now = modelsOf(room);
|
|
@@ -53,12 +52,16 @@ export function createMemoryAdapter(options = {}) {
|
|
|
53
52
|
const listeners = new Set();
|
|
54
53
|
const modeObservers = new Set();
|
|
55
54
|
const scripted = new Map();
|
|
56
|
-
const
|
|
57
|
-
const sealed = new Set();
|
|
55
|
+
const sentTurns = new Map();
|
|
58
56
|
const historyPageSize = options.historyPageSize;
|
|
59
|
-
|
|
57
|
+
const attached = new Map();
|
|
58
|
+
const linked = new WeakMap();
|
|
59
|
+
const carried = new Map();
|
|
60
60
|
let expiring = [];
|
|
61
|
+
let openings = 0;
|
|
62
|
+
const declaredRooms = new Set();
|
|
61
63
|
let replicated = [];
|
|
64
|
+
let heldCursor = null;
|
|
62
65
|
let issued = 0;
|
|
63
66
|
function scriptConversations(entries) {
|
|
64
67
|
scripted.clear();
|
|
@@ -86,6 +89,19 @@ export function createMemoryAdapter(options = {}) {
|
|
|
86
89
|
const wanted = ordinals.get(`${locator}\u0000${target}`);
|
|
87
90
|
return held !== undefined && wanted !== undefined && held >= wanted;
|
|
88
91
|
}
|
|
92
|
+
function heldBlob(room, path) {
|
|
93
|
+
return attached.get(`${room.locator}\u0000${path}`) ?? room.blobs?.[path];
|
|
94
|
+
}
|
|
95
|
+
function freePath(room, name) {
|
|
96
|
+
const dot = name.lastIndexOf('.');
|
|
97
|
+
const stem = dot > 0 ? name.slice(0, dot) : name;
|
|
98
|
+
const extension = dot > 0 ? name.slice(dot) : '';
|
|
99
|
+
for (let count = 1;; count += 1) {
|
|
100
|
+
const path = `${ATTACHMENTS}/${count === 1 ? stem : `${stem}-${count}`}${extension}`;
|
|
101
|
+
if (heldBlob(room, path) === undefined && room.documents?.[path] === undefined)
|
|
102
|
+
return path;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
89
105
|
function retain(entries) {
|
|
90
106
|
for (const room of entries) {
|
|
91
107
|
note(room.locator, room);
|
|
@@ -107,35 +123,51 @@ export function createMemoryAdapter(options = {}) {
|
|
|
107
123
|
providerOwnedPaths: room.providerOwnedPaths,
|
|
108
124
|
};
|
|
109
125
|
}
|
|
110
|
-
function page(room,
|
|
126
|
+
function page(room, after) {
|
|
111
127
|
const paths = Object.keys(room.documents ?? {}).sort();
|
|
128
|
+
const opening = after === undefined;
|
|
129
|
+
const from = opening ? 0 : paths.filter((path) => path <= after).length;
|
|
112
130
|
const size = pageSize ?? paths.length;
|
|
113
131
|
const taken = paths.slice(from, from + size);
|
|
114
132
|
const next = from + taken.length;
|
|
115
|
-
const targets =
|
|
133
|
+
const targets = opening ? Object.keys(room.binaryFiles ?? {}) : [];
|
|
116
134
|
return {
|
|
117
135
|
kind: 'bootstrap',
|
|
118
136
|
roomVersion: room.roomVersion,
|
|
119
|
-
...(
|
|
137
|
+
...(opening ? { models: modelsOf(room) } : {}),
|
|
120
138
|
documents: named(room.documents ?? {}, taken),
|
|
121
|
-
revisions: named(room.revisions ?? {}, taken),
|
|
139
|
+
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
140
|
+
...(room.fileIds === undefined
|
|
141
|
+
? {}
|
|
142
|
+
: { fileIds: named(room.fileIds, [...taken, ...targets]) }),
|
|
122
143
|
changes: named(room.changes ?? {}, [...taken, ...targets]),
|
|
123
|
-
|
|
124
|
-
...(
|
|
125
|
-
...(next < paths.length ? { pageToken:
|
|
144
|
+
binaryFiles: named(room.binaryFiles ?? {}, targets),
|
|
145
|
+
...(opening && room.folders !== undefined ? { folders: room.folders } : {}),
|
|
146
|
+
...(next < paths.length ? { pageToken: taken.at(-1) } : {}),
|
|
126
147
|
};
|
|
127
148
|
}
|
|
128
|
-
function
|
|
149
|
+
function foldersMoved(room, from) {
|
|
150
|
+
const now = new Set(room.folders ?? []);
|
|
151
|
+
const before = new Set(from.folders ?? []);
|
|
152
|
+
const folders = [...now].filter((folder) => !before.has(folder)).sort();
|
|
153
|
+
const folderRemovals = [...before].filter((folder) => !now.has(folder)).sort();
|
|
154
|
+
return {
|
|
155
|
+
...(folders.length === 0 ? {} : { folders }),
|
|
156
|
+
...(folderRemovals.length === 0 ? {} : { folderRemovals }),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function advancement(room, from, at, whole = false) {
|
|
129
160
|
const current = room.documents ?? {};
|
|
130
161
|
const previous = from.documents ?? {};
|
|
131
|
-
const currentTargets = new Set(room.
|
|
132
|
-
const previousTargets = new Set(from.
|
|
162
|
+
const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
|
|
163
|
+
const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
|
|
133
164
|
const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
|
|
165
|
+
room.fileIds?.[path] !== from.fileIds?.[path] ||
|
|
134
166
|
!sameChange(room.changes?.[path], from.changes?.[path]);
|
|
135
167
|
const changed = Object.keys(current)
|
|
136
168
|
.filter((path) => current[path] !== previous[path] || headMoved(path))
|
|
137
169
|
.sort();
|
|
138
|
-
const size = pageSize ?? changed.length;
|
|
170
|
+
const size = whole ? changed.length : (pageSize ?? changed.length);
|
|
139
171
|
const taken = changed.slice(at, at + size);
|
|
140
172
|
const next = at + taken.length;
|
|
141
173
|
const opening = at === 0;
|
|
@@ -145,27 +177,48 @@ export function createMemoryAdapter(options = {}) {
|
|
|
145
177
|
const targets = opening
|
|
146
178
|
? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
|
|
147
179
|
: [];
|
|
148
|
-
const attachments = room.attachments ?? [];
|
|
149
|
-
const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
|
|
150
180
|
const models = opening ? changedModels(room, from) : undefined;
|
|
151
181
|
return {
|
|
152
182
|
kind: 'net-advancement',
|
|
153
183
|
roomVersion: room.roomVersion,
|
|
154
184
|
...(models === undefined ? {} : { models }),
|
|
155
185
|
documents: named(current, taken),
|
|
156
|
-
revisions: named(room.revisions ?? {}, taken),
|
|
186
|
+
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
187
|
+
...(room.fileIds === undefined
|
|
188
|
+
? {}
|
|
189
|
+
: { fileIds: named(room.fileIds, [...taken, ...targets]) }),
|
|
157
190
|
changes: named(room.changes ?? {}, [...taken, ...targets]),
|
|
158
|
-
|
|
191
|
+
binaryFiles: named(room.binaryFiles ?? {}, targets),
|
|
192
|
+
...(opening ? foldersMoved(room, from) : {}),
|
|
159
193
|
removals: opening
|
|
160
194
|
? [
|
|
161
195
|
...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
|
|
162
196
|
...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
|
|
163
197
|
].sort()
|
|
164
198
|
: [],
|
|
165
|
-
...(declared ? { attachments } : {}),
|
|
166
199
|
...(pageToken === undefined ? {} : { pageToken }),
|
|
167
200
|
};
|
|
168
201
|
}
|
|
202
|
+
function carry(locator) {
|
|
203
|
+
const at = carried.get(locator);
|
|
204
|
+
const current = rooms.find((entry) => entry.locator === locator);
|
|
205
|
+
if (at === undefined || current === undefined || current.roomVersion === at)
|
|
206
|
+
return;
|
|
207
|
+
const from = served.get(locator)?.get(at);
|
|
208
|
+
carried.set(locator, current.roomVersion);
|
|
209
|
+
if (from === undefined)
|
|
210
|
+
return;
|
|
211
|
+
const page = advancement(current, from, 0, true);
|
|
212
|
+
for (const observer of observers) {
|
|
213
|
+
observer({
|
|
214
|
+
kind: 'room-change',
|
|
215
|
+
locator,
|
|
216
|
+
from: at,
|
|
217
|
+
roomVersion: current.roomVersion,
|
|
218
|
+
read: async () => page,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
169
222
|
function pageOf(conversation, after) {
|
|
170
223
|
const messages = conversation.messages ?? [];
|
|
171
224
|
const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
|
|
@@ -180,16 +233,13 @@ export function createMemoryAdapter(options = {}) {
|
|
|
180
233
|
: {}),
|
|
181
234
|
};
|
|
182
235
|
}
|
|
183
|
-
function historiesOf(
|
|
184
|
-
const asked = input?.conversations;
|
|
185
|
-
if (!Array.isArray(asked))
|
|
186
|
-
return { kind: 'rejected', code: 'invalid_request', fields: {} };
|
|
236
|
+
function historiesOf(request) {
|
|
187
237
|
const histories = [];
|
|
188
|
-
for (const entry of
|
|
189
|
-
const conversation =
|
|
238
|
+
for (const entry of request.conversations) {
|
|
239
|
+
const conversation = scripted.get(entry.conversation);
|
|
190
240
|
if (conversation === undefined)
|
|
191
241
|
continue;
|
|
192
|
-
const outcome = conversation.outcomes?.
|
|
242
|
+
const outcome = conversation.outcomes?.history;
|
|
193
243
|
if (outcome !== undefined)
|
|
194
244
|
return outcome;
|
|
195
245
|
histories.push(pageOf(conversation, entry.after));
|
|
@@ -200,44 +250,47 @@ export function createMemoryAdapter(options = {}) {
|
|
|
200
250
|
function conversationAction(request) {
|
|
201
251
|
const name = request.name;
|
|
202
252
|
const input = (request.input ?? {});
|
|
203
|
-
if (name === '
|
|
204
|
-
return historiesOf(request.input);
|
|
205
|
-
if (name === 'conversation.create') {
|
|
253
|
+
if (name === 'conversations/create') {
|
|
206
254
|
issued += 1;
|
|
207
255
|
const conversation = `conversation-${issued}`;
|
|
208
256
|
scripted.set(conversation, { conversation });
|
|
209
|
-
return { kind: 'action', result: { conversation } };
|
|
257
|
+
return { kind: 'action', result: { conversation_id: conversation } };
|
|
210
258
|
}
|
|
211
|
-
const named = typeof input.
|
|
259
|
+
const named = typeof input.conversation_id === 'string' ? input.conversation_id : '';
|
|
212
260
|
const conversation = scripted.get(named);
|
|
213
261
|
if (conversation === undefined) {
|
|
214
|
-
return {
|
|
262
|
+
return {
|
|
263
|
+
kind: 'rejected',
|
|
264
|
+
code: 'unknown-conversation',
|
|
265
|
+
fields: { conversation: named },
|
|
266
|
+
retryable: false,
|
|
267
|
+
};
|
|
215
268
|
}
|
|
216
269
|
const outcome = conversation.outcomes?.[name];
|
|
217
270
|
if (outcome !== undefined)
|
|
218
271
|
return outcome;
|
|
219
|
-
if (name === '
|
|
272
|
+
if (name === 'conversations/send') {
|
|
273
|
+
const operation = typeof input.operation_id === 'string' ? input.operation_id : null;
|
|
274
|
+
const answered = operation === null ? undefined : sentTurns.get(operation);
|
|
275
|
+
if (answered !== undefined)
|
|
276
|
+
return { kind: 'action', result: { message_id: answered } };
|
|
220
277
|
issued += 1;
|
|
221
278
|
const turn = `turn-${issued}`;
|
|
222
|
-
|
|
223
|
-
|
|
279
|
+
if (operation !== null)
|
|
280
|
+
sentTurns.set(operation, turn);
|
|
281
|
+
return { kind: 'action', result: { message_id: turn } };
|
|
224
282
|
}
|
|
225
|
-
if (name === '
|
|
226
|
-
const turn = typeof input.turn === 'string' ? input.turn : '';
|
|
227
|
-
if (sealed.has(turn) || !unsealed.has(turn)) {
|
|
228
|
-
return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
|
|
229
|
-
}
|
|
230
|
-
unsealed.delete(turn);
|
|
231
|
-
return { kind: 'action', result: { turn, cancelled: true } };
|
|
232
|
-
}
|
|
233
|
-
if (name === 'conversation.delete')
|
|
283
|
+
if (name === 'conversations/delete')
|
|
234
284
|
scripted.delete(named);
|
|
235
|
-
return { kind: 'action', result: {
|
|
285
|
+
return { kind: 'action', result: { conversation_id: named } };
|
|
236
286
|
}
|
|
237
287
|
function announceList() {
|
|
238
|
-
const entries = [...scripted.values()].flatMap(({ conversation, listed }) => listed === undefined
|
|
239
|
-
|
|
240
|
-
|
|
288
|
+
const entries = [...scripted.values()].flatMap(({ conversation, listed, messages = [] }) => listed === undefined
|
|
289
|
+
? []
|
|
290
|
+
: [{ conversation, ...listed, newest: messages.at(-1)?.position ?? null }]);
|
|
291
|
+
for (const listener of listeners) {
|
|
292
|
+
listener({ kind: 'list', entries, whole: true, more: false, cursor: null });
|
|
293
|
+
}
|
|
241
294
|
}
|
|
242
295
|
function discovery() {
|
|
243
296
|
return {
|
|
@@ -246,9 +299,45 @@ export function createMemoryAdapter(options = {}) {
|
|
|
246
299
|
capabilities,
|
|
247
300
|
providerLimits,
|
|
248
301
|
retention,
|
|
302
|
+
...(options.member === undefined ? {} : { member: options.member }),
|
|
249
303
|
};
|
|
250
304
|
}
|
|
305
|
+
function discovered() {
|
|
306
|
+
return resolveScript(scripts.discover, discovery, undefined).then((answer) => {
|
|
307
|
+
if (answer.kind === 'discovery')
|
|
308
|
+
for (const room of answer.rooms)
|
|
309
|
+
note(room.locator, room);
|
|
310
|
+
return answer;
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
function opened(notify) {
|
|
314
|
+
const opening = ++openings;
|
|
315
|
+
notify({ kind: 'opened' });
|
|
316
|
+
void discovered()
|
|
317
|
+
.catch(() => ({ kind: 'transport-uncertainty' }))
|
|
318
|
+
.then((answer) => {
|
|
319
|
+
if (opening !== openings)
|
|
320
|
+
return;
|
|
321
|
+
if (answer.kind !== 'discovery') {
|
|
322
|
+
openings += 1;
|
|
323
|
+
carried.clear();
|
|
324
|
+
const revoked = answer.kind === 'revoked-authorization';
|
|
325
|
+
notify({ kind: 'closed', revoked, lost: !revoked, authorityChanged: false });
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
declaredRooms.clear();
|
|
329
|
+
for (const room of answer.rooms)
|
|
330
|
+
declaredRooms.add(room.locator);
|
|
331
|
+
notify({ kind: 'discovered', discovery: answer });
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
function emitAll(event) {
|
|
335
|
+
for (const observer of observers)
|
|
336
|
+
observer(event);
|
|
337
|
+
}
|
|
251
338
|
return {
|
|
339
|
+
...(options.roomTypes === undefined ? {} : { roomTypes: options.roomTypes }),
|
|
340
|
+
...(options.typedPaths === undefined ? {} : { typedPaths: options.typedPaths }),
|
|
252
341
|
setRooms(next) {
|
|
253
342
|
rooms = [...next];
|
|
254
343
|
retain(rooms);
|
|
@@ -257,26 +346,37 @@ export function createMemoryAdapter(options = {}) {
|
|
|
257
346
|
scriptConversations(next);
|
|
258
347
|
},
|
|
259
348
|
open() {
|
|
349
|
+
carried.clear();
|
|
260
350
|
announceList();
|
|
261
|
-
|
|
262
|
-
observer({ kind: 'opened' });
|
|
351
|
+
opened(emitAll);
|
|
263
352
|
},
|
|
264
|
-
close(revoked = false) {
|
|
265
|
-
|
|
266
|
-
|
|
353
|
+
close({ revoked = false, lost = !revoked, authorityChanged = false } = {}) {
|
|
354
|
+
openings += 1;
|
|
355
|
+
carried.clear();
|
|
356
|
+
emitAll({ kind: 'closed', revoked, lost, authorityChanged });
|
|
267
357
|
},
|
|
268
358
|
expire(locators) {
|
|
269
359
|
expiring = [...locators];
|
|
270
360
|
},
|
|
271
|
-
notifyRoomVersion({ locator
|
|
272
|
-
|
|
273
|
-
|
|
361
|
+
notifyRoomVersion({ locator }) {
|
|
362
|
+
carry(locator);
|
|
363
|
+
},
|
|
364
|
+
notifyAuthorityChanged(locators) {
|
|
365
|
+
const named = new Set(locators ?? [...declaredRooms, ...rooms.map((room) => room.locator)]);
|
|
366
|
+
const listed = rooms.filter((room) => named.has(room.locator));
|
|
367
|
+
const left = [...named].filter((locator) => !listed.some((room) => room.locator === locator));
|
|
368
|
+
for (const room of listed)
|
|
369
|
+
declaredRooms.add(room.locator);
|
|
370
|
+
for (const locator of left)
|
|
371
|
+
declaredRooms.delete(locator);
|
|
372
|
+
emitAll({
|
|
373
|
+
kind: 'authority-changed',
|
|
374
|
+
rooms: listed.map(declared),
|
|
375
|
+
left,
|
|
376
|
+
...(options.member === undefined ? {} : { member: options.member }),
|
|
377
|
+
});
|
|
274
378
|
},
|
|
275
379
|
notifyConversation(event) {
|
|
276
|
-
if (event.kind === 'accepted-message') {
|
|
277
|
-
sealed.add(event.message.turn);
|
|
278
|
-
unsealed.delete(event.message.turn);
|
|
279
|
-
}
|
|
280
380
|
for (const listener of listeners)
|
|
281
381
|
listener(event);
|
|
282
382
|
},
|
|
@@ -285,21 +385,31 @@ export function createMemoryAdapter(options = {}) {
|
|
|
285
385
|
observer(mode);
|
|
286
386
|
},
|
|
287
387
|
heldRooms() {
|
|
288
|
-
return
|
|
388
|
+
return [...carried.keys()].sort();
|
|
289
389
|
},
|
|
290
390
|
replicatedConversations() {
|
|
291
391
|
return replicated;
|
|
292
392
|
},
|
|
393
|
+
heldConversationCursor() {
|
|
394
|
+
return heldCursor;
|
|
395
|
+
},
|
|
293
396
|
conversations: {
|
|
294
397
|
replicate(next) {
|
|
295
398
|
replicated = [...next];
|
|
296
399
|
},
|
|
400
|
+
hold(cursor) {
|
|
401
|
+
heldCursor = cursor;
|
|
402
|
+
},
|
|
297
403
|
observe(notify) {
|
|
298
404
|
listeners.add(notify);
|
|
299
405
|
return () => {
|
|
300
406
|
listeners.delete(notify);
|
|
301
407
|
};
|
|
302
408
|
},
|
|
409
|
+
history: (request) => Promise.resolve(historiesOf(request)),
|
|
410
|
+
...(options.agents === undefined
|
|
411
|
+
? {}
|
|
412
|
+
: { agents: () => Promise.resolve(structuredClone(options.agents)) }),
|
|
303
413
|
},
|
|
304
414
|
serviceMode: {
|
|
305
415
|
observe(notify) {
|
|
@@ -311,23 +421,29 @@ export function createMemoryAdapter(options = {}) {
|
|
|
311
421
|
},
|
|
312
422
|
roomStream: {
|
|
313
423
|
hold(asked) {
|
|
314
|
-
|
|
315
|
-
const
|
|
316
|
-
expiring = [];
|
|
317
|
-
const moved = asked.flatMap((room) => {
|
|
424
|
+
const named = asked.map((room) => room.locator);
|
|
425
|
+
const unknown = asked.flatMap((room) => {
|
|
318
426
|
const current = rooms.find((entry) => entry.locator === room.locator);
|
|
319
427
|
return current === undefined ||
|
|
320
|
-
|
|
321
|
-
|
|
428
|
+
current.roomVersion === room.roomVersion ||
|
|
429
|
+
served.get(room.locator)?.has(room.roomVersion) === true
|
|
322
430
|
? []
|
|
323
|
-
: [
|
|
431
|
+
: [room.locator];
|
|
324
432
|
});
|
|
433
|
+
const expired = [
|
|
434
|
+
...new Set([...expiring.filter((locator) => named.includes(locator)), ...unknown]),
|
|
435
|
+
];
|
|
436
|
+
expiring = expiring.filter((locator) => !named.includes(locator));
|
|
325
437
|
queueMicrotask(() => {
|
|
326
|
-
for (const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
438
|
+
for (const room of asked) {
|
|
439
|
+
if (expired.includes(room.locator))
|
|
440
|
+
carried.delete(room.locator);
|
|
441
|
+
else {
|
|
442
|
+
carried.set(room.locator, room.roomVersion);
|
|
443
|
+
carry(room.locator);
|
|
444
|
+
}
|
|
330
445
|
}
|
|
446
|
+
emitAll({ kind: 'caught-up', expired });
|
|
331
447
|
});
|
|
332
448
|
},
|
|
333
449
|
observe(notify) {
|
|
@@ -336,11 +452,14 @@ export function createMemoryAdapter(options = {}) {
|
|
|
336
452
|
if (!observers.has(notify))
|
|
337
453
|
return;
|
|
338
454
|
if (options.unopened === true) {
|
|
339
|
-
notify({ kind: 'closed', revoked: false });
|
|
455
|
+
notify({ kind: 'closed', revoked: false, lost: true, authorityChanged: false });
|
|
340
456
|
return;
|
|
341
457
|
}
|
|
342
458
|
announceList();
|
|
343
|
-
|
|
459
|
+
opened((event) => {
|
|
460
|
+
if (observers.has(notify))
|
|
461
|
+
notify(event);
|
|
462
|
+
});
|
|
344
463
|
});
|
|
345
464
|
return () => {
|
|
346
465
|
observers.delete(notify);
|
|
@@ -357,12 +476,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
357
476
|
return resolveScript(scripts.authorize, () => ({}), undefined);
|
|
358
477
|
},
|
|
359
478
|
async discover(_authorization) {
|
|
360
|
-
return
|
|
361
|
-
if (answer.kind === 'discovery')
|
|
362
|
-
for (const room of answer.rooms)
|
|
363
|
-
note(room.locator, room);
|
|
364
|
-
return answer;
|
|
365
|
-
});
|
|
479
|
+
return discovered();
|
|
366
480
|
},
|
|
367
481
|
reached,
|
|
368
482
|
follows(locator, roomVersion, next) {
|
|
@@ -379,7 +493,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
379
493
|
if (room === undefined) {
|
|
380
494
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
381
495
|
}
|
|
382
|
-
return page(room, request.pageToken
|
|
496
|
+
return page(room, request.pageToken);
|
|
383
497
|
}, request).then((answer) => note(request.locator, answer));
|
|
384
498
|
},
|
|
385
499
|
async refresh(_authorization, request) {
|
|
@@ -412,8 +526,20 @@ export function createMemoryAdapter(options = {}) {
|
|
|
412
526
|
if (room === undefined) {
|
|
413
527
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
414
528
|
}
|
|
415
|
-
return {
|
|
416
|
-
|
|
529
|
+
return {
|
|
530
|
+
kind: 'rejected',
|
|
531
|
+
code: 'unscripted-mutation',
|
|
532
|
+
fields: {},
|
|
533
|
+
retryable: false,
|
|
534
|
+
affected: {},
|
|
535
|
+
};
|
|
536
|
+
}, request).then((answer) => {
|
|
537
|
+
const destination = request.changeBatch.between?.destination.room;
|
|
538
|
+
if (answer.kind === 'accepted' && answer.destination !== undefined && destination) {
|
|
539
|
+
note(destination, answer.destination);
|
|
540
|
+
}
|
|
541
|
+
return note(request.locator, answer);
|
|
542
|
+
});
|
|
417
543
|
},
|
|
418
544
|
async history(_authorization, request) {
|
|
419
545
|
return resolveScript(scripts.history, () => {
|
|
@@ -427,11 +553,46 @@ export function createMemoryAdapter(options = {}) {
|
|
|
427
553
|
};
|
|
428
554
|
}, request);
|
|
429
555
|
},
|
|
556
|
+
async binary(_authorization, request) {
|
|
557
|
+
return resolveScript(scripts.binary, () => {
|
|
558
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
559
|
+
if (room === undefined)
|
|
560
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
561
|
+
const blob = heldBlob(room, request.path);
|
|
562
|
+
return blob === undefined
|
|
563
|
+
? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
|
|
564
|
+
: { kind: 'binary', body: blob.stream(), mediaType: blob.type };
|
|
565
|
+
}, request);
|
|
566
|
+
},
|
|
567
|
+
async link(_authorization, request) {
|
|
568
|
+
return resolveScript(scripts.link, () => {
|
|
569
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
570
|
+
if (room === undefined)
|
|
571
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
572
|
+
const blob = heldBlob(room, request.path);
|
|
573
|
+
if (blob === undefined) {
|
|
574
|
+
return { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false };
|
|
575
|
+
}
|
|
576
|
+
const url = linked.get(blob) ?? URL.createObjectURL(blob);
|
|
577
|
+
linked.set(blob, url);
|
|
578
|
+
return { kind: 'link', url, name: lastName(request.path), mediaType: blob.type };
|
|
579
|
+
}, request);
|
|
580
|
+
},
|
|
581
|
+
async attach(_authorization, request) {
|
|
582
|
+
return resolveScript(scripts.attach, () => {
|
|
583
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
584
|
+
if (room === undefined)
|
|
585
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
586
|
+
const path = freePath(room, request.name);
|
|
587
|
+
attached.set(`${room.locator}\u0000${path}`, request.blob);
|
|
588
|
+
return { kind: 'attached', path, revision: `attached-${attached.size}` };
|
|
589
|
+
}, request);
|
|
590
|
+
},
|
|
430
591
|
async action(_authorization, request) {
|
|
431
592
|
return resolveScript(scripts.action, () => {
|
|
432
|
-
if (request.name.startsWith('
|
|
593
|
+
if (request.name.startsWith('conversations/'))
|
|
433
594
|
return conversationAction(request);
|
|
434
|
-
return { kind: 'rejected', code: 'unscripted-action', fields: {} };
|
|
595
|
+
return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
|
|
435
596
|
}, request).then((answer) => {
|
|
436
597
|
if (answer.kind === 'action' && answer.at !== undefined)
|
|
437
598
|
note(answer.at.locator, answer.at);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AcceptedMessage } from './adapter.js';
|
|
2
|
+
import type { Connection } from './tables.js';
|
|
3
|
+
export declare const MESSAGE_TABLES: readonly string[];
|
|
4
|
+
export type HeldConversation = {
|
|
5
|
+
readonly conversation: string;
|
|
6
|
+
readonly read: string | null | undefined;
|
|
7
|
+
readonly partial: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type MessageWindow = {
|
|
10
|
+
readonly messages: AcceptedMessage[];
|
|
11
|
+
readonly more: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type ConversationWrite = {
|
|
14
|
+
readonly conversation: string;
|
|
15
|
+
readonly messages: readonly AcceptedMessage[];
|
|
16
|
+
readonly read?: {
|
|
17
|
+
readonly at: string | null;
|
|
18
|
+
readonly partial: boolean;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function heldConversations(connection: Connection): HeldConversation[];
|
|
22
|
+
export declare function keptMessages(connection: Connection, { conversation, messages, read }: ConversationWrite): null;
|
|
23
|
+
export declare function messageWindow(connection: Connection, conversation: string, limit: number, before: readonly [string, string] | null, phrase: string | null): MessageWindow;
|
|
24
|
+
export declare function messageCount(connection: Connection, conversation: string, phrase: string | null): number;
|
|
25
|
+
export declare function turnArrived(connection: Connection, conversation: string, turn: string): boolean;
|
|
26
|
+
export declare function droppedMessages(connection: Connection, conversations: readonly string[]): void;
|
|
27
|
+
export declare function forgottenMessages(connection: Connection): void;
|
|
28
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAM3C,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;IAC9C,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3E,CAAC;AAMF,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,EAAE,CAmB5E;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,iBAAiB,GAClD,IAAI,CA+BN;AAkBD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,EACxC,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,aAAa,CAWf;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CAOR;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAO/F;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAK9F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAG9D"}
|