@optimystic/db-core 0.21.0 → 0.24.0

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 (185) hide show
  1. package/README.md +336 -336
  2. package/dist/src/btree/btree.d.ts +2 -1
  3. package/dist/src/btree/btree.d.ts.map +1 -1
  4. package/dist/src/btree/btree.js +1 -1
  5. package/dist/src/btree/btree.js.map +1 -1
  6. package/dist/src/chain/chain.d.ts +1 -1
  7. package/dist/src/chain/chain.d.ts.map +1 -1
  8. package/dist/src/chain/chain.js +1 -1
  9. package/dist/src/chain/chain.js.map +1 -1
  10. package/dist/src/cluster/structs.d.ts +39 -1
  11. package/dist/src/cluster/structs.d.ts.map +1 -1
  12. package/dist/src/cluster/structs.js +24 -0
  13. package/dist/src/cluster/structs.js.map +1 -1
  14. package/dist/src/collection/collection.d.ts +20 -1
  15. package/dist/src/collection/collection.d.ts.map +1 -1
  16. package/dist/src/collection/collection.js +31 -4
  17. package/dist/src/collection/collection.js.map +1 -1
  18. package/dist/src/collections/diary/diary.d.ts.map +1 -1
  19. package/dist/src/collections/diary/diary.js +2 -1
  20. package/dist/src/collections/diary/diary.js.map +1 -1
  21. package/dist/src/collections/diary/struct.js +1 -1
  22. package/dist/src/collections/diary/struct.js.map +1 -1
  23. package/dist/src/collections/tree/collection-trunk.js +1 -1
  24. package/dist/src/collections/tree/collection-trunk.js.map +1 -1
  25. package/dist/src/collections/tree/struct.d.ts +1 -1
  26. package/dist/src/collections/tree/struct.d.ts.map +1 -1
  27. package/dist/src/collections/tree/struct.js +2 -1
  28. package/dist/src/collections/tree/struct.js.map +1 -1
  29. package/dist/src/collections/tree/tree.d.ts +5 -0
  30. package/dist/src/collections/tree/tree.d.ts.map +1 -1
  31. package/dist/src/collections/tree/tree.js +7 -0
  32. package/dist/src/collections/tree/tree.js.map +1 -1
  33. package/dist/src/log/log.d.ts +1 -1
  34. package/dist/src/log/log.d.ts.map +1 -1
  35. package/dist/src/log/log.js +2 -2
  36. package/dist/src/log/log.js.map +1 -1
  37. package/dist/src/network/i-peer-network.d.ts +16 -0
  38. package/dist/src/network/i-peer-network.d.ts.map +1 -1
  39. package/dist/src/network/struct.d.ts +39 -2
  40. package/dist/src/network/struct.d.ts.map +1 -1
  41. package/dist/src/network/struct.js +18 -0
  42. package/dist/src/network/struct.js.map +1 -1
  43. package/dist/src/testing/test-transactor.d.ts +95 -8
  44. package/dist/src/testing/test-transactor.d.ts.map +1 -1
  45. package/dist/src/testing/test-transactor.js +133 -12
  46. package/dist/src/testing/test-transactor.js.map +1 -1
  47. package/dist/src/transaction/coordinator.d.ts.map +1 -1
  48. package/dist/src/transaction/coordinator.js +2 -1
  49. package/dist/src/transaction/coordinator.js.map +1 -1
  50. package/dist/src/transaction/transaction.d.ts +1 -1
  51. package/dist/src/transaction/transaction.js +1 -1
  52. package/dist/src/transactor/network-transactor.d.ts.map +1 -1
  53. package/dist/src/transactor/network-transactor.js +57 -18
  54. package/dist/src/transactor/network-transactor.js.map +1 -1
  55. package/dist/src/transactor/transactor-source.d.ts.map +1 -1
  56. package/dist/src/transactor/transactor-source.js +25 -2
  57. package/dist/src/transactor/transactor-source.js.map +1 -1
  58. package/dist/src/transform/cache-source.js +1 -1
  59. package/dist/src/transform/cache-source.js.map +1 -1
  60. package/dist/src/transform/helpers.d.ts +6 -1
  61. package/dist/src/transform/helpers.d.ts.map +1 -1
  62. package/dist/src/transform/helpers.js +7 -6
  63. package/dist/src/transform/helpers.js.map +1 -1
  64. package/dist/src/transform/tracker.d.ts.map +1 -1
  65. package/dist/src/transform/tracker.js +2 -1
  66. package/dist/src/transform/tracker.js.map +1 -1
  67. package/package.json +1 -1
  68. package/src/btree/btree.ts +2 -1
  69. package/src/chain/chain.ts +2 -1
  70. package/src/cluster/membership.ts +85 -85
  71. package/src/cluster/structs.ts +43 -4
  72. package/src/cohort-topic/addressing.ts +120 -120
  73. package/src/cohort-topic/antidos/bootstrap-evidence-envelope.ts +253 -253
  74. package/src/cohort-topic/antidos/bootstrap-evidence.ts +106 -106
  75. package/src/cohort-topic/antidos/index.ts +5 -5
  76. package/src/cohort-topic/antidos/rate-limiter.ts +210 -210
  77. package/src/cohort-topic/antidos/replay-guard.ts +146 -146
  78. package/src/cohort-topic/antidos/topic-budget.ts +160 -160
  79. package/src/cohort-topic/antiflood/index.ts +2 -2
  80. package/src/cohort-topic/antiflood/invariants.ts +108 -108
  81. package/src/cohort-topic/antiflood/jitter.ts +117 -117
  82. package/src/cohort-topic/coldstart.ts +237 -237
  83. package/src/cohort-topic/dmax.ts +88 -88
  84. package/src/cohort-topic/gossip/bus.ts +254 -254
  85. package/src/cohort-topic/gossip/index.ts +3 -3
  86. package/src/cohort-topic/gossip/records.ts +45 -45
  87. package/src/cohort-topic/gossip/view.ts +91 -91
  88. package/src/cohort-topic/index.ts +20 -20
  89. package/src/cohort-topic/load/barometer.ts +134 -134
  90. package/src/cohort-topic/load/index.ts +1 -1
  91. package/src/cohort-topic/member-engine.ts +430 -430
  92. package/src/cohort-topic/membership/index.ts +3 -3
  93. package/src/cohort-topic/membership/publisher.ts +163 -163
  94. package/src/cohort-topic/membership/source.ts +41 -41
  95. package/src/cohort-topic/membership/verifier.ts +461 -461
  96. package/src/cohort-topic/ports.ts +157 -157
  97. package/src/cohort-topic/promotion.ts +405 -405
  98. package/src/cohort-topic/registration/bytes.ts +37 -37
  99. package/src/cohort-topic/registration/handoff.ts +154 -154
  100. package/src/cohort-topic/registration/index.ts +6 -6
  101. package/src/cohort-topic/registration/renewal.ts +495 -495
  102. package/src/cohort-topic/registration/sharding.ts +61 -61
  103. package/src/cohort-topic/registration/store.ts +81 -81
  104. package/src/cohort-topic/registration/types.ts +91 -91
  105. package/src/cohort-topic/ring-hash.ts +50 -50
  106. package/src/cohort-topic/service.ts +416 -416
  107. package/src/cohort-topic/sig/index.ts +2 -2
  108. package/src/cohort-topic/sig/payloads.ts +59 -59
  109. package/src/cohort-topic/sig/threshold.ts +64 -64
  110. package/src/cohort-topic/tiers.ts +74 -74
  111. package/src/cohort-topic/traffic.ts +233 -233
  112. package/src/cohort-topic/walk.ts +326 -326
  113. package/src/cohort-topic/willingness.ts +237 -237
  114. package/src/cohort-topic/wire/codec.ts +216 -216
  115. package/src/cohort-topic/wire/index.ts +18 -18
  116. package/src/cohort-topic/wire/payloads.ts +126 -126
  117. package/src/cohort-topic/wire/primitives.ts +188 -188
  118. package/src/cohort-topic/wire/types.ts +475 -475
  119. package/src/cohort-topic/wire/validate.ts +512 -512
  120. package/src/collection/collection-type-registry.ts +37 -37
  121. package/src/collection/collection.ts +32 -4
  122. package/src/collections/diary/diary.ts +68 -67
  123. package/src/collections/diary/struct.ts +1 -1
  124. package/src/collections/tree/collection-trunk.ts +1 -1
  125. package/src/collections/tree/readme.md +4 -0
  126. package/src/collections/tree/struct.ts +3 -1
  127. package/src/collections/tree/tree.ts +320 -312
  128. package/src/log/log.ts +2 -2
  129. package/src/matchmaking/capability-filter.ts +45 -45
  130. package/src/matchmaking/config.ts +98 -98
  131. package/src/matchmaking/index.ts +21 -21
  132. package/src/matchmaking/multi-cohort-seeker.ts +234 -234
  133. package/src/matchmaking/provider.ts +123 -123
  134. package/src/matchmaking/query-eval.ts +105 -105
  135. package/src/matchmaking/seeker-walk.ts +127 -127
  136. package/src/matchmaking/seeker.ts +86 -86
  137. package/src/matchmaking/topic-anchor.ts +90 -90
  138. package/src/matchmaking/voting-quorum.ts +394 -394
  139. package/src/matchmaking/wire.ts +603 -603
  140. package/src/network/i-peer-network.ts +17 -0
  141. package/src/network/stale-failure.ts +43 -43
  142. package/src/network/struct.ts +41 -2
  143. package/src/network/types.ts +37 -37
  144. package/src/reactivity/backfill.ts +220 -220
  145. package/src/reactivity/backpressure.ts +191 -191
  146. package/src/reactivity/checkpoint.ts +308 -308
  147. package/src/reactivity/config.ts +172 -172
  148. package/src/reactivity/dedupe.ts +132 -132
  149. package/src/reactivity/forwarder.ts +87 -87
  150. package/src/reactivity/index.ts +34 -34
  151. package/src/reactivity/notification.ts +123 -123
  152. package/src/reactivity/policy.ts +79 -79
  153. package/src/reactivity/push-state.ts +310 -310
  154. package/src/reactivity/recover.ts +153 -153
  155. package/src/reactivity/replay-buffer.ts +141 -141
  156. package/src/reactivity/resume.ts +549 -549
  157. package/src/reactivity/rotation.ts +415 -415
  158. package/src/reactivity/subscriber.ts +132 -132
  159. package/src/reactivity/subscription.ts +66 -66
  160. package/src/reactivity/topic-anchor.ts +71 -71
  161. package/src/reactivity/verify.ts +73 -73
  162. package/src/reactivity/wire-validate.ts +13 -13
  163. package/src/reactivity/wire.ts +224 -224
  164. package/src/testing/async-wait.ts +65 -65
  165. package/src/testing/index.ts +2 -2
  166. package/src/testing/test-transactor.ts +638 -489
  167. package/src/transaction/coordinator.ts +2 -1
  168. package/src/transaction/errors.ts +91 -91
  169. package/src/transaction/operations-hash.ts +196 -196
  170. package/src/transaction/read-dependency-collector.ts +78 -78
  171. package/src/transaction/transaction.ts +1 -1
  172. package/src/transactor/change-notifier.ts +80 -80
  173. package/src/transactor/index.ts +5 -5
  174. package/src/transactor/network-transactor.ts +58 -19
  175. package/src/transactor/transactor-source.ts +25 -2
  176. package/src/transform/atomic-proxy.ts +92 -92
  177. package/src/transform/cache-source.ts +1 -1
  178. package/src/transform/helpers.ts +159 -158
  179. package/src/transform/tracker.ts +2 -1
  180. package/src/utility/backoff.ts +95 -95
  181. package/src/utility/batch-coordinator.ts +191 -191
  182. package/dist/src/transaction/context.d.ts +0 -60
  183. package/dist/src/transaction/context.d.ts.map +0 -1
  184. package/dist/src/transaction/context.js +0 -91
  185. package/dist/src/transaction/context.js.map +0 -1
