@agentshouse/mdruntime 0.1.0-cd50a4607cb7d → 0.1.0-cd9e28a590f84
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 +19 -16
- package/dist/adapter.d.ts +146 -70
- 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 +38 -4
- 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 +26 -10
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +180 -99
- 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 -16
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -88
- 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 +22 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +97 -11
- package/dist/collection.d.ts +10 -21
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +39 -291
- 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 +37 -12
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +3425 -1118
- package/dist/conversation.d.ts +31 -14
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +521 -202
- 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 +4 -1
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +19 -23
- 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 +10 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +118 -19
- package/dist/identity.d.ts +0 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -3
- package/dist/index.d.ts +15 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/live.d.ts +22 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +123 -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 +16 -6
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +207 -96
- 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 +9 -3
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +8 -11
- 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 +15 -0
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +93 -3
- 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 +45 -7
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +39 -0
- package/dist/overlay.d.ts +3 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +95 -156
- 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 +43 -2
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +67 -7
- package/dist/reach.d.ts +16 -4
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +218 -74
- package/dist/react.d.ts +6 -3
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -17
- 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 +3 -2
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +34 -7
- package/dist/refresh.d.ts +17 -14
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +155 -52
- package/dist/replica.d.ts +55 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +300 -182
- package/dist/room-draft.d.ts +36 -5
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +161 -74
- package/dist/rows.d.ts +39 -29
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +178 -94
- package/dist/save.d.ts +53 -14
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +529 -185
- package/dist/search.d.ts +15 -77
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -186
- 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 +7 -3
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +119 -66
- package/dist/status.d.ts +4 -3
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -1
- package/dist/store.d.ts +104 -94
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +337 -637
- 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 +5 -3
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +51 -21
- package/dist/validation.d.ts +29 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +101 -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 +165 -32
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +56 -31
- package/package.json +18 -19
- package/AGENTS.md +0 -296
- package/dist/chat/acts.d.ts +0 -33
- 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 -26
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -62
- package/dist/chat/markdown.d.ts +0 -20
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -188
- 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 -620
- 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 -25
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -639
package/dist/query.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
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';
|
|
5
|
+
export function bodied(shape) {
|
|
6
|
+
return shape.sections !== null || shape.preamble || shape.markdown;
|
|
7
|
+
}
|
|
4
8
|
export class QueryError extends Error {
|
|
5
9
|
code;
|
|
6
10
|
retryable = false;
|
|
@@ -11,9 +15,28 @@ export class QueryError extends Error {
|
|
|
11
15
|
}
|
|
12
16
|
const RANGE = ['$gt', '$gte', '$lt', '$lte'];
|
|
13
17
|
const SINGLE = ['$eq', '$ne', '$in', '$nin', '$all', '$size', '$exists'];
|
|
14
|
-
const FILTER = [
|
|
18
|
+
const FILTER = [
|
|
19
|
+
'rooms',
|
|
20
|
+
'types',
|
|
21
|
+
'where',
|
|
22
|
+
'pathPrefix',
|
|
23
|
+
'folder',
|
|
24
|
+
'paths',
|
|
25
|
+
'hop',
|
|
26
|
+
'backlinks',
|
|
27
|
+
'text',
|
|
28
|
+
];
|
|
15
29
|
const RELATED = ['types', 'where', 'pathPrefix', 'field'];
|
|
16
|
-
const PARTS = [
|
|
30
|
+
const PARTS = [
|
|
31
|
+
'fields',
|
|
32
|
+
'sections',
|
|
33
|
+
'preamble',
|
|
34
|
+
'markdown',
|
|
35
|
+
'backlinks',
|
|
36
|
+
'change',
|
|
37
|
+
'fileId',
|
|
38
|
+
'revision',
|
|
39
|
+
];
|
|
17
40
|
const ORDER = ['by', 'direction', 'nulls', 'stringSort', 'locale', 'localeOptions'];
|
|
18
41
|
const CALENDAR_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
19
42
|
const STRAY_ESCAPE = /~(?![01])/u;
|
|
@@ -60,6 +83,18 @@ function names(input, at) {
|
|
|
60
83
|
invalid(at, 'expects a list of names');
|
|
61
84
|
return [...new Set(listed)].sort();
|
|
62
85
|
}
|
|
86
|
+
function pathsOf(input) {
|
|
87
|
+
const listed = list(input, 'paths');
|
|
88
|
+
if (listed.some((item) => typeof item !== 'string' || item === '' || normalize(item) !== item)) {
|
|
89
|
+
invalid('paths', 'expects a list of Paths');
|
|
90
|
+
}
|
|
91
|
+
return [...new Set(listed)].sort();
|
|
92
|
+
}
|
|
93
|
+
function phrase(input) {
|
|
94
|
+
if (typeof input !== 'string' || input === '')
|
|
95
|
+
invalid('text', 'expects a phrase');
|
|
96
|
+
return input;
|
|
97
|
+
}
|
|
63
98
|
function directory(input, at) {
|
|
64
99
|
if (typeof input !== 'string' || normalize(input) !== input) {
|
|
65
100
|
invalid(at, 'expects a normalized directory');
|
|
@@ -279,15 +314,16 @@ function backlinksOf(facts, rooms, input) {
|
|
|
279
314
|
return { types, where, pathPrefix, field };
|
|
280
315
|
}
|
|
281
316
|
function keyPlan(typed, input, at, path) {
|
|
282
|
-
if (input === 'room' || input === 'type' || (path && input === 'path'))
|
|
317
|
+
if (input === 'room' || input === 'type' || input === 'folder' || (path && input === 'path')) {
|
|
283
318
|
return { of: input };
|
|
319
|
+
}
|
|
284
320
|
if (plain(input) && Object.hasOwn(input, 'field') && Object.keys(input).length === 1) {
|
|
285
321
|
if (specs(typed, input.field, place(at, 'field')).some(several)) {
|
|
286
322
|
invalid(place(at, 'field'), 'a path that can hold several values');
|
|
287
323
|
}
|
|
288
324
|
return { of: 'field', field: input.field };
|
|
289
325
|
}
|
|
290
|
-
return invalid(at, path ? 'expects room, path, type or a field' : 'expects room, type or a field');
|
|
326
|
+
return invalid(at, path ? 'expects room, path, type, folder or a field' : 'expects room, type, folder or a field');
|
|
291
327
|
}
|
|
292
328
|
function direction(input, at) {
|
|
293
329
|
if (input === undefined)
|
|
@@ -349,7 +385,7 @@ function parts(typed, input, at, fields) {
|
|
|
349
385
|
});
|
|
350
386
|
return named;
|
|
351
387
|
}
|
|
352
|
-
function flag(input, at) {
|
|
388
|
+
export function flag(input, at) {
|
|
353
389
|
if (input === undefined)
|
|
354
390
|
return false;
|
|
355
391
|
if (input !== true)
|
|
@@ -377,6 +413,8 @@ function documentShape(typed, input) {
|
|
|
377
413
|
markdown: true,
|
|
378
414
|
backlinks: true,
|
|
379
415
|
change: true,
|
|
416
|
+
fileId: true,
|
|
417
|
+
revision: true,
|
|
380
418
|
orderBy,
|
|
381
419
|
};
|
|
382
420
|
}
|
|
@@ -391,6 +429,8 @@ function documentShape(typed, input) {
|
|
|
391
429
|
markdown: flag(select.markdown, 'select.markdown'),
|
|
392
430
|
backlinks: flag(select.backlinks, 'select.backlinks'),
|
|
393
431
|
change: flag(select.change, 'select.change'),
|
|
432
|
+
fileId: flag(select.fileId, 'select.fileId'),
|
|
433
|
+
revision: flag(select.revision, 'select.revision'),
|
|
394
434
|
orderBy,
|
|
395
435
|
};
|
|
396
436
|
}
|
|
@@ -421,20 +461,37 @@ export function planOf(input, facts, reach = null) {
|
|
|
421
461
|
invalid('select', 'a grouped query selects nothing');
|
|
422
462
|
if (!grouped && input.select === undefined)
|
|
423
463
|
invalid('select', 'a Document query must select');
|
|
424
|
-
known(input, [...FILTER, 'orderBy', 'limit', grouped ? 'groupBy' : 'select'], '');
|
|
464
|
+
known(input, [...FILTER, 'orderBy', 'limit', 'after', 'total', grouped ? 'groupBy' : 'select'], '');
|
|
425
465
|
const limit = limitOf(input.limit);
|
|
426
466
|
const rooms = input.rooms === undefined ? null : names(input.rooms, 'rooms');
|
|
427
467
|
const { typed, ...root } = scope(facts, rooms, input, '');
|
|
468
|
+
const shape = grouped ? groupShape(typed, input) : documentShape(typed, input);
|
|
428
469
|
return {
|
|
470
|
+
key: queryKey(input),
|
|
429
471
|
rooms,
|
|
430
472
|
reach,
|
|
473
|
+
locked: [],
|
|
431
474
|
root,
|
|
475
|
+
folder: input.folder === undefined ? null : directory(input.folder, 'folder'),
|
|
476
|
+
paths: input.paths === undefined ? null : pathsOf(input.paths),
|
|
432
477
|
hop: input.hop === undefined ? null : hopOf(facts, rooms, typed, input.hop),
|
|
433
478
|
backlinks: input.backlinks === undefined ? null : backlinksOf(facts, rooms, input.backlinks),
|
|
434
|
-
|
|
479
|
+
text: input.text === undefined ? null : phrase(input.text),
|
|
480
|
+
shape,
|
|
435
481
|
limit,
|
|
482
|
+
after: continuationOf(input.after, shape.orderBy.length + 1),
|
|
483
|
+
total: flag(input.total, 'total'),
|
|
436
484
|
};
|
|
437
485
|
}
|
|
486
|
+
function continuationOf(input, arity) {
|
|
487
|
+
if (input === undefined)
|
|
488
|
+
return null;
|
|
489
|
+
const values = typeof input === 'string' ? decodedCursor(input) : null;
|
|
490
|
+
if (values === null || (values.length !== 0 && values.length !== arity)) {
|
|
491
|
+
invalid('after', 'expects the next an earlier result of this query returned');
|
|
492
|
+
}
|
|
493
|
+
return { text: input, values: values.length === 0 ? null : values };
|
|
494
|
+
}
|
|
438
495
|
export function limitOf(input) {
|
|
439
496
|
if (input === undefined)
|
|
440
497
|
return null;
|
|
@@ -449,6 +506,9 @@ export function filterOf(input, facts, reach = null) {
|
|
|
449
506
|
known(input, FILTER, '');
|
|
450
507
|
return planOf({ ...input, select: {} }, facts, reach);
|
|
451
508
|
}
|
|
509
|
+
export function queryKey(query) {
|
|
510
|
+
return canonical(query);
|
|
511
|
+
}
|
|
452
512
|
function canonical(value) {
|
|
453
513
|
if (Array.isArray(value))
|
|
454
514
|
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 { AppRoom, MdRuntime, ReadinessPort, RuntimeTopic } from './connection.js';
|
|
3
2
|
import type { Plan, PlanReach, QueryResult } from './query.js';
|
|
3
|
+
import type { Readiness } from './readiness.js';
|
|
4
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 open: 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,19 @@ 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
34
|
search(input: unknown, reach: PortReach | null): Promise<SearchResult>;
|
|
28
|
-
|
|
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;
|
|
40
|
+
room(locator: string): AppRoom | undefined;
|
|
29
41
|
};
|
|
30
42
|
export declare function holds(reach: PortReach | null, room: string): boolean;
|
|
31
43
|
export declare function governs(reach: PortReach | null, room: {
|
|
@@ -38,5 +50,5 @@ export declare function governs(reach: PortReach | null, room: {
|
|
|
38
50
|
readonly selection: boolean;
|
|
39
51
|
};
|
|
40
52
|
export declare function planReach(reach: PortReach | null): PlanReach | null;
|
|
41
|
-
export declare function narrowed(runtime: Reachable, given: PortReach | null): NarrowedView;
|
|
53
|
+
export declare function narrowed(runtime: Reachable, given: PortReach | null, told: ReadinessPort): NarrowedView;
|
|
42
54
|
//# 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,10 +1,9 @@
|
|
|
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';
|
|
10
9
|
const UNHELD_TYPES = { collection: modelTypes(NO_MODEL), typedSelection: null };
|
|
@@ -14,18 +13,26 @@ function unconversed(name) {
|
|
|
14
13
|
const NO_CONVERSATION = {
|
|
15
14
|
list: () => Promise.resolve([]),
|
|
16
15
|
read: (conversation) => Promise.resolve(unheldView(conversation)),
|
|
17
|
-
create: unconversed('
|
|
18
|
-
send: unconversed('
|
|
19
|
-
answer: unconversed('
|
|
20
|
-
interrupt: unconversed('
|
|
21
|
-
kill: unconversed('
|
|
22
|
-
|
|
23
|
-
delete: unconversed('conversation.delete'),
|
|
16
|
+
create: unconversed('conversations/create'),
|
|
17
|
+
send: unconversed('conversations/send'),
|
|
18
|
+
answer: unconversed('conversations/interaction/answer'),
|
|
19
|
+
interrupt: unconversed('conversations/interrupt'),
|
|
20
|
+
kill: unconversed('conversations/kill'),
|
|
21
|
+
delete: unconversed('conversations/delete'),
|
|
24
22
|
};
|
|
25
23
|
const NO_CHAT_DRAFT = {
|
|
26
24
|
write: () => Promise.resolve(),
|
|
25
|
+
prepend: () => Promise.resolve(),
|
|
27
26
|
discard: () => Promise.resolve(),
|
|
28
27
|
};
|
|
28
|
+
function areasOf(reach) {
|
|
29
|
+
return reach.areas ?? [];
|
|
30
|
+
}
|
|
31
|
+
function fenced(reach, room, path) {
|
|
32
|
+
return areasOf(reach).some((area) => area.room === room &&
|
|
33
|
+
beneath(area.path, path) &&
|
|
34
|
+
!area.open.some((open) => beneath(open, path)));
|
|
35
|
+
}
|
|
29
36
|
export function holds(reach, room) {
|
|
30
37
|
return (reach === null ||
|
|
31
38
|
reach.rooms.includes(room) ||
|
|
@@ -46,26 +53,13 @@ export function governs(reach, room) {
|
|
|
46
53
|
}
|
|
47
54
|
function covers(reach, room, path) {
|
|
48
55
|
return (reach === null ||
|
|
49
|
-
reach
|
|
50
|
-
|
|
56
|
+
(!fenced(reach, room, path) &&
|
|
57
|
+
(reach.rooms.includes(room) ||
|
|
58
|
+
reach.documents.some((document) => document.room === room && document.path === path))));
|
|
51
59
|
}
|
|
52
60
|
function conversing(reach) {
|
|
53
61
|
return reach === null || reach.conversations;
|
|
54
62
|
}
|
|
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
63
|
export function planReach(reach) {
|
|
70
64
|
return reach === null
|
|
71
65
|
? null
|
|
@@ -74,6 +68,9 @@ export function planReach(reach) {
|
|
|
74
68
|
documents: [
|
|
75
69
|
...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
|
|
76
70
|
].sort(),
|
|
71
|
+
areas: areasOf(reach)
|
|
72
|
+
.map(({ room, path, open }) => ({ room, path, open: [...new Set(open)].sort() }))
|
|
73
|
+
.sort((left, right) => documentKey(left.room, left.path) < documentKey(right.room, right.path) ? -1 : 1),
|
|
77
74
|
};
|
|
78
75
|
}
|
|
79
76
|
function roomsWithin(reach, rooms) {
|
|
@@ -89,7 +86,7 @@ function typesWithin(reach, room, types) {
|
|
|
89
86
|
};
|
|
90
87
|
}
|
|
91
88
|
function moves(reach, room, move) {
|
|
92
|
-
return move === undefined || covers(reach, room, moveTarget(move));
|
|
89
|
+
return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
|
|
93
90
|
}
|
|
94
91
|
function draftWithin(reach, draft) {
|
|
95
92
|
return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
|
|
@@ -122,76 +119,128 @@ function savedWithin(reach, room, result) {
|
|
|
122
119
|
function statusWithin(reach, status) {
|
|
123
120
|
return {
|
|
124
121
|
...status,
|
|
125
|
-
attentionRequired: status.attentionRequired.filter((entry) =>
|
|
122
|
+
attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
|
|
123
|
+
unsent: status.unsent.filter((change) => covers(reach, change.room, change.path)),
|
|
126
124
|
};
|
|
127
125
|
}
|
|
128
126
|
function queueWithin(reach, room, entries) {
|
|
129
|
-
return entries
|
|
130
|
-
(
|
|
127
|
+
return entries
|
|
128
|
+
.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
|
|
129
|
+
(change.kind !== 'move' || covers(reach, room, change.to))))
|
|
130
|
+
.map((entry) => {
|
|
131
|
+
const { between, ...batch } = entry.batch;
|
|
132
|
+
if (between === undefined)
|
|
133
|
+
return entry;
|
|
134
|
+
return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
|
|
135
|
+
? entry
|
|
136
|
+
: { ...entry, batch };
|
|
137
|
+
});
|
|
131
138
|
}
|
|
132
139
|
function unreached(room) {
|
|
133
|
-
return runtimeError('room
|
|
140
|
+
return runtimeError('unknown-room', `Unknown Room ${room}`);
|
|
141
|
+
}
|
|
142
|
+
function lockedError(room) {
|
|
143
|
+
return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
|
|
144
|
+
}
|
|
145
|
+
function deviceUnreached() {
|
|
146
|
+
return runtimeError('device-unreached', 'Only the panel cleans up this device');
|
|
147
|
+
}
|
|
148
|
+
const ATTACH_REQUIRED = 'attach-required';
|
|
149
|
+
function attachRequired() {
|
|
150
|
+
return runtimeError(ATTACH_REQUIRED, 'App code takes a file in with binaryFile.attach');
|
|
151
|
+
}
|
|
152
|
+
function carriesFile(parts) {
|
|
153
|
+
return parts !== null && typeof parts === 'object' && Object.hasOwn(parts, 'file');
|
|
134
154
|
}
|
|
135
|
-
export function narrowed(runtime, given) {
|
|
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.message);
|
|
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,57 +260,147 @@ 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
|
+
async function hand(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
|
-
rooms: () => roomsWithin(reach,
|
|
219
|
-
query: ((input) =>
|
|
278
|
+
rooms: () => md.rooms().then((rooms) => roomsWithin(reach, rooms)),
|
|
279
|
+
query: ((input) => {
|
|
280
|
+
const plan = runtime.plan(input, reach);
|
|
281
|
+
return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
|
|
282
|
+
}),
|
|
220
283
|
search: (input) => runtime.search(input, reach),
|
|
221
284
|
types(room) {
|
|
285
|
+
if (holds(reach, room) && runtime.locked(room))
|
|
286
|
+
throw lockedError(room);
|
|
222
287
|
if (wholly(reach, room))
|
|
223
288
|
return md.types(room);
|
|
224
289
|
if (!holds(reach, room))
|
|
225
290
|
return structuredClone(UNHELD_TYPES);
|
|
226
|
-
|
|
227
|
-
return typesWithin(reach, listed, md.types(room));
|
|
291
|
+
return typesWithin(reach, runtime.room(room), md.types(room));
|
|
228
292
|
},
|
|
229
293
|
async save(room, roomDrafts, writtenBy) {
|
|
230
294
|
if (!holds(reach, room))
|
|
231
295
|
throw unreached(room);
|
|
232
|
-
|
|
233
|
-
|
|
296
|
+
if (runtime.locked(room))
|
|
297
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
298
|
+
const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
|
|
299
|
+
const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
|
|
234
300
|
if (outside !== undefined) {
|
|
235
301
|
return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
|
|
236
302
|
}
|
|
303
|
+
if (intoLocked(held))
|
|
304
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
237
305
|
return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
|
|
238
306
|
},
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
307
|
+
async saveParts(room, parts, writtenBy) {
|
|
308
|
+
if (!holds(reach, room))
|
|
309
|
+
throw unreached(room);
|
|
310
|
+
const filed = reach === null ? undefined : parts.find(({ parts: one }) => carriesFile(one));
|
|
311
|
+
if (filed !== undefined) {
|
|
312
|
+
return { outcome: 'refused', code: ATTACH_REQUIRED, retryable: false, file: filed.path };
|
|
313
|
+
}
|
|
314
|
+
if (runtime.locked(room))
|
|
315
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
316
|
+
const held = parts.map(({ path, parts: one }) => readParts(one, path).move);
|
|
317
|
+
if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
|
|
318
|
+
throw unreached(room);
|
|
319
|
+
}
|
|
320
|
+
if (intoLocked(held))
|
|
321
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
322
|
+
return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
|
|
323
|
+
},
|
|
324
|
+
resolve(room, path, destination) {
|
|
325
|
+
const at = runtime.located(room, path, destination);
|
|
326
|
+
return at !== null && !covers(reach, at.room, at.path)
|
|
327
|
+
? Promise.resolve(UNREADABLE)
|
|
328
|
+
: md.resolve(room, path, destination);
|
|
329
|
+
},
|
|
330
|
+
history: (room, path, query) => !covers(reach, room, path)
|
|
331
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
332
|
+
: runtime.locked(room)
|
|
333
|
+
? Promise.resolve(lockedRoom(room))
|
|
334
|
+
: md.history(room, path, query),
|
|
242
335
|
binaryFile: {
|
|
243
|
-
read: (room, path, revision) => covers(reach, room, path)
|
|
244
|
-
?
|
|
245
|
-
:
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
336
|
+
read: (room, path, revision) => !covers(reach, room, path)
|
|
337
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
338
|
+
: runtime.locked(room)
|
|
339
|
+
? Promise.resolve(lockedRoom(room))
|
|
340
|
+
: hand(md.binaryFile.read(room, path, revision)),
|
|
341
|
+
link: (room, path, revision) => !covers(reach, room, path)
|
|
342
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
343
|
+
: runtime.locked(room)
|
|
344
|
+
? Promise.resolve(lockedRoom(room))
|
|
345
|
+
: md.binaryFile.link(room, path, revision),
|
|
346
|
+
show: (room, path, revision) => !covers(reach, room, path)
|
|
347
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
348
|
+
: runtime.locked(room)
|
|
349
|
+
? Promise.resolve(lockedRoom(room))
|
|
350
|
+
: hand(md.binaryFile.show(room, path, revision)),
|
|
351
|
+
attach: (room, file) => !wholly(reach, room)
|
|
352
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
353
|
+
: runtime.locked(room)
|
|
354
|
+
? Promise.resolve(lockedRoom(room))
|
|
355
|
+
: md.binaryFile.attach(room, file),
|
|
356
|
+
async part(file, part) {
|
|
357
|
+
const key = files.get(file);
|
|
358
|
+
if (key === undefined)
|
|
359
|
+
return null;
|
|
360
|
+
const bytes = await md.binaryFile.part(key, part);
|
|
361
|
+
if (bytes === null)
|
|
362
|
+
files.delete(file);
|
|
363
|
+
return bytes;
|
|
364
|
+
},
|
|
249
365
|
},
|
|
250
|
-
reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
|
|
251
|
-
|
|
366
|
+
reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
|
|
367
|
+
!runtime.locked(room) &&
|
|
368
|
+
(await md.reached(room, roomVersion, path)),
|
|
252
369
|
log: () => (reach === null ? md.log() : ''),
|
|
370
|
+
cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
|
|
253
371
|
roomDraft: {
|
|
254
|
-
list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
372
|
+
list: () => md.roomDraft.list().then((drafts) => unlocked(draftsWithin(reach, drafts))),
|
|
373
|
+
async read(room, path) {
|
|
374
|
+
if (!covers(reach, room, path))
|
|
375
|
+
return null;
|
|
376
|
+
if (runtime.locked(room))
|
|
377
|
+
throw lockedError(room);
|
|
378
|
+
return shownDraft(reach, await md.roomDraft.read(room, path));
|
|
379
|
+
},
|
|
380
|
+
write(room, path, revision, parts, next) {
|
|
381
|
+
try {
|
|
382
|
+
if (reach !== null && carriesFile(parts))
|
|
383
|
+
throw attachRequired();
|
|
384
|
+
const move = readParts(parts, path).move;
|
|
385
|
+
if (!covers(reach, room, path) || !moves(reach, room, move))
|
|
386
|
+
throw unreached(room);
|
|
387
|
+
if (runtime.locked(room))
|
|
388
|
+
throw lockedError(room);
|
|
389
|
+
if (intoLocked([move]))
|
|
390
|
+
throw lockedError(move.room);
|
|
259
391
|
}
|
|
260
|
-
|
|
392
|
+
catch (error) {
|
|
393
|
+
return Promise.reject(error);
|
|
394
|
+
}
|
|
395
|
+
return md.roomDraft
|
|
396
|
+
.write(room, path, revision, parts, next)
|
|
397
|
+
.then((written) => writeWithin(reach, written));
|
|
261
398
|
},
|
|
262
399
|
async discard(room, path, revision) {
|
|
263
400
|
if (!covers(reach, room, path))
|
|
264
401
|
return staleWrite(null);
|
|
402
|
+
if (runtime.locked(room))
|
|
403
|
+
throw lockedError(room);
|
|
265
404
|
return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
|
|
266
405
|
},
|
|
267
406
|
},
|
|
@@ -273,11 +412,11 @@ export function narrowed(runtime, given) {
|
|
|
273
412
|
answer: (id, answer) => conversation().answer(id, answer),
|
|
274
413
|
interrupt: (id) => conversation().interrupt(id),
|
|
275
414
|
kill: (id) => conversation().kill(id),
|
|
276
|
-
cancel: (id, turn) => conversation().cancel(id, turn),
|
|
277
415
|
delete: (id) => conversation().delete(id),
|
|
278
416
|
},
|
|
279
417
|
chatDraft: {
|
|
280
418
|
write: (id, draft, revision) => chatDraft().write(id, draft, revision),
|
|
419
|
+
prepend: (id, draft) => chatDraft().prepend(id, draft),
|
|
281
420
|
discard: (id) => chatDraft().discard(id),
|
|
282
421
|
},
|
|
283
422
|
observe: observing(within),
|
|
@@ -290,5 +429,10 @@ export function narrowed(runtime, given) {
|
|
|
290
429
|
for (const restart of [...open])
|
|
291
430
|
restart();
|
|
292
431
|
},
|
|
432
|
+
facts(next) {
|
|
433
|
+
port = next;
|
|
434
|
+
for (const restart of [...open])
|
|
435
|
+
restart();
|
|
436
|
+
},
|
|
293
437
|
};
|
|
294
438
|
}
|