@agentshouse/mdruntime 0.1.0-ca9afacd5aebd → 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 +18 -15
- package/dist/adapter.d.ts +99 -36
- 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 +21 -4
- package/dist/attempt.d.ts.map +1 -1
- package/dist/attempt.js +14 -1
- package/dist/binary.d.ts +0 -5
- package/dist/binary.d.ts.map +1 -1
- package/dist/binary.js +1 -1
- package/dist/bootstrap.d.ts +31 -9
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +155 -64
- 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 -63
- package/dist/change.d.ts +31 -1
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +10 -1
- package/dist/client.d.ts +24 -12
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +49 -9
- package/dist/collection.d.ts +7 -6
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +30 -77
- 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 +42 -15
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +3415 -810
- package/dist/conversation.d.ts +30 -9
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +549 -181
- 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/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 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +126 -16
- package/dist/identity.d.ts +1 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +3 -0
- package/dist/index.d.ts +15 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -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 +10 -3
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +54 -26
- 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 +4 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +11 -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/opened.d.ts +22 -0
- package/dist/opened.d.ts.map +1 -0
- package/dist/opened.js +107 -0
- package/dist/outcome.d.ts +38 -4
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +26 -0
- package/dist/overlay.d.ts +3 -4
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +100 -182
- package/dist/query.d.ts +66 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +48 -7
- package/dist/reach.d.ts +17 -6
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +205 -68
- package/dist/react.d.ts +8 -6
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -17
- 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 +16 -15
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +113 -49
- package/dist/replica.d.ts +56 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +297 -162
- package/dist/room-draft.d.ts +17 -2
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +65 -25
- package/dist/rows.d.ts +35 -37
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +165 -105
- package/dist/save.d.ts +50 -9
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +528 -166
- package/dist/search.d.ts +39 -28
- 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 +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +116 -74
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +353 -444
- 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 +164 -32
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +55 -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 +27 -24
- package/AGENTS.md +0 -318
- package/dist/chat/acts.d.ts +0 -34
- package/dist/chat/acts.d.ts.map +0 -1
- package/dist/chat/acts.js +0 -36
- package/dist/chat/context.d.ts +0 -3
- package/dist/chat/context.d.ts.map +0 -1
- package/dist/chat/context.js +0 -10
- package/dist/chat/input.d.ts +0 -9
- package/dist/chat/input.d.ts.map +0 -1
- package/dist/chat/input.js +0 -99
- package/dist/chat/kit.d.ts +0 -60
- package/dist/chat/kit.d.ts.map +0 -1
- package/dist/chat/kit.js +0 -123
- package/dist/chat/lasting.d.ts +0 -6
- package/dist/chat/lasting.d.ts.map +0 -1
- package/dist/chat/lasting.js +0 -19
- package/dist/chat/list.d.ts +0 -20
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -59
- package/dist/chat/markdown.d.ts +0 -19
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -187
- package/dist/chat/message.d.ts +0 -6
- package/dist/chat/message.d.ts.map +0 -1
- package/dist/chat/message.js +0 -192
- package/dist/chat/messages.d.ts +0 -21
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -151
- package/dist/chat/name.d.ts +0 -6
- package/dist/chat/name.d.ts.map +0 -1
- package/dist/chat/name.js +0 -37
- package/dist/chat/opened.d.ts +0 -11
- package/dist/chat/opened.d.ts.map +0 -1
- package/dist/chat/opened.js +0 -17
- package/dist/chat/overlay.d.ts +0 -31
- package/dist/chat/overlay.d.ts.map +0 -1
- package/dist/chat/overlay.js +0 -97
- package/dist/chat/parts.d.ts +0 -57
- package/dist/chat/parts.d.ts.map +0 -1
- package/dist/chat/parts.js +0 -119
- package/dist/chat/process.d.ts +0 -20
- package/dist/chat/process.d.ts.map +0 -1
- package/dist/chat/process.js +0 -32
- package/dist/chat/provider.d.ts +0 -63
- package/dist/chat/provider.d.ts.map +0 -1
- package/dist/chat/provider.js +0 -645
- package/dist/chat/question.d.ts +0 -9
- package/dist/chat/question.d.ts.map +0 -1
- package/dist/chat/question.js +0 -80
- package/dist/chat/questions.d.ts +0 -31
- package/dist/chat/questions.d.ts.map +0 -1
- package/dist/chat/questions.js +0 -111
- package/dist/chat/read.d.ts +0 -5
- package/dist/chat/read.d.ts.map +0 -1
- package/dist/chat/read.js +0 -13
- package/dist/chat/ready.d.ts +0 -33
- package/dist/chat/ready.d.ts.map +0 -1
- package/dist/chat/ready.js +0 -91
- package/dist/chat/style.d.ts +0 -4
- package/dist/chat/style.d.ts.map +0 -1
- package/dist/chat/style.js +0 -302
- package/dist/chat.d.ts +0 -14
- package/dist/chat.d.ts.map +0 -1
- package/dist/chat.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 -440
package/dist/query.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { pointerFacts, } from '@agentshouse/mdmodel';
|
|
2
2
|
import { referenceField } from './model.js';
|
|
3
3
|
import { normalize } from './paths.js';
|
|
4
|
+
import { decodedCursor } from './windows.js';
|
|
4
5
|
export class QueryError extends Error {
|
|
5
6
|
code;
|
|
6
7
|
retryable = false;
|
|
@@ -11,9 +12,18 @@ export class QueryError extends Error {
|
|
|
11
12
|
}
|
|
12
13
|
const RANGE = ['$gt', '$gte', '$lt', '$lte'];
|
|
13
14
|
const SINGLE = ['$eq', '$ne', '$in', '$nin', '$all', '$size', '$exists'];
|
|
14
|
-
const FILTER = ['rooms', 'types', 'where', 'pathPrefix', 'hop', 'backlinks'];
|
|
15
|
+
const FILTER = ['rooms', 'types', 'where', 'pathPrefix', 'folder', 'paths', 'hop', 'backlinks'];
|
|
15
16
|
const RELATED = ['types', 'where', 'pathPrefix', 'field'];
|
|
16
|
-
const PARTS = [
|
|
17
|
+
const PARTS = [
|
|
18
|
+
'fields',
|
|
19
|
+
'sections',
|
|
20
|
+
'preamble',
|
|
21
|
+
'markdown',
|
|
22
|
+
'backlinks',
|
|
23
|
+
'change',
|
|
24
|
+
'fileId',
|
|
25
|
+
'revision',
|
|
26
|
+
];
|
|
17
27
|
const ORDER = ['by', 'direction', 'nulls', 'stringSort', 'locale', 'localeOptions'];
|
|
18
28
|
const CALENDAR_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
19
29
|
const STRAY_ESCAPE = /~(?![01])/u;
|
|
@@ -60,6 +70,13 @@ function names(input, at) {
|
|
|
60
70
|
invalid(at, 'expects a list of names');
|
|
61
71
|
return [...new Set(listed)].sort();
|
|
62
72
|
}
|
|
73
|
+
function pathsOf(input) {
|
|
74
|
+
const listed = list(input, 'paths');
|
|
75
|
+
if (listed.some((item) => typeof item !== 'string' || item === '' || normalize(item) !== item)) {
|
|
76
|
+
invalid('paths', 'expects a list of Paths');
|
|
77
|
+
}
|
|
78
|
+
return [...new Set(listed)].sort();
|
|
79
|
+
}
|
|
63
80
|
function directory(input, at) {
|
|
64
81
|
if (typeof input !== 'string' || normalize(input) !== input) {
|
|
65
82
|
invalid(at, 'expects a normalized directory');
|
|
@@ -279,15 +296,16 @@ function backlinksOf(facts, rooms, input) {
|
|
|
279
296
|
return { types, where, pathPrefix, field };
|
|
280
297
|
}
|
|
281
298
|
function keyPlan(typed, input, at, path) {
|
|
282
|
-
if (input === 'room' || input === 'type' || (path && input === 'path'))
|
|
299
|
+
if (input === 'room' || input === 'type' || input === 'folder' || (path && input === 'path')) {
|
|
283
300
|
return { of: input };
|
|
301
|
+
}
|
|
284
302
|
if (plain(input) && Object.hasOwn(input, 'field') && Object.keys(input).length === 1) {
|
|
285
303
|
if (specs(typed, input.field, place(at, 'field')).some(several)) {
|
|
286
304
|
invalid(place(at, 'field'), 'a path that can hold several values');
|
|
287
305
|
}
|
|
288
306
|
return { of: 'field', field: input.field };
|
|
289
307
|
}
|
|
290
|
-
return invalid(at, path ? 'expects room, path, type or a field' : 'expects room, type or a field');
|
|
308
|
+
return invalid(at, path ? 'expects room, path, type, folder or a field' : 'expects room, type, folder or a field');
|
|
291
309
|
}
|
|
292
310
|
function direction(input, at) {
|
|
293
311
|
if (input === undefined)
|
|
@@ -349,7 +367,7 @@ function parts(typed, input, at, fields) {
|
|
|
349
367
|
});
|
|
350
368
|
return named;
|
|
351
369
|
}
|
|
352
|
-
function flag(input, at) {
|
|
370
|
+
export function flag(input, at) {
|
|
353
371
|
if (input === undefined)
|
|
354
372
|
return false;
|
|
355
373
|
if (input !== true)
|
|
@@ -377,6 +395,8 @@ function documentShape(typed, input) {
|
|
|
377
395
|
markdown: true,
|
|
378
396
|
backlinks: true,
|
|
379
397
|
change: true,
|
|
398
|
+
fileId: true,
|
|
399
|
+
revision: true,
|
|
380
400
|
orderBy,
|
|
381
401
|
};
|
|
382
402
|
}
|
|
@@ -391,6 +411,8 @@ function documentShape(typed, input) {
|
|
|
391
411
|
markdown: flag(select.markdown, 'select.markdown'),
|
|
392
412
|
backlinks: flag(select.backlinks, 'select.backlinks'),
|
|
393
413
|
change: flag(select.change, 'select.change'),
|
|
414
|
+
fileId: flag(select.fileId, 'select.fileId'),
|
|
415
|
+
revision: flag(select.revision, 'select.revision'),
|
|
394
416
|
orderBy,
|
|
395
417
|
};
|
|
396
418
|
}
|
|
@@ -421,20 +443,36 @@ export function planOf(input, facts, reach = null) {
|
|
|
421
443
|
invalid('select', 'a grouped query selects nothing');
|
|
422
444
|
if (!grouped && input.select === undefined)
|
|
423
445
|
invalid('select', 'a Document query must select');
|
|
424
|
-
known(input, [...FILTER, 'orderBy', 'limit', grouped ? 'groupBy' : 'select'], '');
|
|
446
|
+
known(input, [...FILTER, 'orderBy', 'limit', 'after', 'total', grouped ? 'groupBy' : 'select'], '');
|
|
425
447
|
const limit = limitOf(input.limit);
|
|
426
448
|
const rooms = input.rooms === undefined ? null : names(input.rooms, 'rooms');
|
|
427
449
|
const { typed, ...root } = scope(facts, rooms, input, '');
|
|
450
|
+
const shape = grouped ? groupShape(typed, input) : documentShape(typed, input);
|
|
428
451
|
return {
|
|
452
|
+
key: queryKey(input),
|
|
429
453
|
rooms,
|
|
430
454
|
reach,
|
|
455
|
+
locked: [],
|
|
431
456
|
root,
|
|
457
|
+
folder: input.folder === undefined ? null : directory(input.folder, 'folder'),
|
|
458
|
+
paths: input.paths === undefined ? null : pathsOf(input.paths),
|
|
432
459
|
hop: input.hop === undefined ? null : hopOf(facts, rooms, typed, input.hop),
|
|
433
460
|
backlinks: input.backlinks === undefined ? null : backlinksOf(facts, rooms, input.backlinks),
|
|
434
|
-
shape
|
|
461
|
+
shape,
|
|
435
462
|
limit,
|
|
463
|
+
after: continuationOf(input.after, shape.orderBy.length + 1),
|
|
464
|
+
total: flag(input.total, 'total'),
|
|
436
465
|
};
|
|
437
466
|
}
|
|
467
|
+
function continuationOf(input, arity) {
|
|
468
|
+
if (input === undefined)
|
|
469
|
+
return null;
|
|
470
|
+
const values = typeof input === 'string' ? decodedCursor(input) : null;
|
|
471
|
+
if (values === null || (values.length !== 0 && values.length !== arity)) {
|
|
472
|
+
invalid('after', 'expects the next an earlier result of this query returned');
|
|
473
|
+
}
|
|
474
|
+
return { text: input, values: values.length === 0 ? null : values };
|
|
475
|
+
}
|
|
438
476
|
export function limitOf(input) {
|
|
439
477
|
if (input === undefined)
|
|
440
478
|
return null;
|
|
@@ -449,6 +487,9 @@ export function filterOf(input, facts, reach = null) {
|
|
|
449
487
|
known(input, FILTER, '');
|
|
450
488
|
return planOf({ ...input, select: {} }, facts, reach);
|
|
451
489
|
}
|
|
490
|
+
export function queryKey(query) {
|
|
491
|
+
return canonical(query);
|
|
492
|
+
}
|
|
452
493
|
function canonical(value) {
|
|
453
494
|
if (Array.isArray(value))
|
|
454
495
|
return `[${value.map(canonical).join(',')}]`;
|
package/dist/reach.d.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { MdRuntime, RuntimeTopic } from './connection.js';
|
|
1
|
+
import type { MdRuntime, ReadinessPort, RuntimeTopic } from './connection.js';
|
|
3
2
|
import type { Plan, PlanReach, QueryResult } from './query.js';
|
|
4
|
-
import type {
|
|
3
|
+
import type { Readiness } from './readiness.js';
|
|
4
|
+
import { type SearchResult } from './search.js';
|
|
5
5
|
export type ReachedDocument = {
|
|
6
6
|
readonly room: string;
|
|
7
7
|
readonly path: string;
|
|
8
8
|
};
|
|
9
|
+
export type ReachedArea = {
|
|
10
|
+
readonly room: string;
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly types: readonly string[];
|
|
13
|
+
};
|
|
9
14
|
export type PortReach = {
|
|
10
15
|
readonly rooms: readonly string[];
|
|
11
16
|
readonly documents: readonly ReachedDocument[];
|
|
17
|
+
readonly areas?: readonly ReachedArea[];
|
|
12
18
|
readonly conversations: boolean;
|
|
13
19
|
};
|
|
14
20
|
export type Deliver = (message: unknown) => void;
|
|
@@ -19,13 +25,18 @@ export type RuntimeView = {
|
|
|
19
25
|
};
|
|
20
26
|
export type NarrowedView = RuntimeView & {
|
|
21
27
|
narrow(reach: PortReach | null): void;
|
|
28
|
+
facts(port: ReadinessPort): void;
|
|
22
29
|
};
|
|
23
30
|
export type Reachable = RuntimeView & {
|
|
24
31
|
plan(input: unknown, reach: PortReach | null): Plan;
|
|
25
32
|
query(plan: Plan): Promise<QueryResult>;
|
|
26
33
|
watchPlan(plan: Plan, deliver: (message: unknown) => void): () => void;
|
|
27
|
-
search(input: unknown, reach: PortReach | null): Promise<SearchResult>;
|
|
28
|
-
|
|
34
|
+
search(input: unknown, reach: PortReach | null, locked: readonly string[]): Promise<SearchResult>;
|
|
35
|
+
watchReadiness(port: ReadinessPort, reach: PortReach | null, deliver: (readiness: Readiness) => void): () => void;
|
|
36
|
+
locked(room: string): boolean;
|
|
37
|
+
lockedRooms(): readonly string[];
|
|
38
|
+
watchLocks(notify: () => void): () => void;
|
|
39
|
+
located(room: string, path: string, destination: string): ReachedDocument | null;
|
|
29
40
|
};
|
|
30
41
|
export declare function holds(reach: PortReach | null, room: string): boolean;
|
|
31
42
|
export declare function governs(reach: PortReach | null, room: {
|
|
@@ -38,5 +49,5 @@ export declare function governs(reach: PortReach | null, room: {
|
|
|
38
49
|
readonly selection: boolean;
|
|
39
50
|
};
|
|
40
51
|
export declare function planReach(reach: PortReach | null): PlanReach | null;
|
|
41
|
-
export declare function narrowed(runtime: Reachable, given: PortReach | null): NarrowedView;
|
|
52
|
+
export declare function narrowed(runtime: Reachable, given: PortReach | null, told: ReadinessPort): NarrowedView;
|
|
42
53
|
//# sourceMappingURL=reach.d.ts.map
|
package/dist/reach.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reach.d.ts","sourceRoot":"","sources":["../src/reach.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"reach.d.ts","sourceRoot":"","sources":["../src/reach.ts"],"names":[],"mappings":"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"}
|
package/dist/reach.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { unheldView } from './conversation.js';
|
|
2
2
|
import { modelTypes, NO_MODEL } from './model.js';
|
|
3
|
-
import {
|
|
3
|
+
import { changeOf, digestApplied, digestOf, observing, } from './observation.js';
|
|
4
4
|
import { runtimeError } from './failure.js';
|
|
5
|
-
import { failure, undeclared, } from './outcome.js';
|
|
5
|
+
import { failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
|
|
6
6
|
import { beneath } from './paths.js';
|
|
7
|
-
import { reconciled } from './read-side.js';
|
|
8
7
|
import { moveTarget, readParts, staleWrite, } from './room-draft.js';
|
|
9
8
|
import { documentKey } from './rows.js';
|
|
9
|
+
import { undeclaredSearch } from './search.js';
|
|
10
10
|
const UNHELD_TYPES = { collection: modelTypes(NO_MODEL), typedSelection: null };
|
|
11
11
|
function unconversed(name) {
|
|
12
12
|
return () => Promise.resolve(undeclared(name));
|
|
@@ -16,6 +16,7 @@ const NO_CONVERSATION = {
|
|
|
16
16
|
read: (conversation) => Promise.resolve(unheldView(conversation)),
|
|
17
17
|
create: unconversed('conversation.create'),
|
|
18
18
|
send: unconversed('conversation.send'),
|
|
19
|
+
attach: unconversed('conversation.attach'),
|
|
19
20
|
answer: unconversed('conversation.answer'),
|
|
20
21
|
interrupt: unconversed('conversation.interrupt'),
|
|
21
22
|
kill: unconversed('conversation.kill'),
|
|
@@ -24,12 +25,23 @@ const NO_CONVERSATION = {
|
|
|
24
25
|
};
|
|
25
26
|
const NO_CHAT_DRAFT = {
|
|
26
27
|
write: () => Promise.resolve(),
|
|
28
|
+
prepend: () => Promise.resolve(),
|
|
27
29
|
discard: () => Promise.resolve(),
|
|
28
30
|
};
|
|
31
|
+
function areasOf(reach) {
|
|
32
|
+
return reach.areas ?? [];
|
|
33
|
+
}
|
|
34
|
+
function typedAreas(reach, room) {
|
|
35
|
+
return areasOf(reach).filter((area) => area.room === room && area.types.length > 0);
|
|
36
|
+
}
|
|
37
|
+
function fenced(reach, room, path) {
|
|
38
|
+
return areasOf(reach).some((area) => area.room === room && beneath(area.path, path));
|
|
39
|
+
}
|
|
29
40
|
export function holds(reach, room) {
|
|
30
41
|
return (reach === null ||
|
|
31
42
|
reach.rooms.includes(room) ||
|
|
32
|
-
reach.documents.some((document) => document.room === room)
|
|
43
|
+
reach.documents.some((document) => document.room === room) ||
|
|
44
|
+
typedAreas(reach, room).length > 0);
|
|
33
45
|
}
|
|
34
46
|
function wholly(reach, room) {
|
|
35
47
|
return reach === null || reach.rooms.includes(room);
|
|
@@ -39,33 +51,23 @@ export function governs(reach, room) {
|
|
|
39
51
|
return { collection: true, selection: room.typedSelection !== null };
|
|
40
52
|
}
|
|
41
53
|
const selected = (path) => room.typedSelection?.roots.some((root) => beneath(root, path)) ?? false;
|
|
42
|
-
const paths =
|
|
43
|
-
.
|
|
44
|
-
|
|
54
|
+
const paths = [
|
|
55
|
+
...reach.documents
|
|
56
|
+
.filter((document) => document.room === room.locator)
|
|
57
|
+
.map(({ path }) => path),
|
|
58
|
+
...typedAreas(reach, room.locator).map(({ path }) => path),
|
|
59
|
+
];
|
|
45
60
|
return { collection: paths.some((path) => !selected(path)), selection: paths.some(selected) };
|
|
46
61
|
}
|
|
47
62
|
function covers(reach, room, path) {
|
|
48
63
|
return (reach === null ||
|
|
49
|
-
reach
|
|
50
|
-
|
|
64
|
+
(!fenced(reach, room, path) &&
|
|
65
|
+
(reach.rooms.includes(room) ||
|
|
66
|
+
reach.documents.some((document) => document.room === room && document.path === path))));
|
|
51
67
|
}
|
|
52
68
|
function conversing(reach) {
|
|
53
69
|
return reach === null || reach.conversations;
|
|
54
70
|
}
|
|
55
|
-
function refers(reach, scope) {
|
|
56
|
-
if (reach === null)
|
|
57
|
-
return true;
|
|
58
|
-
if (scope === null)
|
|
59
|
-
return false;
|
|
60
|
-
if (scope.kind === 'conversations')
|
|
61
|
-
return reach.conversations;
|
|
62
|
-
return scope.path === undefined
|
|
63
|
-
? wholly(reach, scope.locator)
|
|
64
|
-
: covers(reach, scope.locator, scope.path);
|
|
65
|
-
}
|
|
66
|
-
function unreachedReference(fileRef) {
|
|
67
|
-
return { kind: 'absent', code: 'binary-file-absent', fields: { fileRef }, retryable: false };
|
|
68
|
-
}
|
|
69
71
|
export function planReach(reach) {
|
|
70
72
|
return reach === null
|
|
71
73
|
? null
|
|
@@ -74,6 +76,9 @@ export function planReach(reach) {
|
|
|
74
76
|
documents: [
|
|
75
77
|
...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
|
|
76
78
|
].sort(),
|
|
79
|
+
areas: areasOf(reach)
|
|
80
|
+
.map(({ room, path, types }) => ({ room, path, types: [...new Set(types)].sort() }))
|
|
81
|
+
.sort((left, right) => documentKey(left.room, left.path) < documentKey(right.room, right.path) ? -1 : 1),
|
|
77
82
|
};
|
|
78
83
|
}
|
|
79
84
|
function roomsWithin(reach, rooms) {
|
|
@@ -89,7 +94,7 @@ function typesWithin(reach, room, types) {
|
|
|
89
94
|
};
|
|
90
95
|
}
|
|
91
96
|
function moves(reach, room, move) {
|
|
92
|
-
return move === undefined || covers(reach, room, moveTarget(move));
|
|
97
|
+
return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
|
|
93
98
|
}
|
|
94
99
|
function draftWithin(reach, draft) {
|
|
95
100
|
return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
|
|
@@ -122,76 +127,120 @@ function savedWithin(reach, room, result) {
|
|
|
122
127
|
function statusWithin(reach, status) {
|
|
123
128
|
return {
|
|
124
129
|
...status,
|
|
125
|
-
attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
|
|
130
|
+
attentionRequired: status.attentionRequired.filter((entry) => 'refusal' in entry ? wholly(reach, entry.room) : covers(reach, entry.room, entry.path)),
|
|
126
131
|
};
|
|
127
132
|
}
|
|
128
133
|
function queueWithin(reach, room, entries) {
|
|
129
|
-
return entries
|
|
130
|
-
(
|
|
134
|
+
return entries
|
|
135
|
+
.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
|
|
136
|
+
(change.kind !== 'move' || covers(reach, room, change.to))))
|
|
137
|
+
.map((entry) => {
|
|
138
|
+
const { between, ...batch } = entry.batch;
|
|
139
|
+
if (between === undefined)
|
|
140
|
+
return entry;
|
|
141
|
+
return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
|
|
142
|
+
? entry
|
|
143
|
+
: { ...entry, batch };
|
|
144
|
+
});
|
|
131
145
|
}
|
|
132
146
|
function unreached(room) {
|
|
133
147
|
return runtimeError('room-not-held', `No Local Replica for ${room}`);
|
|
134
148
|
}
|
|
135
|
-
|
|
149
|
+
function lockedError(room) {
|
|
150
|
+
return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
|
|
151
|
+
}
|
|
152
|
+
function deviceUnreached() {
|
|
153
|
+
return runtimeError('device-unreached', 'Only the panel cleans up this device');
|
|
154
|
+
}
|
|
155
|
+
export function narrowed(runtime, given, told) {
|
|
136
156
|
const { md, watch } = runtime;
|
|
137
157
|
let reach = given;
|
|
158
|
+
let port = told;
|
|
138
159
|
const open = new Set();
|
|
139
|
-
function following(begin) {
|
|
160
|
+
function following(begin, locking = false) {
|
|
140
161
|
let stop = begin();
|
|
141
162
|
const restart = () => {
|
|
142
163
|
stop();
|
|
143
164
|
stop = begin();
|
|
144
165
|
};
|
|
145
166
|
open.add(restart);
|
|
167
|
+
const unwatch = locking ? runtime.watchLocks(restart) : () => { };
|
|
146
168
|
return () => {
|
|
147
169
|
open.delete(restart);
|
|
170
|
+
unwatch();
|
|
148
171
|
stop();
|
|
149
172
|
};
|
|
150
173
|
}
|
|
174
|
+
const unlocking = (rooms) => {
|
|
175
|
+
const locked = (rooms ?? []).filter((room) => runtime.locked(room));
|
|
176
|
+
return locked.length === 0
|
|
177
|
+
? null
|
|
178
|
+
: { pending: locked.map((room) => ({ room, awaits: 'unlock' })) };
|
|
179
|
+
};
|
|
180
|
+
const unlocked = (entries) => entries.filter((entry) => !runtime.locked(entry.room));
|
|
181
|
+
const intoLocked = (held) => held.some((move) => move?.room !== undefined && runtime.locked(move.room));
|
|
151
182
|
const within = (topic, input, deliver) => {
|
|
152
183
|
if (topic === 'rooms') {
|
|
153
184
|
return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
|
|
154
185
|
}
|
|
186
|
+
if (topic === 'readiness') {
|
|
187
|
+
return following(() => runtime.watchReadiness(port, reach, deliver));
|
|
188
|
+
}
|
|
155
189
|
if (topic === 'sync-status') {
|
|
156
|
-
return following(() => watch(topic, input, (status) =>
|
|
190
|
+
return following(() => watch(topic, input, (status) => {
|
|
191
|
+
const within = statusWithin(reach, status);
|
|
192
|
+
deliver({ ...within, attentionRequired: unlocked(within.attentionRequired) });
|
|
193
|
+
}), true);
|
|
157
194
|
}
|
|
158
195
|
if (topic === 'room-drafts') {
|
|
159
|
-
return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
|
|
196
|
+
return following(() => watch(topic, input, (drafts) => deliver(unlocked(draftsWithin(reach, drafts)))), true);
|
|
160
197
|
}
|
|
161
198
|
if (topic === 'queue') {
|
|
162
199
|
const room = input[0];
|
|
163
200
|
return following(() => {
|
|
164
|
-
if (!holds(reach, room)) {
|
|
201
|
+
if (!holds(reach, room) || runtime.locked(room)) {
|
|
165
202
|
deliver([]);
|
|
166
203
|
return () => { };
|
|
167
204
|
}
|
|
168
205
|
return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
|
|
169
|
-
});
|
|
206
|
+
}, true);
|
|
170
207
|
}
|
|
171
208
|
if (topic === 'query') {
|
|
172
209
|
const plan = runtime.plan(input[0], reach);
|
|
173
210
|
let held = null;
|
|
174
211
|
return following(() => {
|
|
212
|
+
const locked = unlocking(plan.rooms);
|
|
213
|
+
if (locked !== null) {
|
|
214
|
+
const answer = { result: locked, keys: [] };
|
|
215
|
+
if (held === null || changeOf(held, answer) !== null)
|
|
216
|
+
deliver(answer);
|
|
217
|
+
held = digestOf(answer);
|
|
218
|
+
return () => { };
|
|
219
|
+
}
|
|
175
220
|
let first = true;
|
|
176
|
-
|
|
221
|
+
let open = true;
|
|
222
|
+
const heard = (message) => {
|
|
177
223
|
if (!first) {
|
|
178
|
-
held =
|
|
224
|
+
held = digestApplied(held, message);
|
|
179
225
|
deliver(message);
|
|
180
226
|
return;
|
|
181
227
|
}
|
|
182
228
|
first = false;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
deliver(next.change);
|
|
229
|
+
const change = held === null ? message : changeOf(held, message);
|
|
230
|
+
held = digestOf(message);
|
|
231
|
+
if (change !== null)
|
|
232
|
+
deliver(change);
|
|
233
|
+
};
|
|
234
|
+
const current = { ...plan, reach: planReach(reach), locked: runtime.lockedRooms() };
|
|
235
|
+
const stop = runtime.watchPlan(current, (message) => {
|
|
236
|
+
if (open)
|
|
237
|
+
heard(message);
|
|
193
238
|
});
|
|
194
|
-
|
|
239
|
+
return () => {
|
|
240
|
+
open = false;
|
|
241
|
+
stop();
|
|
242
|
+
};
|
|
243
|
+
}, true);
|
|
195
244
|
}
|
|
196
245
|
if (topic === 'conversation') {
|
|
197
246
|
return following(() => {
|
|
@@ -211,14 +260,32 @@ export function narrowed(runtime, given) {
|
|
|
211
260
|
}
|
|
212
261
|
return watch(topic, input, deliver);
|
|
213
262
|
};
|
|
263
|
+
const files = new Map();
|
|
264
|
+
let handed = 0;
|
|
265
|
+
const hand = async (reading) => {
|
|
266
|
+
const answer = await reading;
|
|
267
|
+
if (answer.kind !== 'binary')
|
|
268
|
+
return answer;
|
|
269
|
+
handed += 1;
|
|
270
|
+
const file = String(handed);
|
|
271
|
+
files.set(file, answer.file);
|
|
272
|
+
return { ...answer, file };
|
|
273
|
+
};
|
|
214
274
|
const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
|
|
215
275
|
const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
|
|
216
276
|
const view = {
|
|
217
277
|
...md,
|
|
218
278
|
rooms: () => roomsWithin(reach, md.rooms()),
|
|
219
|
-
query: ((input) =>
|
|
220
|
-
|
|
279
|
+
query: ((input) => {
|
|
280
|
+
const plan = runtime.plan(input, reach);
|
|
281
|
+
return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
|
|
282
|
+
}),
|
|
283
|
+
search: (input) => port.search === 'required'
|
|
284
|
+
? runtime.search(input, reach, runtime.lockedRooms())
|
|
285
|
+
: Promise.resolve(undeclaredSearch()),
|
|
221
286
|
types(room) {
|
|
287
|
+
if (holds(reach, room) && runtime.locked(room))
|
|
288
|
+
throw lockedError(room);
|
|
222
289
|
if (wholly(reach, room))
|
|
223
290
|
return md.types(room);
|
|
224
291
|
if (!holds(reach, room))
|
|
@@ -229,39 +296,98 @@ export function narrowed(runtime, given) {
|
|
|
229
296
|
async save(room, roomDrafts, writtenBy) {
|
|
230
297
|
if (!holds(reach, room))
|
|
231
298
|
throw unreached(room);
|
|
232
|
-
|
|
233
|
-
|
|
299
|
+
if (runtime.locked(room))
|
|
300
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
301
|
+
const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
|
|
302
|
+
const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
|
|
234
303
|
if (outside !== undefined) {
|
|
235
304
|
return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
|
|
236
305
|
}
|
|
306
|
+
if (intoLocked(held))
|
|
307
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
237
308
|
return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
|
|
238
309
|
},
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
310
|
+
async saveParts(room, parts, writtenBy) {
|
|
311
|
+
if (!holds(reach, room))
|
|
312
|
+
throw unreached(room);
|
|
313
|
+
if (runtime.locked(room))
|
|
314
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
315
|
+
const held = parts.map(({ parts: one }) => readParts(one).move);
|
|
316
|
+
if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
|
|
317
|
+
throw unreached(room);
|
|
318
|
+
}
|
|
319
|
+
if (intoLocked(held))
|
|
320
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
321
|
+
return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
|
|
322
|
+
},
|
|
323
|
+
resolve(room, path, destination) {
|
|
324
|
+
const at = runtime.located(room, path, destination);
|
|
325
|
+
return at !== null && !covers(reach, at.room, at.path)
|
|
326
|
+
? Promise.resolve(UNREADABLE)
|
|
327
|
+
: md.resolve(room, path, destination);
|
|
328
|
+
},
|
|
329
|
+
history: (room, path, query) => !covers(reach, room, path)
|
|
330
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
331
|
+
: runtime.locked(room)
|
|
332
|
+
? Promise.resolve(lockedRoom(room))
|
|
333
|
+
: md.history(room, path, query),
|
|
242
334
|
binaryFile: {
|
|
243
|
-
read: (room, path, revision) => covers(reach, room, path)
|
|
244
|
-
?
|
|
245
|
-
:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
335
|
+
read: (room, path, revision) => !covers(reach, room, path)
|
|
336
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
337
|
+
: runtime.locked(room)
|
|
338
|
+
? Promise.resolve(lockedRoom(room))
|
|
339
|
+
: hand(md.binaryFile.read(room, path, revision)),
|
|
340
|
+
link: (room, path, revision) => !covers(reach, room, path)
|
|
341
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
342
|
+
: runtime.locked(room)
|
|
343
|
+
? Promise.resolve(lockedRoom(room))
|
|
344
|
+
: md.binaryFile.link(room, path, revision),
|
|
345
|
+
async part(file, part) {
|
|
346
|
+
const key = files.get(file);
|
|
347
|
+
if (key === undefined)
|
|
348
|
+
return null;
|
|
349
|
+
const bytes = await md.binaryFile.part(key, part);
|
|
350
|
+
if (bytes === null)
|
|
351
|
+
files.delete(file);
|
|
352
|
+
return bytes;
|
|
353
|
+
},
|
|
249
354
|
},
|
|
250
|
-
reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
|
|
251
|
-
|
|
355
|
+
reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
|
|
356
|
+
!runtime.locked(room) &&
|
|
357
|
+
(await md.reached(room, roomVersion, path)),
|
|
252
358
|
log: () => (reach === null ? md.log() : ''),
|
|
359
|
+
cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
|
|
253
360
|
roomDraft: {
|
|
254
|
-
list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
361
|
+
list: () => md.roomDraft.list().then((drafts) => unlocked(draftsWithin(reach, drafts))),
|
|
362
|
+
async read(room, path) {
|
|
363
|
+
if (!covers(reach, room, path))
|
|
364
|
+
return null;
|
|
365
|
+
if (runtime.locked(room))
|
|
366
|
+
throw lockedError(room);
|
|
367
|
+
return shownDraft(reach, await md.roomDraft.read(room, path));
|
|
368
|
+
},
|
|
369
|
+
write(room, path, revision, parts, next) {
|
|
370
|
+
try {
|
|
371
|
+
const move = readParts(parts).move;
|
|
372
|
+
if (!covers(reach, room, path) || !moves(reach, room, move))
|
|
373
|
+
throw unreached(room);
|
|
374
|
+
if (runtime.locked(room))
|
|
375
|
+
throw lockedError(room);
|
|
376
|
+
if (intoLocked([move]))
|
|
377
|
+
throw lockedError(move.room);
|
|
259
378
|
}
|
|
260
|
-
|
|
379
|
+
catch (error) {
|
|
380
|
+
return Promise.reject(error);
|
|
381
|
+
}
|
|
382
|
+
return md.roomDraft
|
|
383
|
+
.write(room, path, revision, parts, next)
|
|
384
|
+
.then((written) => writeWithin(reach, written));
|
|
261
385
|
},
|
|
262
386
|
async discard(room, path, revision) {
|
|
263
387
|
if (!covers(reach, room, path))
|
|
264
388
|
return staleWrite(null);
|
|
389
|
+
if (runtime.locked(room))
|
|
390
|
+
throw lockedError(room);
|
|
265
391
|
return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
|
|
266
392
|
},
|
|
267
393
|
},
|
|
@@ -269,7 +395,12 @@ export function narrowed(runtime, given) {
|
|
|
269
395
|
list: () => conversation().list(),
|
|
270
396
|
read: (id, options) => conversation().read(id, options),
|
|
271
397
|
create: (input) => conversation().create(input),
|
|
272
|
-
send: (id) => conversation().send(id),
|
|
398
|
+
send: (id, operation, draft) => conversation().send(id, operation, draft),
|
|
399
|
+
attach: (room, file) => !wholly(reach, room)
|
|
400
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
401
|
+
: runtime.locked(room)
|
|
402
|
+
? Promise.resolve(lockedRoom(room))
|
|
403
|
+
: conversation().attach(room, file),
|
|
273
404
|
answer: (id, answer) => conversation().answer(id, answer),
|
|
274
405
|
interrupt: (id) => conversation().interrupt(id),
|
|
275
406
|
kill: (id) => conversation().kill(id),
|
|
@@ -278,6 +409,7 @@ export function narrowed(runtime, given) {
|
|
|
278
409
|
},
|
|
279
410
|
chatDraft: {
|
|
280
411
|
write: (id, draft, revision) => chatDraft().write(id, draft, revision),
|
|
412
|
+
prepend: (id, draft) => chatDraft().prepend(id, draft),
|
|
281
413
|
discard: (id) => chatDraft().discard(id),
|
|
282
414
|
},
|
|
283
415
|
observe: observing(within),
|
|
@@ -290,5 +422,10 @@ export function narrowed(runtime, given) {
|
|
|
290
422
|
for (const restart of [...open])
|
|
291
423
|
restart();
|
|
292
424
|
},
|
|
425
|
+
facts(next) {
|
|
426
|
+
port = next;
|
|
427
|
+
for (const restart of [...open])
|
|
428
|
+
restart();
|
|
429
|
+
},
|
|
293
430
|
};
|
|
294
431
|
}
|