@@ -1,37 +1,37 @@
1
- import type { BlockType } from "../blocks/index.js";
2
- import type { ITransactor } from "../transactor/index.js";
3
- import type { CollectionId, ICollection } from "./struct.js";
4
-
5
- export interface CollectionTypeDescriptor {
6
- /** The block type used for this collection's header block (e.g. "DIH", "TRE") */
7
- blockType: BlockType;
8
- /** Human-readable name (e.g. "Diary", "Tree") */
9
- name: string;
10
- /** Optional factory to open a collection with default settings, bringing it into existence
11
- * when nothing has ever been committed under the id (see {@link Collection.createOrOpen}).
12
- * Not all types support this (e.g. Tree requires keyFromEntry/compare). */
13
- createOrOpen?: (transactor: ITransactor, id: CollectionId) => Promise<ICollection<any>>;
14
- }
15
-
16
- const collectionTypes = new Map<BlockType, CollectionTypeDescriptor>();
17
-
18
- /** Register a collection type by its header block type. Throws if already registered. */
19
- export function registerCollectionType(descriptor: CollectionTypeDescriptor): void {
20
- if (collectionTypes.has(descriptor.blockType)) {
21
- throw new Error(
22
- `Collection type ${descriptor.blockType} (${descriptor.name}) already registered`
23
- + ` (${collectionTypes.get(descriptor.blockType)!.name})`
24
- );
25
- }
26
- collectionTypes.set(descriptor.blockType, descriptor);
27
- }
28
-
29
- /** Look up a collection type descriptor by its header block type. */
30
- export function getCollectionType(blockType: BlockType): CollectionTypeDescriptor | undefined {
31
- return collectionTypes.get(blockType);
32
- }
33
-
34
- /** Returns all registered collection type descriptors. */
35
- export function getCollectionTypes(): ReadonlyMap<BlockType, CollectionTypeDescriptor> {
36
- return collectionTypes;
37
- }
1
+ import type { BlockType } from "../blocks/index.js";
2
+ import type { ITransactor } from "../transactor/index.js";
3
+ import type { CollectionId, ICollection } from "./struct.js";
4
+
5
+ export interface CollectionTypeDescriptor {
6
+ /** The block type used for this collection's header block (e.g. "DIH", "TRE") */
7
+ blockType: BlockType;
8
+ /** Human-readable name (e.g. "Diary", "Tree") */
9
+ name: string;
10
+ /** Optional factory to open a collection with default settings, bringing it into existence
11
+ * when nothing has ever been committed under the id (see {@link Collection.createOrOpen}).
12
+ * Not all types support this (e.g. Tree requires keyFromEntry/compare). */
13
+ createOrOpen?: (transactor: ITransactor, id: CollectionId) => Promise<ICollection<any>>;
14
+ }
15
+
16
+ const collectionTypes = new Map<BlockType, CollectionTypeDescriptor>();
17
+
18
+ /** Register a collection type by its header block type. Throws if already registered. */
19
+ export function registerCollectionType(descriptor: CollectionTypeDescriptor): void {
20
+ if (collectionTypes.has(descriptor.blockType)) {
21
+ throw new Error(
22
+ `Collection type ${descriptor.blockType} (${descriptor.name}) already registered`
23
+ + ` (${collectionTypes.get(descriptor.blockType)!.name})`
24
+ );
25
+ }
26
+ collectionTypes.set(descriptor.blockType, descriptor);
27
+ }
28
+
29
+ /** Look up a collection type descriptor by its header block type. */
30
+ export function getCollectionType(blockType: BlockType): CollectionTypeDescriptor | undefined {
31
+ return collectionTypes.get(blockType);
32
+ }
33
+
34
+ /** Returns all registered collection type descriptors. */
35
+ export function getCollectionTypes(): ReadonlyMap<BlockType, CollectionTypeDescriptor> {
36
+ return collectionTypes;
37
+ }
@@ -1,8 +1,13 @@
1
1
  import type { IBlock, Action, ActionType, ActionHandler, BlockId, ITransactor, BlockStore, Transforms, ActionId } from "../index.js";
