@agentshouse/mdruntime 0.1.0-c7b0ab1aa40a3 → 0.1.0-c7bd7ca3faee4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/AGENTS.md +40 -19
  2. package/README.md +9 -9
  3. package/dist/adapter.d.ts +8 -0
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +15 -2
  7. package/dist/bootstrap.d.ts.map +1 -1
  8. package/dist/bootstrap.js +1 -0
  9. package/dist/client.d.ts +3 -1
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +35 -0
  12. package/dist/connection.d.ts +4 -2
  13. package/dist/connection.d.ts.map +1 -1
  14. package/dist/connection.js +54 -15
  15. package/dist/host.d.ts +1 -0
  16. package/dist/host.d.ts.map +1 -1
  17. package/dist/host.js +1 -0
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/memory.d.ts +2 -1
  21. package/dist/memory.d.ts.map +1 -1
  22. package/dist/memory.js +8 -0
  23. package/dist/model.d.ts +7 -0
  24. package/dist/model.d.ts.map +1 -1
  25. package/dist/model.js +2 -0
  26. package/dist/paths.d.ts +0 -1
  27. package/dist/paths.d.ts.map +1 -1
  28. package/dist/paths.js +0 -16
  29. package/dist/query.d.ts +1 -1
  30. package/dist/query.d.ts.map +1 -1
  31. package/dist/query.js +49 -19
  32. package/dist/react.d.ts +22 -14
  33. package/dist/react.d.ts.map +1 -1
  34. package/dist/react.js +7 -6
  35. package/dist/read-side.d.ts.map +1 -1
  36. package/dist/read-side.js +102 -46
  37. package/dist/replica.d.ts +3 -3
  38. package/dist/replica.d.ts.map +1 -1
  39. package/dist/replica.js +4 -3
  40. package/dist/rows.d.ts +2 -1
  41. package/dist/rows.d.ts.map +1 -1
  42. package/dist/rows.js +77 -37
  43. package/dist/save.d.ts +1 -0
  44. package/dist/save.d.ts.map +1 -1
  45. package/dist/save.js +90 -43
  46. package/dist/store.d.ts +5 -1
  47. package/dist/store.d.ts.map +1 -1
  48. package/dist/store.js +13 -2
  49. package/dist/wire.d.ts +1 -0
  50. package/dist/wire.d.ts.map +1 -1
  51. package/dist/wire.js +1 -0
  52. package/package.json +2 -2
package/dist/react.d.ts CHANGED
@@ -1,31 +1,39 @@
1
1
  import type { MdRuntimeClient } from './client.js';
2
2
  import type { AppRoom, ConnectionRefusal, SaveResult } from './connection.js';
