@agentshouse/mdruntime 0.1.0-cc7bd7a53214e → 0.1.0-ccbb89b0ca151

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 (186) hide show
  1. package/README.md +24 -11
  2. package/dist/adapter.d.ts +187 -48
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js +1 -9
  5. package/dist/attached-model.d.ts +15 -0
  6. package/dist/attached-model.d.ts.map +1 -0
  7. package/dist/attached-model.js +64 -0
  8. package/dist/attempt.d.ts +16 -0
  9. package/dist/attempt.d.ts.map +1 -0
  10. package/dist/attempt.js +70 -0
  11. package/dist/binary.d.ts +18 -0
  12. package/dist/binary.d.ts.map +1 -0
  13. package/dist/binary.js +8 -0
  14. package/dist/bootstrap.d.ts +44 -7
  15. package/dist/bootstrap.d.ts.map +1 -1
  16. package/dist/bootstrap.js +223 -45
  17. package/dist/chain.d.ts +11 -0
  18. package/dist/chain.d.ts.map +1 -0
  19. package/dist/chain.js +64 -0
  20. package/dist/change-set.d.ts +9 -14
  21. package/dist/change-set.d.ts.map +1 -1
  22. package/dist/change-set.js +11 -56
  23. package/dist/change.d.ts +45 -0
  24. package/dist/change.d.ts.map +1 -1
  25. package/dist/change.js +34 -0
  26. package/dist/client.d.ts +37 -15
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +159 -29
  29. package/dist/collection.d.ts +9 -13
  30. package/dist/collection.d.ts.map +1 -1
  31. package/dist/collection.js +46 -56
  32. package/dist/compile.d.ts +16 -0
  33. package/dist/compile.d.ts.map +1 -0
  34. package/dist/compile.js +765 -0
  35. package/dist/connection.d.ts +64 -25
  36. package/dist/connection.d.ts.map +1 -1
  37. package/dist/connection.js +3926 -961
  38. package/dist/conversation.d.ts +54 -16
  39. package/dist/conversation.d.ts.map +1 -1
  40. package/dist/conversation.js +730 -243
  41. package/dist/digest.d.ts +7 -0
  42. package/dist/digest.d.ts.map +1 -0
  43. package/dist/digest.js +113 -0
  44. package/dist/durability.d.ts +5 -1
  45. package/dist/durability.d.ts.map +1 -1
  46. package/dist/durability.js +5 -0
  47. package/dist/entry.d.ts +19 -0
  48. package/dist/entry.d.ts.map +1 -0
  49. package/dist/entry.js +151 -0
  50. package/dist/expectation.d.ts +21 -0
  51. package/dist/expectation.d.ts.map +1 -0
  52. package/dist/expectation.js +70 -0
  53. package/dist/failure.d.ts +13 -0
  54. package/dist/failure.d.ts.map +1 -0
  55. package/dist/failure.js +19 -0
  56. package/dist/fence.d.ts +6 -0
  57. package/dist/fence.d.ts.map +1 -0
  58. package/dist/fence.js +10 -0
  59. package/dist/file.d.ts +2 -19
  60. package/dist/file.d.ts.map +1 -1
  61. package/dist/file.js +7 -122
  62. package/dist/fulltext.d.ts +27 -0
  63. package/dist/fulltext.d.ts.map +1 -0
  64. package/dist/fulltext.js +368 -0
  65. package/dist/host.d.ts +15 -2
  66. package/dist/host.d.ts.map +1 -1
  67. package/dist/host.js +136 -31
  68. package/dist/identity.d.ts +4 -0
  69. package/dist/identity.d.ts.map +1 -1
  70. package/dist/identity.js +16 -1
  71. package/dist/index.d.ts +19 -9
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +8 -0
  74. package/dist/live.d.ts +22 -0
  75. package/dist/live.d.ts.map +1 -0
  76. package/dist/live.js +124 -0
  77. package/dist/media.d.ts +8 -0
  78. package/dist/media.d.ts.map +1 -0
  79. package/dist/media.js +195 -0
  80. package/dist/memory.d.ts +22 -8
  81. package/dist/memory.d.ts.map +1 -1
  82. package/dist/memory.js +207 -47
  83. package/dist/messages.d.ts +28 -0
  84. package/dist/messages.d.ts.map +1 -0
  85. package/dist/messages.js +90 -0
  86. package/dist/model.d.ts +17 -14
  87. package/dist/model.d.ts.map +1 -1
  88. package/dist/model.js +16 -4
  89. package/dist/name.d.ts +4 -0
  90. package/dist/name.d.ts.map +1 -0
  91. package/dist/name.js +122 -0
  92. package/dist/observation.d.ts +19 -2
  93. package/dist/observation.d.ts.map +1 -1
  94. package/dist/observation.js +113 -12
  95. package/dist/open.d.ts +2 -0
  96. package/dist/open.d.ts.map +1 -0
  97. package/dist/open.js +1 -0
  98. package/dist/opened.d.ts +22 -0
  99. package/dist/opened.d.ts.map +1 -0
  100. package/dist/opened.js +107 -0
  101. package/dist/outcome.d.ts +73 -3
  102. package/dist/outcome.d.ts.map +1 -1
  103. package/dist/outcome.js +79 -1
  104. package/dist/overlay.d.ts +15 -5
  105. package/dist/overlay.d.ts.map +1 -1
  106. package/dist/overlay.js +136 -180
  107. package/dist/paths.d.ts +0 -1
  108. package/dist/paths.d.ts.map +1 -1
  109. package/dist/paths.js +0 -16
  110. package/dist/query.d.ts +71 -5
  111. package/dist/query.d.ts.map +1 -1
  112. package/dist/query.js +122 -40
  113. package/dist/reach.d.ts +17 -4
  114. package/dist/reach.d.ts.map +1 -1
  115. package/dist/reach.js +251 -81
  116. package/dist/react.d.ts +43 -0
  117. package/dist/react.d.ts.map +1 -0
  118. package/dist/react.js +54 -0
  119. package/dist/readiness.d.ts +64 -0
  120. package/dist/readiness.d.ts.map +1 -0
  121. package/dist/readiness.js +33 -0
  122. package/dist/reads.d.ts +11 -0
  123. package/dist/reads.d.ts.map +1 -0
  124. package/dist/reads.js +100 -0
  125. package/dist/recovery.d.ts +25 -0
  126. package/dist/recovery.d.ts.map +1 -0
  127. package/dist/recovery.js +198 -0
  128. package/dist/refresh.d.ts +19 -7
  129. package/dist/refresh.d.ts.map +1 -1
  130. package/dist/refresh.js +125 -53
  131. package/dist/replica.d.ts +59 -33
  132. package/dist/replica.d.ts.map +1 -1
  133. package/dist/replica.js +321 -156
  134. package/dist/room-draft.d.ts +41 -9
  135. package/dist/room-draft.d.ts.map +1 -1
  136. package/dist/room-draft.js +186 -37
  137. package/dist/rows.d.ts +39 -34
  138. package/dist/rows.d.ts.map +1 -1
  139. package/dist/rows.js +195 -81
  140. package/dist/save.d.ts +72 -6
  141. package/dist/save.d.ts.map +1 -1
  142. package/dist/save.js +889 -178
  143. package/dist/search.d.ts +41 -29
  144. package/dist/search.d.ts.map +1 -1
  145. package/dist/search.js +37 -105
  146. package/dist/seed.d.ts +16 -0
  147. package/dist/seed.d.ts.map +1 -0
  148. package/dist/seed.js +75 -0
  149. package/dist/shared.d.ts +16 -0
  150. package/dist/shared.d.ts.map +1 -0
  151. package/dist/shared.js +431 -0
  152. package/dist/status.d.ts +6 -2
  153. package/dist/status.d.ts.map +1 -1
  154. package/dist/status.js +0 -8
  155. package/dist/store.d.ts +119 -58
  156. package/dist/store.d.ts.map +1 -1
  157. package/dist/store.js +362 -344
  158. package/dist/stored.d.ts +152 -0
  159. package/dist/stored.d.ts.map +1 -0
  160. package/dist/stored.js +607 -0
  161. package/dist/tables.d.ts +352 -0
  162. package/dist/tables.d.ts.map +1 -0
  163. package/dist/tables.js +624 -0
  164. package/dist/turn.d.ts +9 -0
  165. package/dist/turn.d.ts.map +1 -0
  166. package/dist/turn.js +75 -0
  167. package/dist/validation.d.ts +30 -0
  168. package/dist/validation.d.ts.map +1 -0
  169. package/dist/validation.js +162 -0
  170. package/dist/windows.d.ts +22 -0
  171. package/dist/windows.d.ts.map +1 -0
  172. package/dist/windows.js +89 -0
  173. package/dist/wire.d.ts +174 -45
  174. package/dist/wire.d.ts.map +1 -1
  175. package/dist/wire.js +70 -46
  176. package/dist/words.d.ts +19 -0
  177. package/dist/words.d.ts.map +1 -0
  178. package/dist/words.js +150 -0
  179. package/package.json +33 -10
  180. package/AGENTS.md +0 -215
  181. package/dist/attachment.d.ts +0 -3
  182. package/dist/attachment.d.ts.map +0 -1
  183. package/dist/attachment.js +0 -8
  184. package/dist/read-side.d.ts +0 -18
  185. package/dist/read-side.d.ts.map +0 -1
  186. package/dist/read-side.js +0 -377
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ const COMPLETE_ROOMS = new Set(['complete', 'unadmitted']);
2
+ const SETTLED_ROOMS = new Set([...COMPLETE_ROOMS, 'refused']);
3
+ export function readinessOf(facts) {
4
+ const { established, coverage: held, ...reported } = facts;
5
+ const settledConversations = held.conversations === 'complete' || held.conversations === 'undeclared';
6
+ const complete = held.listed &&
7
+ settledConversations &&
8
+ held.rooms.every((room) => COMPLETE_ROOMS.has(room.state));
9
+ const settled = held.listed &&
10
+ settledConversations &&
11
+ held.rooms.every((room) => SETTLED_ROOMS.has(room.state));
12
+ const coverage = { ...held, complete };
13
+ const stored = facts.code === 'stored';
14
+ const ready = stored && complete;
15
+ const usable = stored && (ready || established);
16
+ const status = ready
17
+ ? 'ready'
18
+ : facts.space !== null || facts.installation.paused !== null
19
+ ? 'paused'
20
+ : settled && !complete
21
+ ? 'refused'
22
+ : facts.lost && !established
23
+ ? 'lost'
24
+ : 'preparing';
25
+ return {
26
+ ...reported,
27
+ coverage,
28
+ status,
29
+ ready,
30
+ usable,
31
+ durability: facts.persistence === 'granted' ? 'persistent' : 'best-effort',
32
+ };
33
+ }
@@ -0,0 +1,11 @@
1
+ import type { Adapter } from './adapter.js';
2
+ import type { Reads } from './bootstrap.js';
3
+ export type DoorReads = Reads & {
4
+ carried(locator: string): number;
5
+ finished(locator: string, turn: number): void;
6
+ opened(): void;
7
+ applied(): void;
8
+ lost(): void;
9
+ };
10
+ export declare function doorReads(adapter: Adapter, declaration: (locator: string) => unknown, generation: () => number): DoorReads;
11
+ //# sourceMappingURL=reads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAOR,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAC9B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AAkCF,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,EACzC,UAAU,EAAE,MAAM,MAAM,GACvB,SAAS,CA4FX"}
package/dist/reads.js ADDED
@@ -0,0 +1,100 @@
1
+ function declaredAs(declaration) {
2
+ if (declaration === null || typeof declaration !== 'object')
3
+ return declaration;
4
+ const { roomVersion: _version, ...declared } = declaration;
5
+ return declared;
6
+ }
7
+ function sameHeld(one, other) {
8
+ return one === other;
9
+ }
10
+ function failed(answer) {
11
+ return answer?.kind === 'transport-uncertainty';
12
+ }
13
+ function continues(answer) {
14
+ const page = answer;
15
+ return page?.kind === 'net-advancement' && page.pageToken !== undefined;
16
+ }
17
+ export function doorReads(adapter, declaration, generation) {
18
+ const reading = new Map();
19
+ const taken = new Map();
20
+ let carrying = false;
21
+ function joined(read, authorization, request, ask) {
22
+ const key = `${read} ${request.locator} ${request.pageToken ?? ''}`;
23
+ const { held, received, ...named } = request;
24
+ const asked = JSON.stringify([declaredAs(declaration(request.locator)), named]);
25
+ const asking = generation();
26
+ const current = reading.get(key);
27
+ if (current !== undefined &&
28
+ current.authorization === authorization &&
29
+ current.asked === asked &&
30
+ sameHeld(current.held, held) &&
31
+ current.received === received &&
32
+ (!current.settled || current.holder < asking)) {
33
+ if (current.settled && !current.continued)
34
+ reading.delete(key);
35
+ else
36
+ current.holder = Math.max(current.holder, asking);
37
+ if (current.from === asking)
38
+ return current.answer;
39
+ const again = () => joined(read, authorization, request, ask);
40
+ return current.answer.then((answer) => {
41
+ if (failed(answer))
42
+ return again();
43
+ taken.set(request.locator, (taken.get(request.locator) ?? 0) + 1);
44
+ return answer;
45
+ }, again);
46
+ }
47
+ const answer = ask();
48
+ const sent = {
49
+ locator: request.locator,
50
+ authorization,
51
+ asked,
52
+ held,
53
+ received,
54
+ answer,
55
+ from: asking,
56
+ holder: asking,
57
+ settled: false,
58
+ continued: false,
59
+ };
60
+ reading.set(key, sent);
61
+ const settled = (result, kept) => {
62
+ sent.settled = true;
63
+ sent.continued = kept && read === 'refresh' && continues(result);
64
+ if (reading.get(key) !== sent)
65
+ return;
66
+ const live = sent.holder === generation();
67
+ if (!kept || (live ? !sent.continued : !carrying))
68
+ reading.delete(key);
69
+ };
70
+ answer.then((result) => settled(result, !failed(result)), () => settled(null, false));
71
+ return answer;
72
+ }
73
+ return {
74
+ bootstrap: (authorization, request) => joined('bootstrap', authorization, request, () => adapter.bootstrap(authorization, request)),
75
+ refresh: (authorization, request) => joined('refresh', authorization, request, () => adapter.refresh(authorization, request)),
76
+ reached: (locator, roomVersion, target) => adapter.reached(locator, roomVersion, target),
77
+ carried: (locator) => taken.get(locator) ?? 0,
78
+ finished(locator, turn) {
79
+ for (const [key, held] of reading) {
80
+ if (held.locator !== locator || !held.settled || held.holder !== turn)
81
+ continue;
82
+ if (turn === generation() || !carrying)
83
+ reading.delete(key);
84
+ }
85
+ },
86
+ opened() {
87
+ carrying = true;
88
+ },
89
+ applied() {
90
+ carrying = false;
91
+ for (const [key, held] of reading) {
92
+ if (held.settled && held.holder !== generation())
93
+ reading.delete(key);
94
+ }
95
+ },
96
+ lost() {
97
+ reading.clear();
98
+ },
99
+ };
100
+ }
@@ -0,0 +1,25 @@
1
+ export type Attempted = 'done' | 'again' | {
2
+ readonly at: number;
3
+ };
4
+ export type Attempt = (signal: AbortSignal) => Promise<Attempted>;
5
+ export type AttemptOptions = {
6
+ readonly at?: number;
7
+ readonly again?: boolean;
8
+ };
9
+ export type RecoveryOptions = {
10
+ readonly firstMs?: number;
11
+ readonly maxMs?: number;
12
+ readonly attempts?: number;
13
+ readonly inFlight?: number;
14
+ };
15
+ export type Recovery = {
16
+ attempt(intent: string, run: Attempt, options?: AttemptOptions): Promise<boolean>;
17
+ pending(intent: string): boolean;
18
+ resume(): void;
19
+ cancel(intent: string): void;
20
+ scope(inFlight?: number): Recovery;
21
+ retire(): Promise<void>;
22
+ };
23
+ export declare function retryDelay(tries: number, firstMs?: number, maxMs?: number): number;
24
+ export declare function createRecovery(options?: RecoveryOptions): Recovery;
25
+ //# sourceMappingURL=recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB,CAAC;AAsBF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,SAAW,EAAE,KAAK,SAAS,GAAG,MAAM,CAGpF;AAwKD,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAStE"}
@@ -0,0 +1,198 @@
1
+ // A first retry waits about a second, so a passing failure clears before the next attempt.
2
+ const FIRST_MS = 1_000;
3
+ // Waits stop doubling at half a minute, so work resumes soon after a long failure ends.
4
+ const MAX_MS = 30_000;
5
+ const ATTEMPTS = 8;
6
+ export function retryDelay(tries, firstMs = FIRST_MS, maxMs = MAX_MS) {
7
+ const longest = Math.min(maxMs, firstMs * 2 ** tries);
8
+ return longest / 2 + (Math.random() * longest) / 2;
9
+ }
10
+ function owner(backoff, inFlight, release = () => { }) {
11
+ const intents = new Map();
12
+ const children = new Set();
13
+ const running = new Set();
14
+ const queued = [];
15
+ let free = inFlight;
16
+ let retired = false;
17
+ function finish(key, intent, done) {
18
+ if (intents.get(key) === intent)
19
+ intents.delete(key);
20
+ if (intent.timer !== null)
21
+ clearTimeout(intent.timer);
22
+ intent.timer = null;
23
+ intent.end(done);
24
+ }
25
+ function wait(key, intent, at, guided) {
26
+ if (intent.timer !== null)
27
+ clearTimeout(intent.timer);
28
+ intent.due = at;
29
+ intent.guided = guided;
30
+ intent.timer = setTimeout(() => {
31
+ intent.timer = null;
32
+ launch(key, intent);
33
+ }, Math.max(0, at - Date.now()));
34
+ }
35
+ function launch(key, intent) {
36
+ intent.due = null;
37
+ intent.guided = false;
38
+ const controller = new AbortController();
39
+ intent.controller = controller;
40
+ const run = start(key, intent, controller);
41
+ running.add(run);
42
+ void run.finally(() => running.delete(run));
43
+ }
44
+ async function start(key, intent, controller) {
45
+ while (free === 0)
46
+ await new Promise((admit) => queued.push(admit));
47
+ if (controller.signal.aborted) {
48
+ queued.shift()?.();
49
+ return;
50
+ }
51
+ free -= 1;
52
+ const abandoned = new Promise((resolve) => {
53
+ controller.signal.addEventListener('abort', () => resolve(null), { once: true });
54
+ });
55
+ let result;
56
+ try {
57
+ result = await Promise.race([intent.run(controller.signal), abandoned]);
58
+ }
59
+ catch {
60
+ result = 'again';
61
+ }
62
+ finally {
63
+ free += 1;
64
+ queued.shift()?.();
65
+ }
66
+ if (result === null || controller.signal.aborted || intents.get(key) !== intent)
67
+ return;
68
+ intent.controller = null;
69
+ const again = intent.again;
70
+ intent.again = null;
71
+ if (result === 'done') {
72
+ intent.tries = 0;
73
+ if (again === null)
74
+ finish(key, intent, true);
75
+ else if (again === 'now')
76
+ launch(key, intent);
77
+ else
78
+ wait(key, intent, again, true);
79
+ return;
80
+ }
81
+ intent.tries += 1;
82
+ if (intent.tries >= backoff.attempts) {
83
+ finish(key, intent, false);
84
+ return;
85
+ }
86
+ if (result === 'again') {
87
+ // The next attempt waits the doubling backoff, up to its maximum.
88
+ const delay = retryDelay(intent.tries - 1, backoff.firstMs, backoff.maxMs);
89
+ wait(key, intent, Date.now() + delay, false);
90
+ }
91
+ else
92
+ wait(key, intent, result.at, true);
93
+ }
94
+ const recovery = {
95
+ attempt(key, run, options = {}) {
96
+ if (retired)
97
+ return Promise.resolve(false);
98
+ const held = intents.get(key);
99
+ if (held !== undefined) {
100
+ held.run = run;
101
+ if (held.controller !== null) {
102
+ const at = options.at;
103
+ held.again =
104
+ at === undefined || held.again === 'now'
105
+ ? 'now'
106
+ : Math.min(at, held.again ?? Number.POSITIVE_INFINITY);
107
+ }
108
+ else if (held.due !== null && held.due <= Date.now()) {
109
+ if (held.timer !== null)
110
+ clearTimeout(held.timer);
111
+ held.timer = null;
112
+ launch(key, held);
113
+ }
114
+ else if (options.at !== undefined && (held.due === null || options.at < held.due)) {
115
+ wait(key, held, options.at, true);
116
+ }
117
+ return held.ended;
118
+ }
119
+ let end = () => { };
120
+ const ended = new Promise((resolve) => {
121
+ end = resolve;
122
+ });
123
+ const intent = {
124
+ run,
125
+ tries: 0,
126
+ timer: null,
127
+ due: null,
128
+ guided: false,
129
+ controller: null,
130
+ again: null,
131
+ ended,
132
+ end,
133
+ };
134
+ intents.set(key, intent);
135
+ if (options.at !== undefined)
136
+ wait(key, intent, options.at, true);
137
+ else if (options.again === true) {
138
+ intent.tries = 1;
139
+ wait(key, intent, Date.now() + retryDelay(0, backoff.firstMs, backoff.maxMs), false);
140
+ }
141
+ else
142
+ launch(key, intent);
143
+ return ended;
144
+ },
145
+ pending(key) {
146
+ const intent = intents.get(key);
147
+ return intent !== undefined && intent.controller === null;
148
+ },
149
+ resume() {
150
+ if (retired)
151
+ return;
152
+ for (const [key, intent] of [...intents]) {
153
+ if (intent.guided && intent.due !== null && intent.due > Date.now())
154
+ continue;
155
+ if (intent.timer !== null)
156
+ clearTimeout(intent.timer);
157
+ intent.timer = null;
158
+ intent.controller?.abort();
159
+ intent.again = null;
160
+ intent.tries = 0;
161
+ launch(key, intent);
162
+ }
163
+ },
164
+ cancel(key) {
165
+ const intent = intents.get(key);
166
+ if (intent === undefined)
167
+ return;
168
+ intent.controller?.abort();
169
+ finish(key, intent, false);
170
+ },
171
+ scope(bound = Infinity) {
172
+ const child = owner(backoff, bound, () => children.delete(child));
173
+ if (retired)
174
+ void child.retire();
175
+ else
176
+ children.add(child);
177
+ return child;
178
+ },
179
+ async retire() {
180
+ retired = true;
181
+ release();
182
+ for (const [key, intent] of [...intents]) {
183
+ intent.controller?.abort();
184
+ finish(key, intent, false);
185
+ }
186
+ await Promise.all([...children].map((child) => child.retire()));
187
+ await Promise.all(running);
188
+ },
189
+ };
190
+ return recovery;
191
+ }
192
+ export function createRecovery(options = {}) {
193
+ return owner({
194
+ firstMs: options.firstMs ?? FIRST_MS,
195
+ maxMs: options.maxMs ?? MAX_MS,
196
+ attempts: options.attempts ?? ATTEMPTS,
197
+ }, options.inFlight ?? Infinity);
198
+ }
package/dist/refresh.d.ts CHANGED
@@ -1,13 +1,25 @@
1
- import type { Adapter, AdapterFailure, Authorization, RetryableRefusal } from './adapter.js';
2
- import { type ConfirmedLayer } from './replica.js';
3
- import { type Refused, type Unconfirmed } from './transfer.js';
4
- export type RefreshOutcome = {
1
+ import type { AdapterFailure, Authorization, RefreshPage, RetryableRefusal } from './adapter.js';
2
+ import type { Reads, Remodel } from './bootstrap.js';
3
+ import type { ReplicaRecord } from './replica.js';
4
+ import type { RefreshedPage } from './store.js';
5
+ import type { HeldEntry, StoredEntry } from './tables.js';
6
+ import { type Unconfirmed } from './transfer.js';
7
+ export type Advancement = {
5
8
  kind: 'still-current';
6
9
  } | {
7
10
  kind: 'advanced';
8
- confirmed: ConfirmedLayer;
11
+ record: ReplicaRecord;
12
+ changed: ReadonlySet<string>;
9
13
  } | {
10
14
  kind: 'beyond-horizon';
11
- } | RetryableRefusal | Unconfirmed | Refused | AdapterFailure;
12
- export declare function refreshRoom(adapter: Adapter, authorization: Authorization, confirmed: ConfirmedLayer, continuing: () => boolean, minPosition: string | undefined): Promise<RefreshOutcome>;
15
+ } | RetryableRefusal | Unconfirmed | AdapterFailure;
16
+ export type Refreshing = {
17
+ turn(): Promise<void>;
18
+ prior(paths: readonly string[]): Promise<ReadonlyMap<string, HeldEntry>>;
19
+ stage(page: RefreshedPage): Promise<boolean>;
20
+ };
21
+ type PageContent = Pick<RefreshPage, 'documents' | 'revisions' | 'fileIds' | 'changes' | 'binaryFiles'>;
22
+ export declare function pageEntries(page: PageContent, removals: readonly string[], roomVersion: string, prior: (paths: readonly string[]) => Promise<ReadonlyMap<string, HeldEntry>>): Promise<StoredEntry[]>;
23
+ export declare function advancement(adapter: Reads, authorization: Authorization, held: ReplicaRecord, remodel: Remodel, continuing: () => boolean, staging: Refreshing): Promise<Advancement>;
24
+ export {};
13
25
  //# sourceMappingURL=refresh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,aAAa,EAGb,gBAAgB,EAEjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAe,KAAK,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5E,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,gBAAgB,GAChB,WAAW,GACX,OAAO,GACP,cAAc,CAAC;AAEnB,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,cAAc,EACzB,UAAU,EAAE,MAAM,OAAO,EACzB,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,OAAO,CAAC,cAAc,CAAC,CA0EzB"}
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACjG,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAG9D,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,gBAAgB,GAChB,WAAW,GACX,cAAc,CAAC;AAEnB,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACzE,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;AASF,KAAK,WAAW,GAAG,IAAI,CACrB,WAAW,EACX,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAClE,CAAC;AAmFF,wBAAsB,WAAW,CAC/B,IAAI,EAAE,WAAW,EACjB,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,GAC3E,OAAO,CAAC,WAAW,EAAE,CAAC,CAKxB;AAeD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,KAAK,EACd,aAAa,EAAE,aAAa,EAC5B,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,OAAO,EACzB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,WAAW,CAAC,CA8CtB"}
package/dist/refresh.js CHANGED
@@ -1,60 +1,133 @@
1
- import { declaredAttachments } from './attachment.js';
2
- import { readStaged } from './replica.js';
3
1
  import { unconfirmed } from './transfer.js';