2
- import { Log, Atomic, Tracker, copyTransforms, CacheSource, isTransformsEmpty, TransactorSource } from "../index.js";
3
- import { BlockUnavailableError } from "../network/struct.js";
2
+ import { Log } from "../log/log.js";
3
+ import { Atomic } from "../transform/atomic.js";
4
+ import { Tracker } from "../transform/tracker.js";
5
+ import { CacheSource } from "../transform/cache-source.js";
6
+ import { copyTransforms, isTransformsEmpty } from "../transform/helpers.js";
7
+ import { TransactorSource } from "../transactor/transactor-source.js";
8
+ import { BlockUnavailableError, BlockPossiblyStaleError } from "../network/struct.js";
4
9
  import type { CollectionHeaderBlock, CollectionId, ICollection, SyncOptions } from "./index.js";
5
- import { CollectionHeaderVanishedError, SyncRetryExhaustedError } from "./index.js";
10
+ import { CollectionHeaderVanishedError, SyncRetryExhaustedError } from "./struct.js";
6
11
  import type { ActionContext } from "./action.js";
7
12
  import type { ReadDependency } from "../transaction/transaction.js";
8
13
  import { clampPriority } from "../transaction/transaction.js";
@@ -436,6 +441,19 @@ export class Collection<TAction> implements ICollection<TAction> {
436
441
  this.pending = [];
437
442
  }
