@agentshouse/mdruntime 0.1.0-alpha.9 → 0.1.0-c3903a68dcbbf

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 (124) hide show
  1. package/AGENTS.md +210 -0
  2. package/README.md +44 -0
  3. package/dist/adapter.d.ts +155 -12
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +2 -3
  6. package/dist/attachment.d.ts +3 -0
  7. package/dist/attachment.d.ts.map +1 -0
  8. package/dist/attachment.js +8 -0
  9. package/dist/bootstrap.d.ts +3 -7
  10. package/dist/bootstrap.d.ts.map +1 -1
  11. package/dist/bootstrap.js +29 -27
  12. package/dist/change-set.d.ts +33 -0
  13. package/dist/change-set.d.ts.map +1 -0
  14. package/dist/change-set.js +87 -0
  15. package/dist/change.d.ts +9 -0
  16. package/dist/change.d.ts.map +1 -1
  17. package/dist/change.js +6 -5
  18. package/dist/client.d.ts +40 -28
  19. package/dist/client.d.ts.map +1 -1
  20. package/dist/client.js +121 -177
  21. package/dist/collection.d.ts +15 -16
  22. package/dist/collection.d.ts.map +1 -1
  23. package/dist/collection.js +54 -87
  24. package/dist/connection.d.ts +57 -35
  25. package/dist/connection.d.ts.map +1 -1
  26. package/dist/connection.js +1475 -964
  27. package/dist/conversation.d.ts +41 -19
  28. package/dist/conversation.d.ts.map +1 -1
  29. package/dist/conversation.js +483 -327
  30. package/dist/durability.js +6 -6
  31. package/dist/file.d.ts +2 -2
  32. package/dist/file.d.ts.map +1 -1
  33. package/dist/file.js +48 -71
  34. package/dist/host.d.ts +7 -2
  35. package/dist/host.d.ts.map +1 -1
  36. package/dist/host.js +100 -102
  37. package/dist/identity.d.ts +1 -0
  38. package/dist/identity.d.ts.map +1 -1
  39. package/dist/identity.js +10 -9
  40. package/dist/index.d.ts +12 -10
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +1 -2
  43. package/dist/log.js +5 -6
  44. package/dist/memory.d.ts +6 -3
  45. package/dist/memory.d.ts.map +1 -1
  46. package/dist/memory.js +206 -210
  47. package/dist/model.d.ts +10 -25
  48. package/dist/model.d.ts.map +1 -1
  49. package/dist/model.js +18 -21
  50. package/dist/observation.d.ts +25 -0
  51. package/dist/observation.d.ts.map +1 -0
  52. package/dist/observation.js +85 -0
  53. package/dist/outcome.d.ts +17 -20
  54. package/dist/outcome.d.ts.map +1 -1
  55. package/dist/outcome.js +1 -23
  56. package/dist/overlay.d.ts +9 -2
  57. package/dist/overlay.d.ts.map +1 -1
  58. package/dist/overlay.js +187 -43
  59. package/dist/paths.d.ts +0 -1
  60. package/dist/paths.d.ts.map +1 -1
  61. package/dist/paths.js +12 -19
  62. package/dist/query.d.ts +210 -10
  63. package/dist/query.d.ts.map +1 -1
  64. package/dist/query.js +420 -15
  65. package/dist/read-side.d.ts +14 -0
  66. package/dist/read-side.d.ts.map +1 -0
  67. package/dist/read-side.js +371 -0
  68. package/dist/refresh.d.ts +4 -5
  69. package/dist/refresh.d.ts.map +1 -1
  70. package/dist/refresh.js +45 -30
  71. package/dist/replica.d.ts +25 -5
  72. package/dist/replica.d.ts.map +1 -1
  73. package/dist/replica.js +232 -38
  74. package/dist/room-draft.d.ts +124 -0
  75. package/dist/room-draft.d.ts.map +1 -0
  76. package/dist/room-draft.js +327 -0
  77. package/dist/rows.d.ts +41 -0
  78. package/dist/rows.d.ts.map +1 -0
  79. package/dist/rows.js +100 -0
  80. package/dist/save.d.ts +8 -4
  81. package/dist/save.d.ts.map +1 -1
  82. package/dist/save.js +265 -350
  83. package/dist/search.d.ts +61 -0
  84. package/dist/search.d.ts.map +1 -0
  85. package/dist/search.js +125 -0
  86. package/dist/status.d.ts +4 -6
  87. package/dist/status.d.ts.map +1 -1
  88. package/dist/status.js +9 -13
  89. package/dist/store.d.ts +68 -30
  90. package/dist/store.d.ts.map +1 -1
  91. package/dist/store.js +360 -134
  92. package/dist/transfer.d.ts +5 -0
  93. package/dist/transfer.d.ts.map +1 -1
  94. package/dist/transfer.js +1 -5
  95. package/dist/wire.d.ts +4 -3
  96. package/dist/wire.d.ts.map +1 -1
  97. package/dist/wire.js +50 -65
  98. package/package.json +6 -12
  99. package/dist/adapter.js.map +0 -1
  100. package/dist/bootstrap.js.map +0 -1
  101. package/dist/change.js.map +0 -1
  102. package/dist/client.js.map +0 -1
  103. package/dist/collection.js.map +0 -1
  104. package/dist/connection.js.map +0 -1
  105. package/dist/conversation.js.map +0 -1
  106. package/dist/durability.js.map +0 -1
  107. package/dist/file.js.map +0 -1
  108. package/dist/host.js.map +0 -1
  109. package/dist/identity.js.map +0 -1
  110. package/dist/index.js.map +0 -1
  111. package/dist/log.js.map +0 -1
  112. package/dist/memory.js.map +0 -1
  113. package/dist/model.js.map +0 -1
  114. package/dist/outcome.js.map +0 -1
  115. package/dist/overlay.js.map +0 -1
  116. package/dist/paths.js.map +0 -1
  117. package/dist/query.js.map +0 -1
  118. package/dist/refresh.js.map +0 -1
  119. package/dist/replica.js.map +0 -1
  120. package/dist/save.js.map +0 -1
  121. package/dist/status.js.map +0 -1
  122. package/dist/store.js.map +0 -1
  123. package/dist/transfer.js.map +0 -1
  124. package/dist/wire.js.map +0 -1