3
- import type { ServiceMode } from './adapter.js';
3
+ import type { Member, ServiceMode } from './adapter.js';
4
4
  import type { ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
5
5
  import type { QueueEntry } from './outcome.js';
6
6
  import type { DocumentQuery, DocumentResult, GroupQuery, GroupResult } from './query.js';
7
7
  import type { RoomDraft, RoomDraftParts } from './room-draft.js';
8
8
  import type { SyncStatus } from './status.js';
9
9
  type Client = MdRuntimeClient | null;
10
- export declare function useObserve(client: Client, topic: 'deployment-facts'): unknown;
11
- export declare function useObserve(client: Client, topic: 'rooms'): readonly AppRoom[] | undefined;
12
- export declare function useObserve(client: Client, topic: 'connection-refusal'): ConnectionRefusal | null | undefined;
13
- export declare function useObserve(client: Client, topic: 'storage-loss'): string | null | undefined;
14
- export declare function useObserve(client: Client, topic: 'sync-status'): SyncStatus | undefined;
15
- export declare function useObserve(client: Client, topic: 'service-mode'): ServiceMode | undefined;
16
- export declare function useObserve(client: Client, topic: 'query', query: DocumentQuery): DocumentResult | undefined;
17
- export declare function useObserve(client: Client, topic: 'query', query: GroupQuery): GroupResult | undefined;
18
- export declare function useObserve(client: Client, topic: 'queue', locator: string): readonly QueueEntry[] | undefined;
19
- export declare function useObserve(client: Client, topic: 'room-drafts'): readonly RoomDraft[] | undefined;
20
- export declare function useObserve(client: Client, topic: 'presentation'): unknown;
21
- export declare function useObserve(client: Client, topic: 'conversation', conversation: string, options: ConversationOptions): ConversationView | undefined;
22
- export declare function useObserve(client: Client, topic: 'conversations'): readonly ConversationEntry[] | undefined;
10
+ export type Observed<T> = {
11
+ readonly state: 'loading';
12
+ } | {
13
+ readonly state: 'ready';
14
+ readonly value: T;
15
+ };
16
+ export declare function useObserve(client: Client, topic: 'deployment-facts'): Observed<unknown>;
17
+ export declare function useObserve(client: Client, topic: 'rooms'): Observed<readonly AppRoom[]>;
18
+ export declare function useObserve(client: Client, topic: 'connection-refusal'): Observed<ConnectionRefusal | null>;
19
+ export declare function useObserve(client: Client, topic: 'storage-loss'): Observed<string | null>;
20
+ export declare function useObserve(client: Client, topic: 'sync-status'): Observed<SyncStatus>;
21
+ export declare function useObserve(client: Client, topic: 'service-mode'): Observed<ServiceMode>;
22
+ export declare function useObserve(client: Client, topic: 'member'): Observed<Member | null>;
23
+ export declare function useObserve(client: Client, topic: 'query', query: DocumentQuery): Observed<DocumentResult>;
24
+ export declare function useObserve(client: Client, topic: 'query', query: GroupQuery): Observed<GroupResult>;
25
+ export declare function useObserve(client: Client, topic: 'queue', locator: string): Observed<readonly QueueEntry[]>;
26
+ export declare function useObserve(client: Client, topic: 'room-drafts'): Observed<readonly RoomDraft[]>;
27
+ export declare function useObserve(client: Client, topic: 'presentation'): Observed<unknown>;
28
+ export declare function useObserve(client: Client, topic: 'conversation', conversation: string, options: ConversationOptions): Observed<ConversationView>;
29
+ export declare function useObserve(client: Client, topic: 'conversations'): Observed<readonly ConversationEntry[]>;
23
30
  export type Saving = {
24
31
  readonly busy: boolean;
25
32
  readonly outcome: SaveResult | null;
26
33
  readonly failure: Error | null;
27
34
  save(room: string, roomDrafts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
28
35
  };
36
+ export declare function saveRoomDrafts(client: MdRuntimeClient, room: string, roomDrafts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
29
37
  export declare function useSave(client: MdRuntimeClient): Saving;
30
38
  export {};
31
39
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAkB,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAElG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,KAAK,MAAM,GAAG,eAAe,GAAG,IAAI,CAAC;AAIrC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC;AAC/E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,OAAO,EAAE,GAAG,SAAS,CAAC;AAC3F,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,oBAAoB,GAC1B,iBAAiB,GAAG,IAAI,GAAG,SAAS,CAAC;AACxC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAC7F,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,CAAC;AACzF,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,WAAW,GAAG,SAAS,CAAC;AAC3F,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,aAAa,GACnB,cAAc,GAAG,SAAS,CAAC;AAC9B,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,UAAU,GAChB,WAAW,GAAG,SAAS,CAAC;AAC3B,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,GACd,SAAS,UAAU,EAAE,GAAG,SAAS,CAAC;AACrC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,SAAS,EAAE,GAAG,SAAS,CAAC;AACnG,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC;AAC3E,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,cAAc,EACrB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,mBAAmB,GAC3B,gBAAgB,GAAG,SAAS,CAAC;AAChC,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,eAAe,GACrB,SAAS,iBAAiB,EAAE,GAAG,SAAS,CAAC;AAkC5C,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1F,CAAC;AAuBF,wBAAgB,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAkBvD"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"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"}
package/dist/react.js CHANGED
@@ -1,10 +1,11 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
1
+ import { useCallback, useLayoutEffect, useRef, useState } from 'react';
2
+ const LOADING = { state: 'loading' };
2
3
  export function useObserve(client, topic, ...input) {
3
4
  const key = JSON.stringify([topic, ...input]);
4
5
  const [held, setHeld] = useState(null);
5
6
  const opened = useRef(input);
6
7
  opened.current = input;
7
- useEffect(() => {
8
+ useLayoutEffect(() => {
8
9
  if (client === null)
9
10
  return;
10
11
  let live = true;
@@ -18,7 +19,7 @@ export function useObserve(client, topic, ...input) {
18
19
  observation = open;
19
20
  const take = (value) => {
20
21
  if (live)
21
- setHeld({ client, key, value });
22
+ setHeld({ client, key, observed: { state: 'ready', value } });
22
23
  };
23
24
  take(open.current());
24
25
  open.subscribe(take);
@@ -28,10 +29,10 @@ export function useObserve(client, topic, ...input) {
28
29
  observation?.close();
29
30
  };
30
31
  }, [client, key]);
31
- return held !== null && held.client === client && held.key === key ? held.value : undefined;
32
+ return held !== null && held.client === client && held.key === key ? held.observed : LOADING;
32
33
  }
33
34
  const IDLE = { busy: false, outcome: null, failure: null };
34
- async function written(client, room, roomDrafts) {
35
+ export async function saveRoomDrafts(client, room, roomDrafts) {
35
36
  const kept = [];
36
37
  for (const [path, parts] of roomDrafts) {
37
38
  const prior = await client.roomDraft.read(room, path);
@@ -48,7 +49,7 @@ export function useSave(client) {
48
49
  const save = useCallback(async (room, roomDrafts) => {
49
50
  setState({ busy: true, outcome: null, failure: null });
50
51
  try {
51
- const outcome = await written(client, room, roomDrafts);
52
+ const outcome = await saveRoomDrafts(client, room, roomDrafts);
52
53
  setState({ busy: false, outcome, failure: null });
53
54
  return outcome;
54
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC3F,OAAO,KAAK,EAOV,IAAI,EAIJ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAqDpD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,KAAK,CACH,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,KAAK,IAAI,GACpD,MAAM,IAAI,CAAC;IACd,SAAS,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AA8RF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,WAAW,GAChB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CA4BpD;AAED,wBAAgB,cAAc,IAAI,QAAQ,CA4HzC"}
1
+ {"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAU,KAAK,WAAW,EAAE,KAAK,WAAW,EAAe,MAAM,kBAAkB,CAAC;AAC3F,OAAO,KAAK,EAOV,IAAI,EAIJ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAuDpD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,KAAK,CACH,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,KAAK,IAAI,GACpD,MAAM,IAAI,CAAC;IACd,SAAS,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AA+UF,wBAAgB,UAAU,CACxB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,WAAW,GAChB;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,IAAI,CA4BpD;AAED,wBAAgB,cAAc,IAAI,QAAQ,CA4HzC"}
package/dist/read-side.js CHANGED
@@ -1,54 +1,58 @@
1
- import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, gt, gte, inArray, isNull, isUndefined, lt, lte, not, or, toArray, } from '@tanstack/db';
1
+ import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, inArray, or, toArray, } from '@tanstack/db';
2
+ import { ARRAY_INDEX, pointerSegments } from '@agentshouse/mdmodel';
2
3
  import { rowsOf } from './observation.js';
3
4
  import { documentKey } from './rows.js';
4
5
  function every(expressions) {
5
6
  const [first, second, ...rest] = expressions;
6
7
  return second === undefined ? first : and(first, second, ...rest);
7
8
  }
8
- function some(expressions) {
9
- const [first, second, ...rest] = expressions;
10
- return second === undefined ? first : or(first, second, ...rest);
9
+ function same(held, value) {
10
+ return Array.isArray(held) ? held.includes(value) : held === value;
11
11
  }
12
- function equal(field, value) {
13
- return or(eq(field, value), inArray(value, field));
12
+ function ordered(held, [operator, bound]) {
13
+ if (typeof held !== typeof bound || held === null || typeof held === 'object')
14
+ return false;
15
+ const left = held;
16
+ const right = bound;
17
+ if (operator === 'gt')
18
+ return left > right;
19
+ if (operator === 'gte')
20
+ return left >= right;
21
+ if (operator === 'lt')
22
+ return left < right;
23
+ return left <= right;
14
24
  }
15
- function tested(test, field, size, written) {
25
+ function satisfied(test, held) {
16
26
  if (test.op === 'eq')
17
- return test.value === null ? isNull(field) : equal(field, test.value);
18
- if (test.op === 'ne') {
19
- return test.value === null
20
- ? not(isNull(field))
21
- : or(isUndefined(field), isNull(field), not(equal(field, test.value)));
22
- }
23
- if (test.op === 'in' || test.op === 'nin') {
24
- const matches = test.values.length === 0
25
- ? inArray(field, [])
26
- : some(test.values.map((value) => (value === null ? isNull(field) : equal(field, value))));
27
- if (test.op === 'in')
28
- return matches;
29
- return some([
30
- isUndefined(field),
31
- ...(test.values.includes(null) ? [] : [isNull(field)]),
32
- not(matches),
33
- ]);
34
- }
35
- if (test.op === 'range') {
36
- const compare = { gt, gte, lt, lte };
37
- return every(test.bounds.map(([operator, bound]) => compare[operator](field, bound)));
38
- }
39
- if (test.op === 'all') {
40
- return every([not(isUndefined(size)), ...test.values.map((value) => inArray(value, field))]);
41
- }
42
- if (test.op === 'size')
43
- return eq(size, test.size);
44
- return test.exists ? not(isUndefined(written)) : isUndefined(written);
27
+ return same(held, test.value);
28
+ if (test.op === 'ne')
29
+ return !same(held, test.value);
30
+ if (test.op === 'in')
31
+ return test.values.some((value) => same(held, value));
32
+ if (test.op === 'nin')
33
+ return !test.values.some((value) => same(held, value));
34
+ if (test.op === 'range')
35
+ return test.bounds.every((bound) => ordered(held, bound));
36
+ if (test.op === 'all')
37
+ return Array.isArray(held) && test.values.every((value) => same(held, value));
38
+ return Array.isArray(held) && held.length === test.size;
39
+ }
40
+ function tested(test, reached) {
41
+ if (test.op === 'exists')
42
+ return test.exists === (reached !== undefined);
43
+ if (reached === undefined)
44
+ return test.op === 'ne' || test.op === 'nin';
45
+ return reached.some((held) => satisfied(test, held));
45
46
  }
46
47
  function conditioned(condition, row) {
47
48
  if ('every' in condition)
48
- return every(condition.every.map((item) => conditioned(item, row)));
49
+ return condition.every.every((item) => conditioned(item, row));
49
50
  if ('some' in condition)
50
- return some(condition.some.map((item) => conditioned(item, row)));
51
- return tested(condition.test, row.values[condition.field], row.sizes[condition.field], row.fields[condition.field]);
51
+ return condition.some.some((item) => conditioned(item, row));
52
+ return tested(condition.test, row.reached[condition.field]);
53
+ }
54
+ function narrowed(query, where, alias) {
55
+ return where === null ? query : query.fn.where((row) => conditioned(where, row[alias]));
52
56
  }
53
57
  function reached(reach, room, document) {
54
58
  return reach === null
@@ -62,7 +66,6 @@ function scoped(scope, row, rooms, reach) {
62
66
  ...reached(reach, row.room, row.key),
63
67
  ...(scope.types === null ? [] : [inArray(row.type, [...scope.types])]),
64
68
  ...(scope.pathPrefix === null ? [] : [inArray(scope.pathPrefix, row.directories)]),
65
- ...(scope.where === null ? [] : [conditioned(scope.where, row)]),
66
69
  ]);
67
70
  }
68
71
  function keyed(key, row) {
@@ -77,16 +80,17 @@ function live(query) {
77
80
  function related(q, rows, scope, field, kept, reach) {
78
81
  const matched = kept === 'source' ? 'target' : 'source';
79
82
  const from = q.from({ r: rows });
80
- return from
81
- .where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [eq(r.field, field)])]))
83
+ const joined = from
84
+ .where(({ r }) => every([eq(r.kind, 'reference'), ...(field === null ? [] : [inArray(field, r.forms)])]))
82
85
  .innerJoin({ m: rows }, ({ r, m }) => eq(r[matched], m.key))
83
- .where(({ m }) => scoped(scope, m, null, reach))
86
+ .where(({ m }) => scoped(scope, m, null, reach));
87
+ return narrowed(joined, scope.where, 'm')
84
88
  .groupBy(({ r }) => r[kept])
85
89
  .select(({ r }) => ({ key: r[kept] }));
86
90
  }
87
91
  function filtered(q, rows, plan) {
88
92
  const from = q.from({ d: rows });
89
- let query = from.where(({ d }) => scoped(plan.root, d, plan.rooms, plan.reach));
93
+ let query = narrowed(from.where(({ d }) => scoped(plan.root, d, plan.rooms, plan.reach)), plan.root.where, 'd');
90
94
  if (plan.hop !== null) {
91
95
  const hop = related(q, rows, plan.hop, plan.hop.field, 'source', plan.reach);
92
96
  query = query.innerJoin({ h: hop }, ({ d, h }) => eq(d.key, h.key));
@@ -117,8 +121,7 @@ function documents(q, rows, plan, shape) {
117
121
  room: d.room,
118
122
  path: d.path,
119
123
  type: d.type,
120
- ...(shape.fields === 'all' ? { fields: d.fields } : {}),
121
- ...(Array.isArray(shape.fields) ? named('field', shape.fields, d.fields) : {}),
124
+ ...(shape.fields === null ? {} : { fields: d.fields }),
122
125
  ...(shape.sections === 'all' ? { sections: b.sections } : {}),
123
126
  ...(Array.isArray(shape.sections) ? named('section', shape.sections, b.sections) : {}),
124
127
  ...(shape.preamble ? { preamble: b.preamble } : {}),
@@ -176,6 +179,55 @@ function part(row, prefix, names, whole) {
176
179
  return whole;
177
180
  return present(names.map((name, index) => [name, row[`${prefix}${index}`]]));
178
181
  }
182
+ function masked(pointers) {
183
+ const root = { whole: false, members: new Map() };
184
+ for (const pointer of pointers) {
185
+ let mask = root;
186
+ for (const token of pointerSegments(pointer)) {
187
+ const next = mask.members.get(token) ?? { whole: false, members: new Map() };
188
+ mask.members.set(token, next);
189
+ mask = next;
190
+ }
191
+ mask.whole = true;
192
+ }
193
+ return root;
194
+ }
195
+ function merged(left, right) {
196
+ if (left === undefined)
197
+ return right;
198
+ const members = new Map(left.members);
199
+ for (const [token, mask] of right.members)
200
+ members.set(token, merged(members.get(token), mask));
201
+ return { whole: left.whole || right.whole, members };
202
+ }
203
+ function cut(value, mask) {
204
+ if (mask.whole)
205
+ return value;
206
+ if (Array.isArray(value)) {
207
+ const each = {
208
+ whole: false,
209
+ members: new Map([...mask.members].filter(([token]) => !ARRAY_INDEX.test(token))),
210
+ };
211
+ const kept = [];
212
+ value.forEach((item, index) => {
213
+ const part = cut(item, merged(mask.members.get(String(index)), each));
214
+ if (part !== undefined)
215
+ kept[index] = part;
216
+ });
217
+ return kept.length === 0 ? undefined : kept;
218
+ }
219
+ if (typeof value !== 'object' || value === null)
220
+ return undefined;
221
+ const kept = Object.entries(value).flatMap(([key, held]) => {
222
+ const member = mask.members.get(key);
223
+ const part = member === undefined ? undefined : cut(held, member);
224
+ return part === undefined ? [] : [[key, part]];
225
+ });
226
+ return kept.length === 0 ? undefined : Object.fromEntries(kept);
227
+ }
228
+ function selected(fields, pointers) {
229
+ return (cut(fields, masked(pointers)) ?? {});
230
+ }
179
231
  function documentOf(row, shape) {
180
232
  if (row.type === null)
181
233
  return { room: row.room, path: row.path };
@@ -185,7 +237,11 @@ function documentOf(row, shape) {
185
237
  type: row.type,
186
238
  ...(shape.fields === null
187
239
  ? {}
188
- : { fields: part(row, 'field', shape.fields, row.fields) }),
240
+ : {
241
+ fields: shape.fields === 'all'
242
+ ? row.fields
243
+ : selected(row.fields, shape.fields),
244
+ }),
189
245
  ...(shape.sections === null
190
246
  ? {}
191
247
  : {
package/dist/replica.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type ChangeBatch } from './change.js';
2
2
  import { type Collection, type Composition } from './collection.js';
3
3
  import { type Layer } from './overlay.js';
4
- import type { RoomAttachment } from './adapter.js';
4
+ import type { HeadChange, RoomAttachment } from './adapter.js';
5
5
  import type { ReplicaRecord } from './store.js';
6
6
  import type { Refused } from './transfer.js';
7
7
  export type ConfirmedLayer = {
@@ -35,9 +35,9 @@ export declare function readStaged(record: ReplicaRecord, previous?: ConfirmedLa
35
35
  export declare function readReclassified(record: ReplicaRecord, previous: ConfirmedLayer): Staged | {
36
36
  kind: 'deferred';
37
37
  };
38
- export declare function applyReturned(confirmed: ConfirmedLayer, documents: Readonly<Record<string, string>>, revisions: Readonly<Record<string, string>>, removals: readonly string[], attachments: readonly RoomAttachment[] | undefined, roomVersion: string, writtenAt: string): Staged;
38
+ export declare function applyReturned(confirmed: ConfirmedLayer, documents: Readonly<Record<string, string>>, revisions: Readonly<Record<string, string>>, changes: Readonly<Record<string, HeadChange>>, removals: readonly string[], attachments: readonly RoomAttachment[] | undefined, roomVersion: string, writtenAt: string): Staged;
39
39
  export declare function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], previous?: Replica): Replica;
40
- export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer): boolean;
40
+ export declare function landed(batch: ChangeBatch, confirmed: ConfirmedLayer, current?: Readonly<Record<string, string>>): boolean;
41
41
  export declare function withdrawals(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[], withdrawable: (batch: ChangeBatch) => boolean): readonly ChangeBatch[];
42
42
  export {};
43
43
  //# sourceMappingURL=replica.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,KAAK,WAAW,EAAqB,MAAM,aAAa,CAAC;AAC1F,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA0C,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAGlF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC;AAE7E,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9B,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC;IACd,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,WAAW,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;CACzB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAQhE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAWtF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAKnF;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAkBnF;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,cAAc,GACvB,MAAM,GAAG;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAM/B;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,SAAS,cAAc,EAAE,GAAG,SAAS,EAClD,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAmCR;AAsDD,wBAAgB,SAAS,CACvB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,QAAQ,CAAC,EAAE,OAAO,GACjB,OAAO,CAgCT;AAkFD,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO,CAa7E;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,GAC5C,SAAS,WAAW,EAAE,CAmBxB"}
1
+ {"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"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"}
package/dist/replica.js CHANGED
@@ -46,7 +46,7 @@ export function readReclassified(record, previous) {
46
46
  ? { kind: 'deferred' }
47
47
  : { kind: 'refused', refusal: verdict };
48
48
  }
49
- export function applyReturned(confirmed, documents, revisions, removals, attachments, roomVersion, writtenAt) {
49
+ export function applyReturned(confirmed, documents, revisions, changes, removals, attachments, roomVersion, writtenAt) {
50
50
  const nextDocuments = { ...confirmed.record.documents, ...documents };
51
51
  const nextRevisions = { ...confirmed.record.revisions, ...revisions };
52
52
  const nextChanges = { ...confirmed.record.changes };
@@ -59,6 +59,7 @@ export function applyReturned(confirmed, documents, revisions, removals, attachm
59
59
  if (confirmed.record.revisions[path] !== revision)
60
60
  delete nextChanges[path];
61
61
  }
62
+ Object.assign(nextChanges, changes);
62
63
  for (const path of removals) {
63
64
  delete nextDocuments[path];
64
65
  delete nextRevisions[path];
@@ -229,8 +230,8 @@ function after(changes, index, path) {
229
230
  }
230
231
  return at;
231
232
  }
232
- export function landed(batch, confirmed) {
233
- const layer = confirmed.record;
233
+ export function landed(batch, confirmed, current = {}) {
234
+ const layer = { ...confirmed.record, documents: { ...confirmed.record.documents, ...current } };
234
235
  return batch.changes.every((change, index) => {
235
236
  if (change.kind === 'replace' || (change.kind === 'create' && 'content' in change)) {
236
237
  const at = after(batch.changes, index, change.path);
package/dist/rows.d.ts CHANGED
@@ -10,7 +10,7 @@ export type DocumentRow = {
10
10
  type: string | null;
11
11
  fields: Fields;
12
12
  values: Fields;
13
- sizes: Readonly<Record<string, number>>;
13
+ reached: Readonly<Record<string, readonly unknown[]>>;
14
14
  directories: readonly string[];
15
15
  body: string;
16
16
  change: HeadChange | null;
@@ -31,6 +31,7 @@ export type ReferenceRow = {
31
31
  source: string;
32
32
  target: string;
33
33
  field: string;
34
+ forms: readonly string[];
34
35
  path: string;
35
36
  type: string;
36
37
  };
@@ -1 +1 @@
1
- {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../src/rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,KAAK,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG,WAAW,GAAG,OAAO,GAAG,YAAY,CAAC;AAMvD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAiBD,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,UAAU,GAAG,IAAI,GACxB,SAAS,GAAG,EAAE,CAsEhB"}
1
+ {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../src/rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,KAAK,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEhD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC,CAAC,CAAC;IACtD,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,GAAG,GAAG,WAAW,GAAG,OAAO,GAAG,YAAY,CAAC;AAMvD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAmFD,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,UAAU,GAAG,IAAI,GACxB,SAAS,GAAG,EAAE,CAuEhB"}
package/dist/rows.js CHANGED
@@ -1,21 +1,65 @@
1
- import { target } from '@agentshouse/mdmodel';
1
+ import { ARRAY_INDEX, escapePointer, references, target, } from '@agentshouse/mdmodel';
2
2
  import { governing } from './collection.js';
3
- import { definitionOf, referenceField } from './model.js';
3
+ import { definitionOf } from './model.js';
4
4
  function keyOf(...parts) {
5
5
  return `${parts.join('\u0000')}\u0000`;
6
6
  }
7
7
  export function documentKey(room, path) {
8
8
  return keyOf('d', room, path);
9
9
  }
10
- function targetOf(path, value) {
11
- return typeof value === 'string' ? target(path, value) : null;
10
+ function plainObject(value) {
11
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
12
12
  }
13
- function resolved(path, value) {
14
- if (value === null)
15
- return null;
16
- if (!Array.isArray(value))
17
- return targetOf(path, value) ?? undefined;
18
- return value.map((item) => targetOf(path, item)).filter((item) => item !== null);
13
+ function compared(reading, exact, value) {
14
+ if (!reading.references.has(exact))
15
+ return value;
16
+ return (typeof value === 'string' ? target(reading.path, value) : null) ?? undefined;
17
+ }
18
+ function record(reading, node, forms, exact) {
19
+ const value = Array.isArray(node)
20
+ ? node.map((item, index) => compared(reading, `${exact}/${index}`, item))
21
+ : compared(reading, exact, node);
22
+ for (const form of forms) {
23
+ if (form.pending)
24
+ continue;
25
+ (reading.reached[form.text] ??= []).push(value);
26
+ if (!form.through && value !== undefined && !plainObject(value)) {
27
+ reading.values[form.text] = value;
28
+ }
29
+ }
30
+ if (Array.isArray(node) || plainObject(node) || !reading.references.has(exact))
31
+ return;
32
+ const found = compared(reading, exact, node);
33
+ if (typeof found !== 'string')
34
+ return;
35
+ const field = forms
36
+ .map((form) => form.text)
37
+ .reduce((left, right) => (right.length < left.length ? right : left));
38
+ const known = reading.targets.get(`${field}\u0000${found}`);
39
+ const kept = known ?? { field, target: found, forms: new Set() };
40
+ for (const form of forms)
41
+ kept.forms.add(form.text);
42
+ reading.targets.set(`${field}\u0000${found}`, kept);
43
+ }
44
+ function walk(reading, node, forms, exact) {
45
+ record(reading, node, forms, exact);
46
+ if (Array.isArray(node)) {
47
+ node.forEach((item, index) => walk(reading, item, forms.flatMap((form) => [
48
+ ...(form.pending
49
+ ? []
50
+ : [{ text: `${form.text}/${index}`, through: form.through, pending: false }]),
51
+ { text: form.text, through: true, pending: true },
52
+ ]), `${exact}/${index}`));
53
+ return;
54
+ }
55
+ if (!plainObject(node))
56
+ return;
57
+ for (const [key, value] of Object.entries(node)) {
58
+ const segment = escapePointer(key);
59
+ walk(reading, value, forms.flatMap((form) => form.pending && ARRAY_INDEX.test(key)
60
+ ? []
61
+ : [{ text: `${form.text}/${segment}`, through: form.through, pending: false }]), `${exact}/${segment}`);
62
+ }
19
63
  }
20
64
  function directoriesOf(path) {
21
65
  const parts = path.split('/').slice(0, -1);
@@ -34,7 +78,7 @@ export function rowsOf(room, path, document, composition, change) {
34
78
  type: null,
35
79
  fields: {},
36
80
  values: {},
37
- sizes: {},
81
+ reached: {},
38
82
  directories: directoriesOf(path),
39
83
  body,
40
84
  change,
@@ -43,32 +87,18 @@ export function rowsOf(room, path, document, composition, change) {
43
87
  }
44
88
  const type = document.type ?? 'any';
45
89
  const definition = definitionOf(governing(composition, path), document.type);
46
- const values = {};
47
- const sizes = {};
48
- const references = [];
90
+ const reading = {
91
+ path,
92
+ references: new Set(definition === undefined ? [] : references(document, definition).map((one) => one.pointer)),
93
+ values: {},
94
+ reached: {},
95
+ targets: new Map(),
96
+ };
49
97
  for (const [name, value] of Object.entries(document.fields)) {
50
- const reference = referenceField(definition?.fields[name]);
51
- const compared = reference ? resolved(path, value) : value;
52
- if (compared !== undefined)
53
- values[name] = compared;
54
- if (Array.isArray(value))
55
- sizes[name] = value.length;
56
- if (!reference)
57
- continue;
58
- const targets = [compared].flat().filter((found) => typeof found === 'string');
59
- for (const found of new Set(targets)) {
60
- references.push({
61
- key: keyOf('r', room, path, name, found),
62
- kind: 'reference',
63
- room,
64
- source: key,
65
- target: documentKey(room, found),
66
- field: name,
67
- path,
68
- type,
69
- });
70
- }
98
+ const segment = escapePointer(name);
99
+ walk(reading, value, [{ text: `/${segment}`, through: false, pending: false }], `/${segment}`);
71
100
  }
101
+ const { values, reached } = reading;
72
102
  return [
73
103
  {
74
104
  key,
@@ -78,7 +108,7 @@ export function rowsOf(room, path, document, composition, change) {
78
108
  type,
79
109
  fields: document.fields,
80
110
  values,
81
- sizes,
111
+ reached,
82
112
  directories: directoriesOf(path),
83
113
  body,
84
114
  change,
@@ -92,6 +122,16 @@ export function rowsOf(room, path, document, composition, change) {
92
122
  sections: document.sections,
93
123
  markdown: document.content,
94
124
  },
95
- ...references,
125
+ ...[...reading.targets.values()].map(({ field, target: found, forms }) => ({
126
+ key: keyOf('r', room, path, field, found),
127
+ kind: 'reference',
128
+ room,
129
+ source: key,
130
+ target: documentKey(room, found),
131
+ field,
132
+ forms: [...forms].sort(),
133
+ path,
134
+ type,
135
+ })),
96
136
  ];
97
137
  }
package/dist/save.d.ts CHANGED
@@ -17,6 +17,7 @@ export type SaveInput = {
17
17
  providerOwnedPaths: readonly string[];
18
18
  providerLimits: readonly ProviderLimit[];
19
19
  visible: VisibleLayer;
20
+ handle: string;
20
21
  changes: readonly Change[];
21
22
  bases: readonly Precondition[];
22
23
  writtenBy?: WrittenBy;
@@ -1 +1 @@
1
- {"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,OAAO,cAAc,EAAE,eAAe,CAAC;IACnD,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAoK9C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW,CAOxF;AA2MD,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CA2FxD"}
1
+ {"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAKL,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,OAAO,cAAc,EAAE,eAAe,CAAC;IACnD,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AA+K9C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW,CAOxF;AAsQD,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAyFxD"}