@agentshouse/mdruntime 0.1.0-cacb4c3f6734e → 0.1.0-cae97ad2e9142
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 +23 -10
- package/dist/adapter.d.ts +126 -30
- 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 +36 -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 +40 -6
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +186 -45
- 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 +35 -14
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +107 -17
- package/dist/collection.d.ts +9 -13
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +46 -56
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +767 -0
- package/dist/connection.d.ts +58 -19
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +3659 -726
- package/dist/conversation.d.ts +41 -12
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +588 -180
- 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 +5 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +19 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +151 -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 -10
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +3 -120
- package/dist/fulltext.d.ts +27 -0
- package/dist/fulltext.d.ts.map +1 -0
- package/dist/fulltext.js +368 -0
- package/dist/host.d.ts +15 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +132 -21
- 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 +20 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/live.d.ts +22 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +124 -0
- package/dist/memory.d.ts +13 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +99 -31
- package/dist/messages.d.ts +28 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +90 -0
- package/dist/model.d.ts +14 -4
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +13 -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 +19 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +113 -12
- 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 +62 -3
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +67 -1
- package/dist/overlay.d.ts +15 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +136 -180
- package/dist/query.d.ts +70 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +53 -38
- package/dist/reach.d.ts +17 -4
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +226 -65
- package/dist/react.d.ts +31 -20
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +13 -21
- package/dist/readiness.d.ts +64 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +33 -0
- package/dist/reads.d.ts +11 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +100 -0
- package/dist/recovery.d.ts +25 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +198 -0
- package/dist/refresh.d.ts +19 -8
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +125 -57
- package/dist/replica.d.ts +59 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +321 -155
- package/dist/room-draft.d.ts +41 -9
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +186 -37
- package/dist/rows.d.ts +37 -35
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +168 -100
- package/dist/save.d.ts +71 -4
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +815 -146
- package/dist/search.d.ts +41 -29
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +37 -105
- 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 +16 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +431 -0
- package/dist/status.d.ts +6 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -8
- package/dist/store.d.ts +124 -58
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +362 -344
- package/dist/stored.d.ts +150 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +564 -0
- package/dist/tables.d.ts +354 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +624 -0
- 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 +30 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +162 -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 +169 -33
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +68 -31
- package/dist/words.d.ts +19 -0
- package/dist/words.d.ts.map +1 -0
- package/dist/words.js +150 -0
- package/package.json +26 -15
- package/AGENTS.md +0 -244
- 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 -433
package/dist/memory.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { sameChange } from './overlay.js';
|
|
2
2
|
const FIXTURE_RETENTION = {
|
|
3
3
|
history: { kind: 'duration', seconds: 1 },
|
|
4
|
-
outcome:
|
|
4
|
+
outcome: 604_800,
|
|
5
5
|
refreshHorizon: 1,
|
|
6
6
|
};
|
|
7
7
|
function declaredRetention(value) {
|
|
@@ -15,12 +15,7 @@ function declaredRetention(value) {
|
|
|
15
15
|
}
|
|
16
16
|
const MODEL_ABSENT = { kind: 'model-unavailable', reason: 'not-readable' };
|
|
17
17
|
function modelsOf(room) {
|
|
18
|
-
return {
|
|
19
|
-
collection: room.model ?? MODEL_ABSENT,
|
|
20
|
-
...(room.typedSelection === undefined
|
|
21
|
-
? {}
|
|
22
|
-
: { selection: room.selectionModel ?? MODEL_ABSENT }),
|
|
23
|
-
};
|
|
18
|
+
return { collection: room.model ?? MODEL_ABSENT };
|
|
24
19
|
}
|
|
25
20
|
function changedModels(room, from) {
|
|
26
21
|
const now = modelsOf(room);
|
|
@@ -55,6 +50,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
55
50
|
const scripted = new Map();
|
|
56
51
|
const unsealed = new Map();
|
|
57
52
|
const sealed = new Set();
|
|
53
|
+
const sentTurns = new Map();
|
|
58
54
|
const historyPageSize = options.historyPageSize;
|
|
59
55
|
let held = [];
|
|
60
56
|
let expiring = [];
|
|
@@ -107,30 +103,46 @@ export function createMemoryAdapter(options = {}) {
|
|
|
107
103
|
providerOwnedPaths: room.providerOwnedPaths,
|
|
108
104
|
};
|
|
109
105
|
}
|
|
110
|
-
function page(room,
|
|
106
|
+
function page(room, after) {
|
|
111
107
|
const paths = Object.keys(room.documents ?? {}).sort();
|
|
108
|
+
const opening = after === undefined;
|
|
109
|
+
const from = opening ? 0 : paths.filter((path) => path <= after).length;
|
|
112
110
|
const size = pageSize ?? paths.length;
|
|
113
111
|
const taken = paths.slice(from, from + size);
|
|
114
112
|
const next = from + taken.length;
|
|
115
|
-
const targets =
|
|
113
|
+
const targets = opening ? Object.keys(room.binaryFiles ?? {}) : [];
|
|
116
114
|
return {
|
|
117
115
|
kind: 'bootstrap',
|
|
118
116
|
roomVersion: room.roomVersion,
|
|
119
|
-
...(
|
|
117
|
+
...(opening ? { models: modelsOf(room) } : {}),
|
|
120
118
|
documents: named(room.documents ?? {}, taken),
|
|
121
|
-
revisions: named(room.revisions ?? {}, taken),
|
|
119
|
+
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
120
|
+
...(room.fileIds === undefined
|
|
121
|
+
? {}
|
|
122
|
+
: { fileIds: named(room.fileIds, [...taken, ...targets]) }),
|
|
122
123
|
changes: named(room.changes ?? {}, [...taken, ...targets]),
|
|
123
|
-
|
|
124
|
-
...(
|
|
125
|
-
...(next < paths.length ? { pageToken:
|
|
124
|
+
binaryFiles: named(room.binaryFiles ?? {}, targets),
|
|
125
|
+
...(opening && room.folders !== undefined ? { folders: room.folders } : {}),
|
|
126
|
+
...(next < paths.length ? { pageToken: taken.at(-1) } : {}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function foldersMoved(room, from) {
|
|
130
|
+
const now = new Set(room.folders ?? []);
|
|
131
|
+
const before = new Set(from.folders ?? []);
|
|
132
|
+
const folders = [...now].filter((folder) => !before.has(folder)).sort();
|
|
133
|
+
const folderRemovals = [...before].filter((folder) => !now.has(folder)).sort();
|
|
134
|
+
return {
|
|
135
|
+
...(folders.length === 0 ? {} : { folders }),
|
|
136
|
+
...(folderRemovals.length === 0 ? {} : { folderRemovals }),
|
|
126
137
|
};
|
|
127
138
|
}
|
|
128
139
|
function advancement(room, from, at) {
|
|
129
140
|
const current = room.documents ?? {};
|
|
130
141
|
const previous = from.documents ?? {};
|
|
131
|
-
const currentTargets = new Set(room.
|
|
132
|
-
const previousTargets = new Set(from.
|
|
142
|
+
const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
|
|
143
|
+
const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
|
|
133
144
|
const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
|
|
145
|
+
room.fileIds?.[path] !== from.fileIds?.[path] ||
|
|
134
146
|
!sameChange(room.changes?.[path], from.changes?.[path]);
|
|
135
147
|
const changed = Object.keys(current)
|
|
136
148
|
.filter((path) => current[path] !== previous[path] || headMoved(path))
|
|
@@ -145,24 +157,25 @@ export function createMemoryAdapter(options = {}) {
|
|
|
145
157
|
const targets = opening
|
|
146
158
|
? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
|
|
147
159
|
: [];
|
|
148
|
-
const attachments = room.attachments ?? [];
|
|
149
|
-
const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
|
|
150
160
|
const models = opening ? changedModels(room, from) : undefined;
|
|
151
161
|
return {
|
|
152
162
|
kind: 'net-advancement',
|
|
153
163
|
roomVersion: room.roomVersion,
|
|
154
164
|
...(models === undefined ? {} : { models }),
|
|
155
165
|
documents: named(current, taken),
|
|
156
|
-
revisions: named(room.revisions ?? {}, taken),
|
|
166
|
+
revisions: named(room.revisions ?? {}, [...taken, ...targets]),
|
|
167
|
+
...(room.fileIds === undefined
|
|
168
|
+
? {}
|
|
169
|
+
: { fileIds: named(room.fileIds, [...taken, ...targets]) }),
|
|
157
170
|
changes: named(room.changes ?? {}, [...taken, ...targets]),
|
|
158
|
-
|
|
171
|
+
binaryFiles: named(room.binaryFiles ?? {}, targets),
|
|
172
|
+
...(opening ? foldersMoved(room, from) : {}),
|
|
159
173
|
removals: opening
|
|
160
174
|
? [
|
|
161
175
|
...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
|
|
162
176
|
...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
|
|
163
177
|
].sort()
|
|
164
178
|
: [],
|
|
165
|
-
...(declared ? { attachments } : {}),
|
|
166
179
|
...(pageToken === undefined ? {} : { pageToken }),
|
|
167
180
|
};
|
|
168
181
|
}
|
|
@@ -183,7 +196,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
183
196
|
function historiesOf(input) {
|
|
184
197
|
const asked = input?.conversations;
|
|
185
198
|
if (!Array.isArray(asked))
|
|
186
|
-
return { kind: 'rejected', code: 'invalid_request', fields: {} };
|
|
199
|
+
return { kind: 'rejected', code: 'invalid_request', fields: {}, retryable: false };
|
|
187
200
|
const histories = [];
|
|
188
201
|
for (const entry of asked) {
|
|
189
202
|
const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
|
|
@@ -211,21 +224,32 @@ export function createMemoryAdapter(options = {}) {
|
|
|
211
224
|
const named = typeof input.conversation === 'string' ? input.conversation : '';
|
|
212
225
|
const conversation = scripted.get(named);
|
|
213
226
|
if (conversation === undefined) {
|
|
214
|
-
return {
|
|
227
|
+
return {
|
|
228
|
+
kind: 'rejected',
|
|
229
|
+
code: 'unknown-conversation',
|
|
230
|
+
fields: { conversation: named },
|
|
231
|
+
retryable: false,
|
|
232
|
+
};
|
|
215
233
|
}
|
|
216
234
|
const outcome = conversation.outcomes?.[name];
|
|
217
235
|
if (outcome !== undefined)
|
|
218
236
|
return outcome;
|
|
219
237
|
if (name === 'conversation.send') {
|
|
238
|
+
const operation = typeof input.operation_id === 'string' ? input.operation_id : null;
|
|
239
|
+
const answered = operation === null ? undefined : sentTurns.get(operation);
|
|
240
|
+
if (answered !== undefined)
|
|
241
|
+
return { kind: 'action', result: { turn: answered } };
|
|
220
242
|
issued += 1;
|
|
221
243
|
const turn = `turn-${issued}`;
|
|
222
244
|
unsealed.set(turn, named);
|
|
245
|
+
if (operation !== null)
|
|
246
|
+
sentTurns.set(operation, turn);
|
|
223
247
|
return { kind: 'action', result: { turn } };
|
|
224
248
|
}
|
|
225
249
|
if (name === 'conversation.cancel') {
|
|
226
250
|
const turn = typeof input.turn === 'string' ? input.turn : '';
|
|
227
251
|
if (sealed.has(turn) || !unsealed.has(turn)) {
|
|
228
|
-
return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
|
|
252
|
+
return { kind: 'rejected', code: 'turn-sealed', fields: { turn }, retryable: false };
|
|
229
253
|
}
|
|
230
254
|
unsealed.delete(turn);
|
|
231
255
|
return { kind: 'action', result: { turn, cancelled: true } };
|
|
@@ -246,9 +270,12 @@ export function createMemoryAdapter(options = {}) {
|
|
|
246
270
|
capabilities,
|
|
247
271
|
providerLimits,
|
|
248
272
|
retention,
|
|
273
|
+
...(options.member === undefined ? {} : { member: options.member }),
|
|
249
274
|
};
|
|
250
275
|
}
|
|
251
276
|
return {
|
|
277
|
+
...(options.exhaustiveDiscovery === undefined ? {} : { exhaustiveDiscovery: true }),
|
|
278
|
+
...(options.roomTypes === undefined ? {} : { roomTypes: options.roomTypes }),
|
|
252
279
|
setRooms(next) {
|
|
253
280
|
rooms = [...next];
|
|
254
281
|
retain(rooms);
|
|
@@ -261,9 +288,9 @@ export function createMemoryAdapter(options = {}) {
|
|
|
261
288
|
for (const observer of observers)
|
|
262
289
|
observer({ kind: 'opened' });
|
|
263
290
|
},
|
|
264
|
-
close(revoked = false) {
|
|
291
|
+
close({ revoked = false, lost = !revoked } = {}) {
|
|
265
292
|
for (const observer of observers)
|
|
266
|
-
observer({ kind: 'closed', revoked });
|
|
293
|
+
observer({ kind: 'closed', revoked, lost });
|
|
267
294
|
},
|
|
268
295
|
expire(locators) {
|
|
269
296
|
expiring = [...locators];
|
|
@@ -272,6 +299,13 @@ export function createMemoryAdapter(options = {}) {
|
|
|
272
299
|
for (const observer of observers)
|
|
273
300
|
observer({ kind: 'room-version', locator, roomVersion });
|
|
274
301
|
},
|
|
302
|
+
notifyAuthorityChanged(scope) {
|
|
303
|
+
for (const observer of observers) {
|
|
304
|
+
observer(scope === undefined
|
|
305
|
+
? { kind: 'authority-changed' }
|
|
306
|
+
: { kind: 'authority-changed', scope });
|
|
307
|
+
}
|
|
308
|
+
},
|
|
275
309
|
notifyConversation(event) {
|
|
276
310
|
if (event.kind === 'accepted-message') {
|
|
277
311
|
sealed.add(event.message.turn);
|
|
@@ -330,13 +364,21 @@ export function createMemoryAdapter(options = {}) {
|
|
|
330
364
|
}
|
|
331
365
|
});
|
|
332
366
|
},
|
|
367
|
+
reopen() {
|
|
368
|
+
queueMicrotask(() => {
|
|
369
|
+
for (const observer of observers) {
|
|
370
|
+
observer({ kind: 'closed', revoked: false, lost: false });
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
},
|
|
374
|
+
published() { },
|
|
333
375
|
observe(notify) {
|
|
334
376
|
observers.add(notify);
|
|
335
377
|
queueMicrotask(() => {
|
|
336
378
|
if (!observers.has(notify))
|
|
337
379
|
return;
|
|
338
380
|
if (options.unopened === true) {
|
|
339
|
-
notify({ kind: 'closed', revoked: false });
|
|
381
|
+
notify({ kind: 'closed', revoked: false, lost: true });
|
|
340
382
|
return;
|
|
341
383
|
}
|
|
342
384
|
announceList();
|
|
@@ -379,7 +421,7 @@ export function createMemoryAdapter(options = {}) {
|
|
|
379
421
|
if (room === undefined) {
|
|
380
422
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
381
423
|
}
|
|
382
|
-
return page(room, request.pageToken
|
|
424
|
+
return page(room, request.pageToken);
|
|
383
425
|
}, request).then((answer) => note(request.locator, answer));
|
|
384
426
|
},
|
|
385
427
|
async refresh(_authorization, request) {
|
|
@@ -412,8 +454,20 @@ export function createMemoryAdapter(options = {}) {
|
|
|
412
454
|
if (room === undefined) {
|
|
413
455
|
return { kind: 'room-not-readable', locator: request.locator };
|
|
414
456
|
}
|
|
415
|
-
return {
|
|
416
|
-
|
|
457
|
+
return {
|
|
458
|
+
kind: 'rejected',
|
|
459
|
+
code: 'unscripted-mutation',
|
|
460
|
+
fields: {},
|
|
461
|
+
retryable: false,
|
|
462
|
+
affected: {},
|
|
463
|
+
};
|
|
464
|
+
}, request).then((answer) => {
|
|
465
|
+
const destination = request.changeBatch.between?.destination.room;
|
|
466
|
+
if (answer.kind === 'accepted' && answer.destination !== undefined && destination) {
|
|
467
|
+
note(destination, answer.destination);
|
|
468
|
+
}
|
|
469
|
+
return note(request.locator, answer);
|
|
470
|
+
});
|
|
417
471
|
},
|
|
418
472
|
async history(_authorization, request) {
|
|
419
473
|
return resolveScript(scripts.history, () => {
|
|
@@ -427,11 +481,25 @@ export function createMemoryAdapter(options = {}) {
|
|
|
427
481
|
};
|
|
428
482
|
}, request);
|
|
429
483
|
},
|
|
484
|
+
async binary(_authorization, request) {
|
|
485
|
+
return resolveScript(scripts.binary, () => {
|
|
486
|
+
const room = rooms.find((entry) => entry.locator === request.locator);
|
|
487
|
+
if (room === undefined)
|
|
488
|
+
return { kind: 'room-not-readable', locator: request.locator };
|
|
489
|
+
const blob = room.blobs?.[request.path];
|
|
490
|
+
return blob === undefined
|
|
491
|
+
? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
|
|
492
|
+
: { kind: 'binary', body: blob.stream(), mediaType: blob.type };
|
|
493
|
+
}, request);
|
|
494
|
+
},
|
|
495
|
+
async link(_authorization, request) {
|
|
496
|
+
return resolveScript(scripts.link, () => ({ kind: 'rejected', code: 'unscripted-link', fields: {}, retryable: false }), request);
|
|
497
|
+
},
|
|
430
498
|
async action(_authorization, request) {
|
|
431
499
|
return resolveScript(scripts.action, () => {
|
|
432
500
|
if (request.name.startsWith('conversation.'))
|
|
433
501
|
return conversationAction(request);
|
|
434
|
-
return { kind: 'rejected', code: 'unscripted-action', fields: {} };
|
|
502
|
+
return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
|
|
435
503
|
}, request).then((answer) => {
|
|
436
504
|
if (answer.kind === 'action' && answer.at !== undefined)
|
|
437
505
|
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): MessageWindow;
|
|
24
|
+
export declare function messageCount(connection: Connection, conversation: string): 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,CAoCN;AAYD,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,GACvC,aAAa,CAUf;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAMjF;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,CAW9F;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAG9D"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { indexMessage, unindexMessages } from './fulltext.js';
|
|
2
|
+
export const MESSAGE_TABLES = [
|
|
3
|
+
'CREATE TABLE conversation_reads (conversation TEXT PRIMARY KEY, read TEXT, partial INTEGER NOT NULL) WITHOUT ROWID',
|
|
4
|
+
'CREATE TABLE conversation_messages (id INTEGER PRIMARY KEY, conversation TEXT NOT NULL, identity TEXT NOT NULL, turn TEXT NOT NULL, position TEXT NOT NULL, message TEXT NOT NULL, text TEXT NOT NULL)',
|
|
5
|
+
'CREATE UNIQUE INDEX conversation_messages_identity ON conversation_messages (conversation, identity)',
|
|
6
|
+
'CREATE INDEX conversation_messages_position ON conversation_messages (conversation, position, identity)',
|
|
7
|
+
'CREATE INDEX conversation_messages_turn ON conversation_messages (conversation, turn)',
|
|
8
|
+
];
|
|
9
|
+
function text(value) {
|
|
10
|
+
return typeof value === 'string' ? value : String(value);
|
|
11
|
+
}
|
|
12
|
+
export function heldConversations(connection) {
|
|
13
|
+
const held = new Map();
|
|
14
|
+
for (const row of connection.rows('SELECT conversation, read, partial FROM conversation_reads')) {
|
|
15
|
+
held.set(text(row.conversation), {
|
|
16
|
+
conversation: text(row.conversation),
|
|
17
|
+
read: row.read === null ? null : text(row.read),
|
|
18
|
+
partial: Number(row.partial) === 1,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
for (const row of connection.rows('SELECT DISTINCT conversation FROM conversation_messages WHERE conversation NOT IN (SELECT conversation FROM conversation_reads)')) {
|
|
22
|
+
held.set(text(row.conversation), {
|
|
23
|
+
conversation: text(row.conversation),
|
|
24
|
+
read: undefined,
|
|
25
|
+
partial: true,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return [...held.values()];
|
|
29
|
+
}
|
|
30
|
+
export function keptMessages(connection, { conversation, messages, read }) {
|
|
31
|
+
for (const message of messages) {
|
|
32
|
+
const [held] = connection.rows('SELECT id FROM conversation_messages WHERE conversation = ? AND identity = ?', [conversation, message.identity]);
|
|
33
|
+
const record = [
|
|
34
|
+
message.turn,
|
|
35
|
+
message.position,
|
|
36
|
+
JSON.stringify(message.message ?? null),
|
|
37
|
+
message.text,
|
|
38
|
+
];
|
|
39
|
+
let id;
|
|
40
|
+
if (held === undefined) {
|
|
41
|
+
connection.run('INSERT INTO conversation_messages (conversation, identity, turn, position, message, text) VALUES (?, ?, ?, ?, ?, ?)', [conversation, message.identity, ...record]);
|
|
42
|
+
id = Number(connection.rows('SELECT last_insert_rowid() AS id')[0].id);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
id = Number(held.id);
|
|
46
|
+
unindexMessages(connection, [id]);
|
|
47
|
+
connection.run('UPDATE conversation_messages SET turn = ?, position = ?, message = ?, text = ? WHERE id = ?', [...record, id]);
|
|
48
|
+
}
|
|
49
|
+
indexMessage(connection, id, message.text);
|
|
50
|
+
}
|
|
51
|
+
if (read !== undefined) {
|
|
52
|
+
connection.run('INSERT OR REPLACE INTO conversation_reads (conversation, read, partial) VALUES (?, ?, ?)', [conversation, read.at, read.partial ? 1 : 0]);
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function accepted(row) {
|
|
57
|
+
return {
|
|
58
|
+
identity: text(row.identity),
|
|
59
|
+
turn: text(row.turn),
|
|
60
|
+
position: text(row.position),
|
|
61
|
+
text: text(row.text),
|
|
62
|
+
message: JSON.parse(text(row.message)),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function messageWindow(connection, conversation, limit, before) {
|
|
66
|
+
const rows = connection.rows(`SELECT identity, turn, position, message, text FROM conversation_messages WHERE conversation = ?${before === null ? '' : ' AND (position < ? OR (position = ? AND identity < ?))'} ORDER BY position DESC, identity DESC LIMIT ?`, before === null
|
|
67
|
+
? [conversation, limit + 1]
|
|
68
|
+
: [conversation, before[0], before[0], before[1], limit + 1]);
|
|
69
|
+
return { messages: rows.slice(0, limit).map(accepted).reverse(), more: rows.length > limit };
|
|
70
|
+
}
|
|
71
|
+
export function messageCount(connection, conversation) {
|
|
72
|
+
const [counted] = connection.rows('SELECT count(*) AS held FROM conversation_messages WHERE conversation = ?', [conversation]);
|
|
73
|
+
return Number(counted?.held ?? 0);
|
|
74
|
+
}
|
|
75
|
+
export function turnArrived(connection, conversation, turn) {
|
|
76
|
+
return (connection.rows('SELECT 1 FROM conversation_messages WHERE conversation = ? AND turn = ? LIMIT 1', [conversation, turn]).length > 0);
|
|
77
|
+
}
|
|
78
|
+
export function droppedMessages(connection, conversations) {
|
|
79
|
+
for (const conversation of conversations) {
|
|
80
|
+
unindexMessages(connection, connection
|
|
81
|
+
.rows('SELECT id FROM conversation_messages WHERE conversation = ?', [conversation])
|
|
82
|
+
.map((row) => Number(row.id)));
|
|
83
|
+
connection.run('DELETE FROM conversation_messages WHERE conversation = ?', [conversation]);
|
|
84
|
+
connection.run('DELETE FROM conversation_reads WHERE conversation = ?', [conversation]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export function forgottenMessages(connection) {
|
|
88
|
+
connection.run('DELETE FROM conversation_messages');
|
|
89
|
+
connection.run('DELETE FROM conversation_reads');
|
|
90
|
+
}
|
package/dist/model.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { Definition, ValueFacts, VerifiedModel } from '@agentshouse/mdmodel';
|
|
2
|
+
import type { Open } from './open.js';
|
|
2
3
|
export type ModelIdentity = {
|
|
3
4
|
identity: string;
|
|
4
5
|
version: string;
|
|
5
6
|
};
|
|
6
7
|
export type ModelSnapshot = ModelIdentity & {
|
|
7
8
|
schema: string | null;
|
|
9
|
+
revision: string | null;
|
|
8
10
|
};
|
|
9
|
-
export type ModelUnavailableReason = 'not-readable' | 'revoked' | 'not-acquired' | 'invalid'
|
|
11
|
+
export type ModelUnavailableReason = Open<'not-readable' | 'revoked' | 'not-acquired' | 'invalid'>;
|
|
10
12
|
export type ModelResult = {
|
|
11
13
|
kind: 'model';
|
|
12
14
|
snapshot: ModelSnapshot;
|
|
@@ -18,6 +20,8 @@ export type MdType = Definition;
|
|
|
18
20
|
export type ModelState = {
|
|
19
21
|
status: 'unavailable';
|
|
20
22
|
reason: ModelUnavailableReason;
|
|
23
|
+
schema?: string | null;
|
|
24
|
+
revision?: string | null;
|
|
21
25
|
} | {
|
|
22
26
|
status: 'current' | 'cached';
|
|
23
27
|
snapshot: ModelSnapshot;
|
|
@@ -25,24 +29,30 @@ export type ModelState = {
|
|
|
25
29
|
types: VerifiedModel['types'];
|
|
26
30
|
};
|
|
27
31
|
export type TypesResult = {
|
|
28
|
-
status: 'unavailable'
|
|
32
|
+
status: Open<'unavailable'>;
|
|
29
33
|
reason: ModelUnavailableReason;
|
|
34
|
+
types: null;
|
|
35
|
+
schema?: string | null;
|
|
36
|
+
revision?: string | null;
|
|
30
37
|
} | {
|
|
31
|
-
status: 'current' | 'cached'
|
|
38
|
+
status: Open<'current' | 'cached'>;
|
|
32
39
|
identity: string;
|
|
33
40
|
version: string;
|
|
34
41
|
verifiedWith: ModelIdentity;
|
|
35
42
|
types: readonly MdType[];
|
|
43
|
+
schema: string | null;
|
|
44
|
+
revision: string | null;
|
|
36
45
|
};
|
|
37
46
|
export type ValidationReceipt = {
|
|
38
47
|
identity: string;
|
|
39
48
|
version: string;
|
|
40
|
-
source: 'current' | 'cached'
|
|
49
|
+
source: Open<'current' | 'cached'>;
|
|
41
50
|
};
|
|
42
51
|
export declare const NO_MODEL: ModelState;
|
|
43
52
|
export declare function definitionOf(state: ModelState, type: string | undefined): Definition | undefined;
|
|
44
53
|
export declare function modelTypes(state: ModelState): TypesResult;
|
|
45
54
|
export declare function cached(state: ModelState): ModelState;
|
|
46
55
|
export declare function sameModel(left: ModelIdentity, right: ModelIdentity): boolean;
|
|
56
|
+
export declare function sameTyping(left: ModelState, right: ModelState): boolean;
|
|
47
57
|
export declare function referenceField(facts: ValueFacts | undefined): boolean;
|
|
48
58
|
//# sourceMappingURL=model.d.ts.map
|
package/dist/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;AACnG,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,UAAU,GAClB;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB;IACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAC5B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;CACpC,CAAC;AACF,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAGhG;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAczD;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E;AACD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CASvE;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAErE"}
|
package/dist/model.js
CHANGED
|
@@ -6,13 +6,15 @@ export function definitionOf(state, type) {
|
|
|
6
6
|
}
|
|
7
7
|
export function modelTypes(state) {
|
|
8
8
|
return state.status === 'unavailable'
|
|
9
|
-
? { ...state }
|
|
9
|
+
? { ...state, types: null }
|
|
10
10
|
: {
|
|
11
11
|
status: state.status,
|
|
12
12
|
identity: state.snapshot.identity,
|
|
13
13
|
version: state.snapshot.version,
|
|
14
14
|
verifiedWith: { ...state.verifiedWith },
|
|
15
|
-
|
|
15
|
+
schema: state.snapshot.schema,
|
|
16
|
+
revision: state.snapshot.revision,
|
|
17
|
+
types: Object.values(state.types).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0),
|
|
16
18
|
};
|
|
17
19
|
}
|
|
18
20
|
export function cached(state) {
|
|
@@ -21,6 +23,15 @@ export function cached(state) {
|
|
|
21
23
|
export function sameModel(left, right) {
|
|
22
24
|
return left.identity === right.identity && left.version === right.version;
|
|
23
25
|
}
|
|
26
|
+
export function sameTyping(left, right) {
|
|
27
|
+
if (left === right)
|
|
28
|
+
return true;
|
|
29
|
+
if (left.status === 'unavailable' || right.status === 'unavailable') {
|
|
30
|
+
return left.status === right.status;
|
|
31
|
+
}
|
|
32
|
+
return (left.snapshot.schema === right.snapshot.schema &&
|
|
33
|
+
sameModel(left.verifiedWith, right.verifiedWith));
|
|
34
|
+
}
|
|
24
35
|
export function referenceField(facts) {
|
|
25
36
|
return facts?.reference !== undefined || facts?.items?.reference !== undefined;
|
|
26
37
|
}
|
package/dist/name.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name.d.ts","sourceRoot":"","sources":["../src/name.ts"],"names":[],"mappings":"AAgHA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK9C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D"}
|
package/dist/name.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const LETTERS = {
|
|
2
|
+
а: 'a',
|
|
3
|
+
б: 'b',
|
|
4
|
+
в: 'v',
|
|
5
|
+
г: 'g',
|
|
6
|
+
ґ: 'g',
|
|
7
|
+
д: 'd',
|
|
8
|
+
ђ: 'dj',
|
|
9
|
+
ѓ: 'gj',
|
|
10
|
+
е: 'e',
|
|
11
|
+
ё: 'yo',
|
|
12
|
+
є: 'ye',
|
|
13
|
+
ж: 'zh',
|
|
14
|
+
з: 'z',
|
|
15
|
+
ѕ: 'dz',
|
|
16
|
+
и: 'i',
|
|
17
|
+
і: 'i',
|
|
18
|
+
ї: 'yi',
|
|
19
|
+
й: 'y',
|
|
20
|
+
ј: 'j',
|
|
21
|
+
к: 'k',
|
|
22
|
+
ќ: 'kj',
|
|
23
|
+
л: 'l',
|
|
24
|
+
љ: 'lj',
|
|
25
|
+
м: 'm',
|
|
26
|
+
н: 'n',
|
|
27
|
+
њ: 'nj',
|
|
28
|
+
о: 'o',
|
|
29
|
+
п: 'p',
|
|
30
|
+
р: 'r',
|
|
31
|
+
с: 's',
|
|
32
|
+
т: 't',
|
|
33
|
+
ћ: 'c',
|
|
34
|
+
у: 'u',
|
|
35
|
+
ў: 'u',
|
|
36
|
+
ф: 'f',
|
|
37
|
+
х: 'kh',
|
|
38
|
+
ц: 'ts',
|
|
39
|
+
ч: 'ch',
|
|
40
|
+
џ: 'dz',
|
|
41
|
+
ш: 'sh',
|
|
42
|
+
щ: 'shch',
|
|
43
|
+
ъ: '',
|
|
44
|
+
ы: 'y',
|
|
45
|
+
ь: '',
|
|
46
|
+
э: 'e',
|
|
47
|
+
ю: 'yu',
|
|
48
|
+
я: 'ya',
|
|
49
|
+
α: 'a',
|
|
50
|
+
β: 'v',
|
|
51
|
+
γ: 'g',
|
|
52
|
+
δ: 'd',
|
|
53
|
+
ε: 'e',
|
|
54
|
+
ζ: 'z',
|
|
55
|
+
η: 'i',
|
|
56
|
+
θ: 'th',
|
|
57
|
+
ι: 'i',
|
|
58
|
+
κ: 'k',
|
|
59
|
+
λ: 'l',
|
|
60
|
+
μ: 'm',
|
|
61
|
+
ν: 'n',
|
|
62
|
+
ξ: 'x',
|
|
63
|
+
ο: 'o',
|
|
64
|
+
π: 'p',
|
|
65
|
+
ρ: 'r',
|
|
66
|
+
σ: 's',
|
|
67
|
+
ς: 's',
|
|
68
|
+
τ: 't',
|
|
69
|
+
υ: 'y',
|
|
70
|
+
φ: 'f',
|
|
71
|
+
χ: 'ch',
|
|
72
|
+
ψ: 'ps',
|
|
73
|
+
ω: 'o',
|
|
74
|
+
ß: 'ss',
|
|
75
|
+
æ: 'ae',
|
|
76
|
+
œ: 'oe',
|
|
77
|
+
ø: 'o',
|
|
78
|
+
đ: 'd',
|
|
79
|
+
ð: 'd',
|
|
80
|
+
þ: 'th',
|
|
81
|
+
ł: 'l',
|
|
82
|
+
ı: 'i',
|
|
83
|
+
};
|
|
84
|
+
const MARKS = /\p{M}/gu;
|
|
85
|
+
const ADMITTED = /^[a-z0-9]$/;
|
|
86
|
+
const WORDLIKE = /^[\p{L}\p{N}]$/u;
|
|
87
|
+
function lowerLetterOf(character) {
|
|
88
|
+
const known = LETTERS[character];
|
|
89
|
+
if (known !== undefined)
|
|
90
|
+
return known;
|
|
91
|
+
const bare = character.normalize('NFKD').replace(MARKS, '');
|
|
92
|
+
const mapped = LETTERS[bare];
|
|
93
|
+
if (mapped !== undefined)
|
|
94
|
+
return mapped;
|
|
95
|
+
return [...bare].every((one) => ADMITTED.test(one)) ? bare : null;
|
|
96
|
+
}
|
|
97
|
+
function codePoint(character) {
|
|
98
|
+
return WORDLIKE.test(character) ? `-u${character.codePointAt(0)?.toString(16) ?? ''}-` : '-';
|
|
99
|
+
}
|
|
100
|
+
function latin(text, unknown) {
|
|
101
|
+
return [...text]
|
|
102
|
+
.map((character) => {
|
|
103
|
+
if ((character.codePointAt(0) ?? 0) < 0x80)
|
|
104
|
+
return character;
|
|
105
|
+
const lower = character.toLowerCase();
|
|
106
|
+
const letter = lowerLetterOf(lower) ?? unknown(lower);
|
|
107
|
+
return lower === character ? letter : `${letter.charAt(0).toUpperCase()}${letter.slice(1)}`;
|
|
108
|
+
})
|
|
109
|
+
.join('');
|
|
110
|
+
}
|
|
111
|
+
export function transliterated(text) {
|
|
112
|
+
return latin(text, () => '-');
|
|
113
|
+
}
|
|
114
|
+
export function nameFrom(title) {
|
|
115
|
+
return latin(title, codePoint)
|
|
116
|
+
.toLowerCase()
|
|
117
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
118
|
+
.replace(/^-+|-+$/g, '');
|
|
119
|
+
}
|
|
120
|
+
export function cutName(name, most) {
|
|
121
|
+
return name.slice(0, most).replace(/-+$/, '');
|
|
122
|
+
}
|