438
443
 
444
+ /** Whether {@link sync} has anything to push: staged actions, or tracker transforms
445
+ * that were never committed (an INVENTED collection's header/root blocks live there
446
+ * until its first sync, with no pending action to name them).
447
+ *
448
+ * This is the exact predicate {@link syncInternal} loops on, so `false` means a sync
449
+ * would commit nothing. Exposed so a caller that would otherwise flush
450
+ * unconditionally can skip the round trip — note that {@link Tree.sync} routes
451
+ * through {@link updateAndSync}, so an unnecessary flush still pays a full,
452
+ * cache-bypassing {@link update} before discovering it has nothing to do. */
453
+ hasUnsyncedChanges(): boolean {
454
+ return this.pending.length > 0 || !isTransformsEmpty(this.tracker.transforms);
455
+ }
456
+
439
457
  /** Fold a just-committed set of transforms into this collection's read cache
440
458
  * so subsequent reads (and stages) through THIS instance observe the committed
441
459
  * state, mirroring what {@link sync} does inline after a successful transact.
@@ -500,7 +518,7 @@ export class Collection<TAction> implements ICollection<TAction> {
500
518
  // in the exhaustion error and never consulted to decide whether to keep retrying.
501
519
  let lastStaleAt: { blockId: BlockId; rev: number } | undefined;
502
520
 
503
- while (this.pending.length || !isTransformsEmpty(this.tracker.transforms)) {
521
+ while (this.hasUnsyncedChanges()) {
504
522
  if (signal?.aborted) {
505
523
  throw makeAbortError(signal);
506
524
  }
@@ -635,6 +653,13 @@ export class Collection<TAction> implements ICollection<TAction> {
635
653
  * pending non-tail blocks and the collection reading as if they did not exist. A tail
636
654
  * with no `state.latest` and NO flag is a real answer (nothing committed yet) and still
637
655
  * no-ops.
656
+ *
657
+ * The same goes for `unconfirmedAheadRev`: this unpinned tail read is the ONE seam where a
658
+ * lagging collection can learn a newer revision exists — every later data read is pinned to
659
+ * the context seeded here. Silently seeding from a tail the repo could not confirm is
660
+ * current would freeze the collection at the stale revision with nothing ever reporting a
661
+ * problem, so it throws the same way TransactorSource.tryGet does for its unpinned reads
662
+ * (see the tradeoff NOTE there).
638
663
  */