4
- export async function refreshRoom(adapter, authorization, confirmed, continuing, minPosition) {
5
- const locator = confirmed.record.locator;
6
- const fromRoomVersion = confirmed.record.roomVersion;
2
+ import { ROW_WEIGHT, stepped, yielded } from './turn.js';
3
+ function* listing(page, removals) {
4
+ const removed = new Set();
5
+ for (const path of removals) {
6
+ removed.add(path);
7
+ yield ROW_WEIGHT;
8
+ }
9
+ const documents = [];
10
+ const binaries = [];
11
+ const asked = [];
12
+ const written = new Set();
13
+ for (const [kept, named] of [
14
+ [documents, page.documents],
15
+ [binaries, page.binaryFiles],
16
+ ]) {
17
+ for (const path of Object.keys(named)) {
18
+ yield ROW_WEIGHT;
19
+ if (removed.has(path))
20
+ continue;
21
+ kept.push(path);
22
+ written.add(path);
23
+ if (page.revisions[path] === undefined)
24
+ asked.push(path);
25
+ }
26
+ }
27
+ const others = [];
28
+ const seen = new Set();
29
+ for (const named of [page.revisions, page.fileIds ?? {}, page.changes]) {
30
+ for (const path of Object.keys(named)) {
31
+ yield ROW_WEIGHT;
32
+ if (seen.has(path))
33
+ continue;
34
+ seen.add(path);
35
+ if (!written.has(path) && !removed.has(path))
36
+ others.push(path);
37
+ }
38
+ }
39
+ return { documents, binaries, others, asked: [...asked, ...others] };
40
+ }
41
+ function* entering(page, roomVersion, listed, prior) {
42
+ const entries = [];
43
+ for (const path of listed.documents) {
44
+ yield ROW_WEIGHT;
45
+ entries.push({
46
+ path,
47
+ content: page.documents[path],
48
+ binary: null,
49
+ revision: page.revisions[path] ?? prior.get(path)?.revision ?? null,
50
+ fileId: page.fileIds?.[path] ?? null,
51
+ change: page.changes[path] ?? null,
52
+ written: roomVersion,
53
+ });
54
+ }
55
+ for (const path of listed.binaries) {
56
+ yield ROW_WEIGHT;
57
+ entries.push({
58
+ path,
59
+ content: null,
60
+ binary: { state: 'accepted', ...page.binaryFiles[path] },
61
+ revision: page.revisions[path] ?? prior.get(path)?.revision ?? null,
62
+ fileId: page.fileIds?.[path] ?? null,
63
+ change: page.changes[path] ?? null,
64
+ written: null,
65
+ });
66
+ }
67
+ for (const path of listed.others) {
68
+ yield ROW_WEIGHT;
69
+ const held = prior.get(path);
70
+ if (held === undefined)
71
+ continue;
72
+ const { type: _type, ...kept } = held;
73
+ entries.push({
74
+ ...kept,
75
+ revision: page.revisions[path] ?? held.revision,
76
+ fileId: page.fileIds?.[path] ?? held.fileId,
77
+ change: page.changes[path] ?? held.change,
78
+ });
79
+ }
80
+ return entries;
81
+ }
82
+ export async function pageEntries(page, removals, roomVersion, prior) {
83
+ await yielded();
84
+ const listed = await stepped(listing(page, removals));
85
+ const held = listed.asked.length === 0 ? new Map() : await prior(listed.asked);
86
+ return stepped(entering(page, roomVersion, listed, held));
87
+ }
88
+ async function pageOf(page, roomVersion, staging) {
89
+ return {
90
+ entries: await pageEntries(page, page.removals, roomVersion, (paths) => staging.prior(paths)),
91
+ removals: page.removals,
92
+ folders: page.folders ?? [],
93
+ folderRemovals: page.folderRemovals ?? [],
94
+ };
95
+ }
96
+ export async function advancement(adapter, authorization, held, remodel, continuing, staging) {
97
+ const locator = held.locator;
98
+ const fromRoomVersion = held.roomVersion;
99
+ await staging.turn();
100
+ if (!continuing())
101
+ return unconfirmed;
7
102
  const first = await adapter.refresh(authorization, {
8
103
  locator,
9
- selection: confirmed.record.replica.selection,
104
+ selection: held.replica.selection,
10
105
  fromRoomVersion,
11
- ...(minPosition === undefined ? {} : { minPosition }),
12
106
  });
13
107
  if (first.kind !== 'net-advancement')
14
108
  return first;
15
109
  const roomVersion = first.roomVersion;
16
- const documents = { ...confirmed.record.documents };
17
- const revisions = { ...confirmed.record.revisions };
18
- const changes = { ...confirmed.record.changes };
19
- const written = { ...confirmed.record.written };
20
- const binaryTargets = new Set(confirmed.record.binaryTargets);
21
- const attachments = [];
22
- const stage = (page) => {
23
- if (page.attachments !== undefined)
24
- attachments.push(page.attachments);
25
- Object.assign(documents, page.documents);
26
- Object.assign(revisions, page.revisions);
27
- for (const path of Object.keys(page.documents)) {
28
- binaryTargets.delete(path);
29
- delete changes[path];
30
- written[path] = roomVersion;
31
- }
32
- for (const target of page.binaryTargets) {
33
- delete documents[target];
34
- delete revisions[target];
35
- delete changes[target];
36
- delete written[target];
37
- binaryTargets.add(target);
38
- }
39
- Object.assign(changes, page.changes);
40
- for (const path of page.removals) {
41
- delete documents[path];
42
- delete revisions[path];
43
- delete changes[path];
44
- delete written[path];
45
- binaryTargets.delete(path);
46
- }
110
+ const models = remodel(first.models, { collection: held.model });
111
+ const changed = new Set();
112
+ const staged = async (page) => {
113
+ const read = await pageOf(page, roomVersion, staging);
114
+ for (const { path } of read.entries)
115
+ changed.add(path);
116
+ for (const path of read.removals)
117
+ changed.add(path);
118
+ return staging.stage(read);
47
119
  };
48
- stage(first);
120
+ if (!(await staged(first)))
121
+ return unconfirmed;
49
122
  let pageToken = first.pageToken;
50
123
  while (pageToken !== undefined) {
124
+ await staging.turn();
51
125
  if (!continuing())
52
126
  return unconfirmed;
53
127
  const page = await adapter.refresh(authorization, {
54
128
  locator,
55
- selection: confirmed.record.replica.selection,
129
+ selection: held.replica.selection,
56
130
  fromRoomVersion,
57
- ...(minPosition === undefined ? {} : { minPosition }),
58
131
  pageToken,
59
132
  });
60
133
  if (page.kind === 'still-current' || page.kind === 'beyond-horizon')
@@ -63,18 +136,17 @@ export async function refreshRoom(adapter, authorization, confirmed, continuing,
63
136
  return page;
64
137
  if (page.roomVersion !== roomVersion)
65
138
  return unconfirmed;
66
- stage(page);
139
+ if (!(await staged(page)))
140
+ return unconfirmed;
67
141
  pageToken = page.pageToken;
68
142
  }
69
- const staged = readStaged({
70
- ...confirmed.record,
71
- roomVersion,
72
- documents,
73
- binaryTargets: [...binaryTargets].sort(),
74
- revisions,
75
- changes,
76
- written,
77
- attachments: attachments.length === 0 ? confirmed.record.attachments : declaredAttachments(attachments),
78
- }, confirmed);
79
- return staged.kind === 'staged' ? { kind: 'advanced', confirmed: staged.confirmed } : staged;
143
+ return {
144
+ kind: 'advanced',
145
+ record: {
146
+ ...held,
147
+ model: models.collection,
148
+ roomVersion,
149
+ },
150
+ changed,
151
+ };
80
152
  }