@optimystic/db-core 0.22.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +336 -336
- package/dist/src/cluster/structs.d.ts +39 -1
- package/dist/src/cluster/structs.d.ts.map +1 -1
- package/dist/src/cluster/structs.js +24 -0
- package/dist/src/cluster/structs.js.map +1 -1
- package/dist/src/collection/collection.d.ts +17 -0
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +24 -2
- package/dist/src/collection/collection.js.map +1 -1
- package/dist/src/collections/tree/tree.d.ts +5 -0
- package/dist/src/collections/tree/tree.d.ts.map +1 -1
- package/dist/src/collections/tree/tree.js +7 -0
- package/dist/src/collections/tree/tree.js.map +1 -1
- package/dist/src/network/i-peer-network.d.ts +16 -0
- package/dist/src/network/i-peer-network.d.ts.map +1 -1
- package/dist/src/network/struct.d.ts +39 -2
- package/dist/src/network/struct.d.ts.map +1 -1
- package/dist/src/network/struct.js +18 -0
- package/dist/src/network/struct.js.map +1 -1
- package/dist/src/testing/test-transactor.d.ts +95 -8
- package/dist/src/testing/test-transactor.d.ts.map +1 -1
- package/dist/src/testing/test-transactor.js +121 -8
- package/dist/src/testing/test-transactor.js.map +1 -1
- package/dist/src/transaction/transaction.d.ts +1 -1
- package/dist/src/transaction/transaction.js +1 -1
- package/dist/src/transactor/network-transactor.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.js +48 -13
- package/dist/src/transactor/network-transactor.js.map +1 -1
- package/dist/src/transactor/transactor-source.d.ts.map +1 -1
- package/dist/src/transactor/transactor-source.js +25 -2
- package/dist/src/transactor/transactor-source.js.map +1 -1
- package/package.json +1 -1
- package/src/cluster/membership.ts +85 -85
- package/src/cluster/structs.ts +43 -4
- package/src/cohort-topic/addressing.ts +120 -120
- package/src/cohort-topic/antidos/bootstrap-evidence-envelope.ts +253 -253
- package/src/cohort-topic/antidos/bootstrap-evidence.ts +106 -106
- package/src/cohort-topic/antidos/index.ts +5 -5
- package/src/cohort-topic/antidos/rate-limiter.ts +210 -210
- package/src/cohort-topic/antidos/replay-guard.ts +146 -146
- package/src/cohort-topic/antidos/topic-budget.ts +160 -160
- package/src/cohort-topic/antiflood/index.ts +2 -2
- package/src/cohort-topic/antiflood/invariants.ts +108 -108
- package/src/cohort-topic/antiflood/jitter.ts +117 -117
- package/src/cohort-topic/coldstart.ts +237 -237
- package/src/cohort-topic/dmax.ts +88 -88
- package/src/cohort-topic/gossip/bus.ts +254 -254
- package/src/cohort-topic/gossip/index.ts +3 -3
- package/src/cohort-topic/gossip/records.ts +45 -45
- package/src/cohort-topic/gossip/view.ts +91 -91
- package/src/cohort-topic/index.ts +20 -20
- package/src/cohort-topic/load/barometer.ts +134 -134
- package/src/cohort-topic/load/index.ts +1 -1
- package/src/cohort-topic/member-engine.ts +430 -430
- package/src/cohort-topic/membership/index.ts +3 -3
- package/src/cohort-topic/membership/publisher.ts +163 -163
- package/src/cohort-topic/membership/source.ts +41 -41
- package/src/cohort-topic/membership/verifier.ts +461 -461
- package/src/cohort-topic/ports.ts +157 -157
- package/src/cohort-topic/promotion.ts +405 -405
- package/src/cohort-topic/registration/bytes.ts +37 -37
- package/src/cohort-topic/registration/handoff.ts +154 -154
- package/src/cohort-topic/registration/index.ts +6 -6
- package/src/cohort-topic/registration/renewal.ts +495 -495
- package/src/cohort-topic/registration/sharding.ts +61 -61
- package/src/cohort-topic/registration/store.ts +81 -81
- package/src/cohort-topic/registration/types.ts +91 -91
- package/src/cohort-topic/ring-hash.ts +50 -50
- package/src/cohort-topic/service.ts +416 -416
- package/src/cohort-topic/sig/index.ts +2 -2
- package/src/cohort-topic/sig/payloads.ts +59 -59
- package/src/cohort-topic/sig/threshold.ts +64 -64
- package/src/cohort-topic/tiers.ts +74 -74
- package/src/cohort-topic/traffic.ts +233 -233
- package/src/cohort-topic/walk.ts +326 -326
- package/src/cohort-topic/willingness.ts +237 -237
- package/src/cohort-topic/wire/codec.ts +216 -216
- package/src/cohort-topic/wire/index.ts +18 -18
- package/src/cohort-topic/wire/payloads.ts +126 -126
- package/src/cohort-topic/wire/primitives.ts +188 -188
- package/src/cohort-topic/wire/types.ts +475 -475
- package/src/cohort-topic/wire/validate.ts +512 -512
- package/src/collection/collection-type-registry.ts +37 -37
- package/src/collection/collection.ts +25 -2
- package/src/collections/diary/diary.ts +68 -68
- package/src/collections/tree/readme.md +4 -0
- package/src/collections/tree/tree.ts +320 -312
- package/src/matchmaking/capability-filter.ts +45 -45
- package/src/matchmaking/config.ts +98 -98
- package/src/matchmaking/index.ts +21 -21
- package/src/matchmaking/multi-cohort-seeker.ts +234 -234
- package/src/matchmaking/provider.ts +123 -123
- package/src/matchmaking/query-eval.ts +105 -105
- package/src/matchmaking/seeker-walk.ts +127 -127
- package/src/matchmaking/seeker.ts +86 -86
- package/src/matchmaking/topic-anchor.ts +90 -90
- package/src/matchmaking/voting-quorum.ts +394 -394
- package/src/matchmaking/wire.ts +603 -603
- package/src/network/i-peer-network.ts +17 -0
- package/src/network/stale-failure.ts +43 -43
- package/src/network/struct.ts +41 -2
- package/src/network/types.ts +37 -37
- package/src/reactivity/backfill.ts +220 -220
- package/src/reactivity/backpressure.ts +191 -191
- package/src/reactivity/checkpoint.ts +308 -308
- package/src/reactivity/config.ts +172 -172
- package/src/reactivity/dedupe.ts +132 -132
- package/src/reactivity/forwarder.ts +87 -87
- package/src/reactivity/index.ts +34 -34
- package/src/reactivity/notification.ts +123 -123
- package/src/reactivity/policy.ts +79 -79
- package/src/reactivity/push-state.ts +310 -310
- package/src/reactivity/recover.ts +153 -153
- package/src/reactivity/replay-buffer.ts +141 -141
- package/src/reactivity/resume.ts +549 -549
- package/src/reactivity/rotation.ts +415 -415
- package/src/reactivity/subscriber.ts +132 -132
- package/src/reactivity/subscription.ts +66 -66
- package/src/reactivity/topic-anchor.ts +71 -71
- package/src/reactivity/verify.ts +73 -73
- package/src/reactivity/wire-validate.ts +13 -13
- package/src/reactivity/wire.ts +224 -224
- package/src/testing/async-wait.ts +65 -65
- package/src/testing/index.ts +2 -2
- package/src/testing/test-transactor.ts +638 -502
- package/src/transaction/errors.ts +91 -91
- package/src/transaction/operations-hash.ts +196 -196
- package/src/transaction/read-dependency-collector.ts +78 -78
- package/src/transaction/transaction.ts +1 -1
- package/src/transactor/change-notifier.ts +80 -80
- package/src/transactor/index.ts +5 -5
- package/src/transactor/network-transactor.ts +49 -14
- package/src/transactor/transactor-source.ts +25 -2
- package/src/transform/atomic-proxy.ts +92 -92
- package/src/transform/helpers.ts +159 -159
- package/src/utility/backoff.ts +95 -95
- package/src/utility/batch-coordinator.ts +191 -191
- package/dist/src/transaction/context.d.ts +0 -60
- package/dist/src/transaction/context.d.ts.map +0 -1
- package/dist/src/transaction/context.js +0 -91
- 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
|
+
}
|
|
@@ -5,7 +5,7 @@ import { Tracker } from "../transform/tracker.js";
|
|
|
5
5
|
import { CacheSource } from "../transform/cache-source.js";
|
|
6
6
|
import { copyTransforms, isTransformsEmpty } from "../transform/helpers.js";
|
|
7
7
|
import { TransactorSource } from "../transactor/transactor-source.js";
|
|
8
|
-
import { BlockUnavailableError } from "../network/struct.js";
|
|
8
|
+
import { BlockUnavailableError, BlockPossiblyStaleError } from "../network/struct.js";
|
|
9
9
|
import type { CollectionHeaderBlock, CollectionId, ICollection, SyncOptions } from "./index.js";
|
|
10
10
|
import { CollectionHeaderVanishedError, SyncRetryExhaustedError } from "./struct.js";
|
|
11
11
|
import type { ActionContext } from "./action.js";
|
|
@@ -441,6 +441,19 @@ export class Collection<TAction> implements ICollection<TAction> {
|
|
|
441
441
|
this.pending = [];
|
|
442
442
|
}
|
|
443
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
|
+
|
|
444
457
|
/** Fold a just-committed set of transforms into this collection's read cache
|
|
445
458
|
* so subsequent reads (and stages) through THIS instance observe the committed
|
|
446
459
|
* state, mirroring what {@link sync} does inline after a successful transact.
|
|
@@ -505,7 +518,7 @@ export class Collection<TAction> implements ICollection<TAction> {
|
|
|
505
518
|
// in the exhaustion error and never consulted to decide whether to keep retrying.
|
|
506
519
|
let lastStaleAt: { blockId: BlockId; rev: number } | undefined;
|
|
507
520
|
|
|
508
|
-
while (this.
|
|
521
|
+
while (this.hasUnsyncedChanges()) {
|
|
509
522
|
if (signal?.aborted) {
|
|
510
523
|
throw makeAbortError(signal);
|
|
511
524
|
}
|
|
@@ -640,6 +653,13 @@ export class Collection<TAction> implements ICollection<TAction> {
|
|
|
640
653
|
* pending non-tail blocks and the collection reading as if they did not exist. A tail
|
|
641
654
|
* with no `state.latest` and NO flag is a real answer (nothing committed yet) and still
|
|
642
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).
|
|
643
663
|
*/
|
|
644
664
|
private static async bootstrapContext(
|
|
645
665
|
source: TransactorSource<IBlock>,
|
|
@@ -653,6 +673,9 @@ export class Collection<TAction> implements ICollection<TAction> {
|
|
|
653
673
|
if (tailEntry?.unavailable !== undefined && tailEntry.block == null) {
|
|
654
674
|
throw new BlockUnavailableError(tailId, tailEntry.unavailable);
|
|
655
675
|
}
|
|
676
|
+
if (tailEntry?.unconfirmedAheadRev !== undefined) {
|
|
677
|
+
throw new BlockPossiblyStaleError(tailId, tailEntry.unconfirmedAheadRev);
|
|
678
|
+
}
|
|
656
679
|
const tailState = tailEntry?.state;
|
|
657
680
|
if (tailState?.latest) {
|
|
658
681
|
source.actionContext = {
|
|
@@ -1,68 +1,68 @@
|
|
|
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
|
+
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
|
+
});
|
|
@@ -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.
|