package/dist/log.js CHANGED
@@ -2,14 +2,13 @@ const BOUND = 256;
2
2
  export function createLog() {
3
3
  const events = [];
4
4
  return {
5
- record (event) {
5
+ record(event) {
6
6
  events.push(event);
7
- if (events.length > BOUND) events.splice(0, events.length - BOUND);
7
+ if (events.length > BOUND)
8
+ events.splice(0, events.length - BOUND);
8
9
  },
9
- export () {
10
+ export() {
10
11
  return events.join('\n');
11
- }
12
+ },
12
13
  };
13
14
  }
14
-
15
- //# sourceMappingURL=log.js.map
package/dist/memory.d.ts CHANGED
@@ -1,15 +1,17 @@
1
1
  import type { ModelResult } from './model.js';
2
- import { type ActionResult, type Adapter, type Capability, type ConversationAction, type ConversationEvent, type ConversationMessage, type DiscoveredRoom, type MdModelIdentity, type ProviderLimit, type Retention, type RoomVersionNotification } from './adapter.js';
2
+ import { type AcceptedMessage, type ActionResult, type Adapter, type Capability, type ConversationAction, type ConversationEvent, type DiscoveredRoom, type HeadChange, type MdModelIdentity, type ProviderLimit, type Retention, type RoomAttachment, type RoomVersionNotification, type ServiceMode } from './adapter.js';
3
3
  export type MemoryRoom = DiscoveredRoom & {
4
4
  model?: ModelResult;
5
5
  selectionModel?: ModelResult;
6
6
  documents?: Readonly<Record<string, string>>;
7
7
  revisions?: Readonly<Record<string, string>>;
8
+ changes?: Readonly<Record<string, HeadChange>>;
8
9
  binaryTargets?: readonly string[];
10
+ attachments?: readonly RoomAttachment[];
9
11
  };
10
12
  export type MemoryConversation = {
11
13
  conversation: string;
12
- messages?: readonly ConversationMessage[];
14
+ messages?: readonly AcceptedMessage[];
13
15
  outcomes?: Partial<Record<ConversationAction, ActionResult>>;
14
16
  };
15
17
  export type MemoryAdapterOptions = {
@@ -29,8 +31,9 @@ export type MemoryAdapter = Adapter & {
29
31
  script(operation: keyof Adapter, answer: unknown): void;
30
32
  notifyRoomVersion(notification: RoomVersionNotification): void;
31
33
  notifyConversation(event: ConversationEvent): void;
34
+ notifyServiceMode(mode: ServiceMode): void;
32
35
  selectedRooms(): readonly string[];
33
- viewedConversations(): readonly string[];
36
+ replicatedConversations(): readonly string[];
34
37
  };
35
38
  export declare function createMemoryAdapter(options?: MemoryAdapterOptions): MemoryAdapter;
36
39
  //# sourceMappingURL=memory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,OAAO,EAIZ,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAExB,KAAK,cAAc,EAGnB,KAAK,eAAe,EAGpB,KAAK,aAAa,EAGlB,KAAK,SAAS,EACd,KAAK,uBAAuB,EAC7B,MAAM,cAAc,CAAC;AAkBtB,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC,CAAC;CAC9D,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,YAAY,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACrC,cAAc,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI,CAAC;IAC7C,gBAAgB,CAAC,aAAa,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI,CAAC;IACrE,MAAM,CAAC,SAAS,EAAE,MAAM,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACxD,iBAAiB,CAAC,YAAY,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC/D,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnD,aAAa,IAAI,SAAS,MAAM,EAAE,CAAC;IACnC,mBAAmB,IAAI,SAAS,MAAM,EAAE,CAAC;CAC1C,CAAC;AA+BF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAwUrF"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,YAAY,EACjB,KAAK,OAAO,EAIZ,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EAItB,KAAK,cAAc,EACnB,KAAK,UAAU,EAGf,KAAK,eAAe,EAGpB,KAAK,aAAa,EAGlB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAmBtB,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC,CAAC;CAC9D,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAC9B,aAAa,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,YAAY,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACrC,cAAc,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI,CAAC;IAC7C,gBAAgB,CAAC,aAAa,EAAE,SAAS,kBAAkB,EAAE,GAAG,IAAI,CAAC;IACrE,MAAM,CAAC,SAAS,EAAE,MAAM,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACxD,iBAAiB,CAAC,YAAY,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC/D,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnD,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3C,aAAa,IAAI,SAAS,MAAM,EAAE,CAAC;IACnC,uBAAuB,IAAI,SAAS,MAAM,EAAE,CAAC;CAC9C,CAAC;AA+BF,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAkZrF"}
package/dist/memory.js CHANGED
@@ -1,16 +1,15 @@
1
- import { ROOM_CONTRACT_VERSION } from './adapter.js';
1
+ import { ROOM_CONTRACT_VERSION, } from './adapter.js';
2
2
  import { MD_MODEL } from './collection.js';
3
+ import { sameChange } from './overlay.js';
3
4
  const FIXTURE_RETENTION = {
4
- history: {
5
- kind: 'duration',
6
- seconds: 1
7
- },
5
+ history: { kind: 'duration', seconds: 1 },
8
6
  outcome: 1,
9
- refreshHorizon: 1
7
+ refreshHorizon: 1,
10
8
  };
11
9
  function declaredRetention(value) {
12
10
  const retention = value ?? FIXTURE_RETENTION;
13
- if (retention.history.kind === 'no-declared-time-bound') return retention;
11
+ if (retention.history.kind === 'no-declared-time-bound')
12
+ return retention;
14
13
  if (Number.isFinite(retention.history.seconds) && retention.history.seconds > 0) {
15
14
  return retention;
16
15
  }
@@ -18,24 +17,22 @@ function declaredRetention(value) {
18
17
  }
19
18
  function named(source, paths) {
20
19
  const taken = {};
21
- for (const path of paths){
20
+ for (const path of paths) {
22
21
  const value = source[path];
23
- if (value !== undefined) taken[path] = value;
22
+ if (value !== undefined)
23
+ taken[path] = value;
24
24
  }
25
25
  return taken;
26
26
  }
27
27
  async function resolveScript(answer, fallback, request) {
28
- if (answer === undefined) return fallback();
28
+ if (answer === undefined)
29
+ return fallback();
29
30
  return typeof answer === 'function' ? answer(request) : answer;
30
31
  }
31
32
  export function createMemoryAdapter(options = {}) {
32
- let rooms = options.rooms === undefined ? [] : [
33
- ...options.rooms
34
- ];
33
+ let rooms = options.rooms === undefined ? [] : [...options.rooms];
35
34
  const mdModel = options.mdModel ?? MD_MODEL;
36
- const supportedVersions = options.supportedVersions ?? [
37
- ROOM_CONTRACT_VERSION
38
- ];
35
+ const supportedVersions = options.supportedVersions ?? [ROOM_CONTRACT_VERSION];
39
36
  const capabilities = options.capabilities ?? [];
40
37
  const providerLimits = options.providerLimits ?? [];
41
38
  const retention = declaredRetention(options.retention);
@@ -45,20 +42,43 @@ export function createMemoryAdapter(options = {}) {
45
42
  const refreshPages = new Map();
46
43
  const observers = new Set();
47
44
  const listeners = new Set();
45
+ const modeObservers = new Set();
48
46
  const scripted = new Map();
49
47
  const unsealed = new Map();
50
48
  const sealed = new Set();
51
49
  const historyPageSize = options.historyPageSize;
52
50
  let selected = [];
53
- let viewed = [];
51
+ let replicated = [];
54
52
  let issued = 0;
55
53
  function scriptConversations(entries) {
56
54
  scripted.clear();
57
- for (const entry of entries)scripted.set(entry.conversation, entry);
55
+ for (const entry of entries)
56
+ scripted.set(entry.conversation, entry);
58
57
  }
59
58
  scriptConversations(options.conversations ?? []);
59
+ const ordinals = new Map();
60
+ function note(locator, answer) {
61
+ const roomVersion = answer.roomVersion;
62
+ const key = `${locator}\u0000${String(roomVersion)}`;
63
+ if (typeof roomVersion === 'string' && !ordinals.has(key))
64
+ ordinals.set(key, ordinals.size);
65
+ return answer;
66
+ }
67
+ function reached(locator, roomVersion, target) {
68
+ const scripted = scripts.reached;
69
+ if (typeof scripted === 'boolean')
70
+ return scripted;
71
+ if (scripted !== undefined)
72
+ return scripted(locator, roomVersion, target);
73
+ if (roomVersion === target)
74
+ return true;
75
+ const held = ordinals.get(`${locator}\u0000${roomVersion}`);
76
+ const wanted = ordinals.get(`${locator}\u0000${target}`);
77
+ return held !== undefined && wanted !== undefined && held >= wanted;
78
+ }
60
79
  function retain(entries) {
61
- for (const room of entries){
80
+ for (const room of entries) {
81
+ note(room.locator, room);
62
82
  const versions = served.get(room.locator) ?? new Map();
63
83
  versions.set(room.roomVersion, room);
64
84
  served.set(room.locator, versions);
@@ -69,15 +89,13 @@ export function createMemoryAdapter(options = {}) {
69
89
  return {
70
90
  name: room.name,
71
91
  locator: room.locator,
72
- collectionRoot: room.collectionRoot,
73
92
  roomVersion: room.roomVersion,
74
93
  operations: room.operations,
75
94
  replica: room.replica,
76
95
  attachedModel: room.attachedModel,
77
- ...room.typedSelection === undefined ? {} : {
78
- typedSelection: room.typedSelection
79
- },
80
- providerOwnedPaths: room.providerOwnedPaths
96
+ ...(room.typedSelection === undefined ? {} : { typedSelection: room.typedSelection }),
97
+ ...(room.untypedFolders === undefined ? {} : { untypedFolders: room.untypedFolders }),
98
+ providerOwnedPaths: room.providerOwnedPaths,
81
99
  };
82
100
  }
83
101
  function page(room, from) {
@@ -85,15 +103,16 @@ export function createMemoryAdapter(options = {}) {
85
103
  const size = pageSize ?? paths.length;
86
104
  const taken = paths.slice(from, from + size);
87
105
  const next = from + taken.length;
106
+ const targets = from === 0 ? (room.binaryTargets ?? []) : [];
88
107
  return {
89
108
  kind: 'bootstrap',
90
109
  roomVersion: room.roomVersion,
91
110
  documents: named(room.documents ?? {}, taken),
92
111
  revisions: named(room.revisions ?? {}, taken),
93
- binaryTargets: from === 0 ? room.binaryTargets ?? [] : [],
94
- ...next < paths.length ? {
95
- pageToken: String(next)
96
- } : {}
112
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
113
+ binaryTargets: targets,
114
+ ...(from === 0 && room.attachments !== undefined ? { attachments: room.attachments } : {}),
115
+ ...(next < paths.length ? { pageToken: String(next) } : {}),
97
116
  };
98
117
  }
99
118
  function advancement(room, from, at) {
@@ -101,128 +120,107 @@ export function createMemoryAdapter(options = {}) {
101
120
  const previous = from.documents ?? {};
102
121
  const currentTargets = new Set(room.binaryTargets ?? []);
103
122
  const previousTargets = new Set(from.binaryTargets ?? []);
104
- const changed = Object.keys(current).filter((path)=>current[path] !== previous[path]).sort();
123
+ const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
124
+ !sameChange(room.changes?.[path], from.changes?.[path]);
125
+ const changed = Object.keys(current)
126
+ .filter((path) => current[path] !== previous[path] || headMoved(path))
127
+ .sort();
105
128
  const size = pageSize ?? changed.length;
106
129
  const taken = changed.slice(at, at + size);
107
130
  const next = at + taken.length;
108
131
  const opening = at === 0;
109
132
  const pageToken = next < changed.length ? `refresh-${refreshPages.size}` : undefined;
110
- if (pageToken !== undefined) refreshPages.set(pageToken, {
111
- room,
112
- from,
113
- at: next
114
- });
133
+ if (pageToken !== undefined)
134
+ refreshPages.set(pageToken, { room, from, at: next });
135
+ const targets = opening
136
+ ? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
137
+ : [];
138
+ const attachments = room.attachments ?? [];
139
+ const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
115
140
  return {
116
141
  kind: 'net-advancement',
117
142
  roomVersion: room.roomVersion,
118
143
  documents: named(current, taken),
119
144
  revisions: named(room.revisions ?? {}, taken),
120
- binaryTargets: opening ? [
121
- ...currentTargets
122
- ].filter((target)=>!previousTargets.has(target)) : [],
123
- removals: opening ? [
124
- ...Object.keys(previous).filter((path)=>!(path in current) && !currentTargets.has(path)),
125
- ...[
126
- ...previousTargets
127
- ].filter((target)=>!currentTargets.has(target) && !(target in current))
128
- ].sort() : [],
129
- ...pageToken === undefined ? {} : {
130
- pageToken
131
- }
145
+ changes: named(room.changes ?? {}, [...taken, ...targets]),
146
+ binaryTargets: targets,
147
+ removals: opening
148
+ ? [
149
+ ...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
150
+ ...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
151
+ ].sort()
152
+ : [],
153
+ ...(declared ? { attachments } : {}),
154
+ ...(pageToken === undefined ? {} : { pageToken }),
132
155
  };
133
156
  }
134
- function historyOf(conversation, cursor) {
157
+ function pageOf(conversation, after) {
135
158
  const messages = conversation.messages ?? [];
136
- const until = typeof cursor === 'string' ? Number(cursor) : messages.length;
137
- if (!Number.isInteger(until) || until < 0 || until > messages.length) {
138
- return {
139
- kind: 'rejected',
140
- code: 'unknown-cursor',
141
- fields: {
142
- cursor
143
- }
144
- };
145
- }
146
- const size = historyPageSize ?? messages.length;
147
- const from = Math.max(0, until - size);
159
+ const first = typeof after === 'string' ? messages.findIndex((message) => message.position > after) : 0;
160
+ const from = first === -1 ? messages.length : first;
161
+ const page = messages.slice(from, from + (historyPageSize ?? messages.length));
162
+ const last = page.at(-1);
148
163
  return {
149
- kind: 'action',
150
- result: {
151
- messages: messages.slice(from, until),
152
- ...from === 0 ? {} : {
153
- cursor: String(from)
154
- }
155
- }
164
+ conversation: conversation.conversation,
165
+ messages: page,
166
+ ...(last !== undefined && from + page.length < messages.length
167
+ ? { next: last.position }
168
+ : {}),
156
169
  };
157
170
  }
171
+ function historiesOf(input) {
172
+ const asked = input?.conversations;
173
+ if (!Array.isArray(asked))
174
+ return { kind: 'rejected', code: 'invalid_request', fields: {} };
175
+ const histories = [];
176
+ for (const entry of asked) {
177
+ const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
178
+ if (conversation === undefined)
179
+ continue;
180
+ const outcome = conversation.outcomes?.['conversation.history'];
181
+ if (outcome !== undefined)
182
+ return outcome;
183
+ histories.push(pageOf(conversation, entry.after));
184
+ }
185
+ const result = { histories };
186
+ return { kind: 'action', result };
187
+ }
158
188
  function conversationAction(request) {
159
189
  const name = request.name;
160
- const input = request.input ?? {};
190
+ const input = (request.input ?? {});
191
+ if (name === 'conversation.history')
192
+ return historiesOf(request.input);
161
193
  if (name === 'conversation.create') {
162
194
  issued += 1;
163
195
  const conversation = `conversation-${issued}`;
164
- scripted.set(conversation, {
165
- conversation
166
- });
167
- return {
168
- kind: 'action',
169
- result: {
170
- conversation
171
- }
172
- };
196
+ scripted.set(conversation, { conversation });
197
+ return { kind: 'action', result: { conversation } };
173
198
  }
174
199
  const named = typeof input.conversation === 'string' ? input.conversation : '';
175
200
  const conversation = scripted.get(named);
176
201
  if (conversation === undefined) {
177
- return {
178
- kind: 'rejected',
179
- code: 'unknown-conversation',
180
- fields: {
181
- conversation: named
182
- }
183
- };
202
+ return { kind: 'rejected', code: 'unknown-conversation', fields: { conversation: named } };
184
203
  }
185
204
  const outcome = conversation.outcomes?.[name];
186
- if (outcome !== undefined) return outcome;
187
- if (name === 'conversation.history') return historyOf(conversation, input.cursor);
205
+ if (outcome !== undefined)
206
+ return outcome;
188
207
  if (name === 'conversation.send') {
189
208
  issued += 1;
190
209
  const turn = `turn-${issued}`;
191
210
  unsealed.set(turn, named);
192
- return {
193
- kind: 'action',
194
- result: {
195
- turn
196
- }
197
- };
211
+ return { kind: 'action', result: { turn } };
198
212
  }
199
213
  if (name === 'conversation.cancel') {
200
214
  const turn = typeof input.turn === 'string' ? input.turn : '';
201
215
  if (sealed.has(turn) || !unsealed.has(turn)) {
202
- return {
203
- kind: 'rejected',
204
- code: 'turn-sealed',
205
- fields: {
206
- turn
207
- }
208
- };
216
+ return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
209
217
  }
210
218
  unsealed.delete(turn);
211
- return {
212
- kind: 'action',
213
- result: {
214
- turn,
215
- cancelled: true
216
- }
217
- };
219
+ return { kind: 'action', result: { turn, cancelled: true } };
218
220
  }
219
- if (name === 'conversation.delete') scripted.delete(named);
220
- return {
221
- kind: 'action',
222
- result: {
223
- conversation: named
224
- }
225
- };
221
+ if (name === 'conversation.delete')
222
+ scripted.delete(named);
223
+ return { kind: 'action', result: { conversation: named } };
226
224
  }
227
225
  function discovery() {
228
226
  return {
@@ -232,164 +230,162 @@ export function createMemoryAdapter(options = {}) {
232
230
  rooms: rooms.map(declared),
233
231
  capabilities,
234
232
  providerLimits,
235
- retention
233
+ retention,
236
234
  };
237
235
  }
238
236
  return {
239
- setRooms (next) {
240
- rooms = [
241
- ...next
242
- ];
237
+ setRooms(next) {
238
+ rooms = [...next];
243
239
  retain(rooms);
244
240
  },
245
- setConversations (next) {
241
+ setConversations(next) {
246
242
  scriptConversations(next);
247
243
  },
248
- notifyRoomVersion (notification) {
249
- for (const observer of observers)observer(notification);
244
+ notifyRoomVersion(notification) {
245
+ for (const observer of observers)
246
+ observer(notification);
250
247
  },
251
- notifyConversation (event) {
248
+ notifyConversation(event) {
252
249
  if (event.kind === 'accepted-message') {
253
250
  sealed.add(event.message.turn);
254
251
  unsealed.delete(event.message.turn);
255
252
  }
256
- for (const listener of listeners)listener(event);
253
+ for (const listener of listeners)
254
+ listener(event);
255
+ },
256
+ notifyServiceMode(mode) {
257
+ for (const observer of modeObservers)
258
+ observer(mode);
257
259
  },
258
- selectedRooms () {
260
+ selectedRooms() {
259
261
  return selected;
260
262
  },
261
- viewedConversations () {
262
- return viewed;
263
+ replicatedConversations() {
264
+ return replicated;
263
265
  },
264
266
  conversations: {
265
- view (next) {
266
- viewed = [
267
- ...next
268
- ];
267
+ replicate(next) {
268
+ replicated = [...next];
269
269
  },
270
- observe (notify) {
270
+ observe(notify) {
271
271
  listeners.add(notify);
272
- return ()=>{
272
+ return () => {
273
273
  listeners.delete(notify);
274
274
  };
275
- }
275
+ },
276
+ },
277
+ serviceMode: {
278
+ observe(notify) {
279
+ modeObservers.add(notify);
280
+ return () => {
281
+ modeObservers.delete(notify);
282
+ };
283
+ },
276
284
  },
277
285
  roomVersions: {
278
- select (locators) {
279
- selected = [
280
- ...locators
281
- ];
286
+ select(locators) {
287
+ selected = [...locators];
282
288
  },
283
- observe (notify) {
289
+ observe(notify) {
284
290
  observers.add(notify);
285
- return ()=>{
291
+ return () => {
286
292
  observers.delete(notify);
287
293
  };
288
- }
294
+ },
289
295
  },
290
- script (operation, answer) {
291
- if (answer === undefined) delete scripts[operation];
292
- else scripts[operation] = answer;
296
+ script(operation, answer) {
297
+ if (answer === undefined)
298
+ delete scripts[operation];
299
+ else
300
+ scripts[operation] = answer;
293
301
  },
294
- async model (_authorization, request) {
295
- return resolveScript(scripts.model, ()=>{
296
- const room = rooms.find((entry)=>entry.locator === request.locator);
302
+ async model(_authorization, request) {
303
+ return resolveScript(scripts.model, () => {
304
+ const room = rooms.find((entry) => entry.locator === request.locator);
297
305
  const answer = request.attached === 'collection' ? room?.model : room?.selectionModel;
298
- return answer ?? {
299
- kind: 'model-unavailable',
300
- reason: 'not-readable'
301
- };
306
+ return answer ?? { kind: 'model-unavailable', reason: 'not-readable' };
302
307
  }, request);
303
308
  },
304
- async authorize () {
305
- return resolveScript(scripts.authorize, ()=>({}), undefined);
309
+ async authorize() {
310
+ return resolveScript(scripts.authorize, () => ({}), undefined);
306
311
  },
307
- async discover (_authorization) {
308
- return resolveScript(scripts.discover, discovery, undefined);
312
+ async discover(_authorization) {
313
+ return resolveScript(scripts.discover, discovery, undefined).then((answer) => {
314
+ if (answer.kind === 'discovery')
315
+ for (const room of answer.rooms)
316
+ note(room.locator, room);
317
+ return answer;
318
+ });
309
319
  },
310
- async bootstrap (_authorization, request) {
311
- return resolveScript(scripts.bootstrap, ()=>{
312
- const room = rooms.find((entry)=>entry.locator === request.locator);
320
+ reached,
321
+ async bootstrap(_authorization, request) {
322
+ return resolveScript(scripts.bootstrap, () => {
323
+ const room = rooms.find((entry) => entry.locator === request.locator);
313
324
  if (room === undefined) {
314
- return {
315
- kind: 'room-not-readable',
316
- locator: request.locator
317
- };
325
+ return { kind: 'room-not-readable', locator: request.locator };
318
326
  }
319
327
  return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));
320
- }, request);
328
+ }, request).then((answer) => note(request.locator, answer));
321
329
  },
322
- async refresh (_authorization, request) {
323
- return resolveScript(scripts.refresh, ()=>{
324
- const room = rooms.find((entry)=>entry.locator === request.locator);
330
+ async refresh(_authorization, request) {
331
+ return resolveScript(scripts.refresh, () => {
332
+ const room = rooms.find((entry) => entry.locator === request.locator);
325
333
  if (room === undefined) {
326
- return {
327
- kind: 'room-not-readable',
328
- locator: request.locator
329
- };
334
+ return { kind: 'room-not-readable', locator: request.locator };
330
335
  }
331
336
  if (request.pageToken !== undefined) {
332
337
  const continuation = refreshPages.get(request.pageToken);
333
- if (continuation === undefined || continuation.room.locator !== request.locator || continuation.from.roomVersion !== request.fromRoomVersion) {
338
+ if (continuation === undefined ||
339
+ continuation.room.locator !== request.locator ||
340
+ continuation.from.roomVersion !== request.fromRoomVersion) {
334
341
  throw new Error('Invalid Refresh Page Token');
335
342
  }
336
343
  return advancement(continuation.room, continuation.from, continuation.at);
337
344
  }
345
+ if (request.minPosition !== undefined &&
346
+ !reached(room.locator, room.roomVersion, request.minPosition)) {
347
+ return { kind: 'retryable-refusal', code: 'replica_behind', fields: {} };
348
+ }
338
349
  if (request.fromRoomVersion === room.roomVersion) {
339
- return {
340
- kind: 'still-current'
341
- };
350
+ return { kind: 'still-current' };
342
351
  }
343
352
  const from = served.get(room.locator)?.get(request.fromRoomVersion);
344
- if (from === undefined) return {
345
- kind: 'beyond-horizon'
346
- };
353
+ if (from === undefined)
354
+ return { kind: 'beyond-horizon' };
347
355
  return advancement(room, from, 0);
348
- }, request);
356
+ }, request).then((answer) => note(request.locator, answer));
349
357
  },
350
- async mutate (_authorization, request) {
351
- return resolveScript(scripts.mutate, ()=>{
352
- const room = rooms.find((entry)=>entry.locator === request.locator);
358
+ async mutate(_authorization, request) {
359
+ return resolveScript(scripts.mutate, () => {
360
+ const room = rooms.find((entry) => entry.locator === request.locator);
353
361
  if (room === undefined) {
354
- return {
355
- kind: 'room-not-readable',
356
- locator: request.locator
357
- };
362
+ return { kind: 'room-not-readable', locator: request.locator };
358
363
  }
359
- return {
360
- kind: 'rejected',
361
- code: 'unscripted-mutation',
362
- fields: {},
363
- affected: {}
364
- };
365
- }, request);
364
+ return { kind: 'rejected', code: 'unscripted-mutation', fields: {}, affected: {} };
365
+ }, request).then((answer) => note(request.locator, answer));
366
366
  },
367
- async history (_authorization, request) {
368
- return resolveScript(scripts.history, ()=>{
369
- const room = rooms.find((entry)=>entry.locator === request.locator);
367
+ async history(_authorization, request) {
368
+ return resolveScript(scripts.history, () => {
369
+ const room = rooms.find((entry) => entry.locator === request.locator);
370
370
  if (room === undefined) {
371
- return {
372
- kind: 'room-not-readable',
373
- locator: request.locator
374
- };
371
+ return { kind: 'room-not-readable', locator: request.locator };
375
372
  }
376
373
  return {
377
374
  kind: 'history',
378
- revisions: []
375
+ revisions: [],
379
376
  };
380
377
  }, request);
381
378
  },
382
- async action (_authorization, request) {
383
- return resolveScript(scripts.action, ()=>{
384
- if (request.name.startsWith('conversation.')) return conversationAction(request);
385
- return {
386
- kind: 'rejected',
387
- code: 'unscripted-action',
388
- fields: {}
389
- };
390
- }, request);
391
- }
379
+ async action(_authorization, request) {
380
+ return resolveScript(scripts.action, () => {
381
+ if (request.name.startsWith('conversation.'))
382
+ return conversationAction(request);
383
+ return { kind: 'rejected', code: 'unscripted-action', fields: {} };
384
+ }, request).then((answer) => {
385
+ if (answer.kind === 'action' && answer.at !== undefined)
386
+ note(answer.at.locator, answer.at);
387
+ return answer;
388
+ });
389
+ },
392
390
  };
393
391
  }
394
-
395
- //# sourceMappingURL=memory.js.map