639
664
  private static async bootstrapContext(
640
665
  source: TransactorSource<IBlock>,
@@ -648,6 +673,9 @@ export class Collection<TAction> implements ICollection<TAction> {
648
673
  if (tailEntry?.unavailable !== undefined && tailEntry.block == null) {
649
674
  throw new BlockUnavailableError(tailId, tailEntry.unavailable);
650
675
  }
676
+ if (tailEntry?.unconfirmedAheadRev !== undefined) {
677
+ throw new BlockPossiblyStaleError(tailId, tailEntry.unconfirmedAheadRev);
678
+ }
651
679
  const tailState = tailEntry?.state;
652
680
  if (tailState?.latest) {
653
681
  source.actionContext = {
@@ -1,67 +1,68 @@
1
- import { Collection, registerCollectionType } from "../../index.js";
2
- import type { ITransactor, Action, BlockId, BlockStore, IBlock, CollectionInitOptions, CollectionId } from "../../index.js";
3
- import { DiaryHeaderBlockType } from "./struct.js";
4
-
5
- /** A diary keeps every entry in the log itself, so the header block is the whole structure
6
- * and the "append" handler has no blocks to touch. */
7
- function diaryInit<TEntry>(): CollectionInitOptions<TEntry> {
8
- return {
9
- modules: {
10
- "append": async (_action, _trx) => {
11
- // Append-only diary doesn't need to modify any blocks
12
- // All entries are stored in the log
13
- }
14
- },
15
- createHeaderBlock: (id: BlockId, store: BlockStore<IBlock>) => ({
16
- header: store.createBlockHeader(DiaryHeaderBlockType, id)
17
- })
18
- };
19
- }
20
-
21
- export class Diary<TEntry> {
22
- private constructor(
23
- private readonly collection: Collection<TEntry>
24
- ) {
25
- }
26
-
27
- /** Open an existing diary, or stage a fresh empty one when nothing has ever been committed
28
- * under this id. Attach-or-create see {@link Collection.createOrOpen}. */
29
- static async createOrOpen<TEntry>(network: ITransactor, id: CollectionId): Promise<Diary<TEntry>> {
30
- const collection = await Collection.createOrOpen(network, id, diaryInit<TEntry>());
31
- return new Diary<TEntry>(collection);
32
- }
33
-
34
- /** Open an EXISTING diary, or resolve to `undefined` when no header block has ever been
35
- * committed under this id. Never brings a diary into existence see {@link Collection.open}. */
36
- static async open<TEntry>(network: ITransactor, id: CollectionId): Promise<Diary<TEntry> | undefined> {
37
- const collection = await Collection.open(network, id, diaryInit<TEntry>());
38
- return collection ? new Diary<TEntry>(collection) : undefined;
39
- }
40
-
41
- async append(data: TEntry): Promise<void> {
42
- const action: Action<TEntry> = {
43
- type: "append",
44
- data: data
45
- };
46
-
47
- await this.collection.act(action);
48
- await this.collection.updateAndSync();
49
- }
50
-
51
- /** Fetch the latest state from the network */
52
- async update(): Promise<void> {
53
- await this.collection.update();
54
- }
55
-
56
- async *select(forward = true): AsyncIterableIterator<TEntry> {
57
- for await (const entry of this.collection.selectLog(forward)) {
58
- yield entry.data;
59
- }
60
- }
61
- }
62
-
63
- registerCollectionType({
64
- blockType: DiaryHeaderBlockType,
65
- name: "Diary",
66
- createOrOpen: (transactor, id) => Collection.createOrOpen(transactor, id, diaryInit<unknown>()),
67
- });
1
+ import { Collection } from "../../collection/collection.js";
2
+ import type { ITransactor, Action, BlockId, BlockStore, IBlock, CollectionInitOptions, CollectionId } from "../../index.js";
3
+ import { registerCollectionType } from "../../collection/collection-type-registry.js";
4
+ import { DiaryHeaderBlockType } from "./struct.js";
5
+
6
+ /** A diary keeps every entry in the log itself, so the header block is the whole structure
7
+ * and the "append" handler has no blocks to touch. */
8
+ function diaryInit<TEntry>(): CollectionInitOptions<TEntry> {
9
+ return {
10
+ modules: {
11
+ "append": async (_action, _trx) => {
12
+ // Append-only diary doesn't need to modify any blocks
13
+ // All entries are stored in the log
14
+ }
15
+ },
16
+ createHeaderBlock: (id: BlockId, store: BlockStore<IBlock>) => ({
17
+ header: store.createBlockHeader(DiaryHeaderBlockType, id)
18
+ })
19
+ };
20
+ }
21
+
22
+ export class Diary<TEntry> {
23
+ private constructor(
24
+ private readonly collection: Collection<TEntry>
25
+ ) {
26
+ }
27
+
28
+ /** Open an existing diary, or stage a fresh empty one when nothing has ever been committed
29
+ * under this id. Attach-or-create see {@link Collection.createOrOpen}. */
30
+ static async createOrOpen<TEntry>(network: ITransactor, id: CollectionId): Promise<Diary<TEntry>> {
31
+ const collection = await Collection.createOrOpen(network, id, diaryInit<TEntry>());
32
+ return new Diary<TEntry>(collection);
33
+ }
34
+
35
+ /** Open an EXISTING diary, or resolve to `undefined` when no header block has ever been
36
+ * committed under this id. Never brings a diary into existence — see {@link Collection.open}. */
37
+ static async open<TEntry>(network: ITransactor, id: CollectionId): Promise<Diary<TEntry> | undefined> {
38
+ const collection = await Collection.open(network, id, diaryInit<TEntry>());
39
+ return collection ? new Diary<TEntry>(collection) : undefined;
40
+ }
41
+
42
+ async append(data: TEntry): Promise<void> {
43
+ const action: Action<TEntry> = {
44
+ type: "append",
45
+ data: data
46
+ };
47
+
48
+ await this.collection.act(action);
49
+ await this.collection.updateAndSync();
50
+ }
51
+
52
+ /** Fetch the latest state from the network */
53
+ async update(): Promise<void> {
54
+ await this.collection.update();
55
+ }
56
+
57
+ async *select(forward = true): AsyncIterableIterator<TEntry> {
58
+ for await (const entry of this.collection.selectLog(forward)) {
59
+ yield entry.data;
60
+ }
61
+ }
62
+ }
63
+
64
+ registerCollectionType({
65
+ blockType: DiaryHeaderBlockType,
66
+ name: "Diary",
67
+ createOrOpen: (transactor, id) => Collection.createOrOpen(transactor, id, diaryInit<unknown>()),
68
+ });
@@ -1,3 +1,3 @@
1
- import { registerBlockType } from "../../index.js";
1
+ import { registerBlockType } from "../../blocks/block-types.js";
2
2
 
3
3
  export const DiaryHeaderBlockType = registerBlockType("DIH", "DiaryHeaderBlock");
@@ -1,4 +1,4 @@
1
- import { apply, get } from "../../index.js";
1
+ import { apply, get } from "../../blocks/helpers.js";
2
2
  import type { BlockId, BlockStore, IBlock, ITreeTrunk } from "../../index.js";
3
3
  import type { ITreeNode } from "../../btree/nodes.js";
4
4
  import { rootId$, type TreeCollectionHeaderBlock } from "./struct.js";
@@ -42,6 +42,10 @@ The view guarantees **one consistent answer from first read to last**:
42
42
  view-creation time.
43
43
  - A block the storage layer cannot reconstruct at the pinned revision surfaces as
44
44
  `BlockUnavailableError`, never as a silently absent block.
45
+ - A block served at a revision the repo could not confirm is the newest one *inside the
46
+ pinned view* (a cohort peer claims a revision at or below the pin that nothing could
47
+ corroborate) surfaces as `BlockPossiblyStaleError`, never as a snapshot silently missing
48
+ a committed update. A claim ABOVE the pin is irrelevant to the view and is not raised.
45
49
 
46
50
  By default a view records **no read dependencies** — it is not part of any transaction's
47
51
  conflict set, so an unrelated committed read can never fail a writer's commit validation.
@@ -1,4 +1,6 @@
1
- import { type BlockId, type CollectionHeaderBlock, registerBlockType, registerCollectionType } from "../../index.js";
1
+ import type { BlockId, CollectionHeaderBlock } from "../../index.js";
2
+ import { registerBlockType } from "../../blocks/block-types.js";
3
+ import { registerCollectionType } from "../../collection/collection-type-registry.js";
2
4
  import { nameof } from "../../utility/nameof.js";
3
5
 
4
6
  export const TreeHeaderBlockType = registerBlockType("TRE", "TreeHeaderBlock");