Skip to content

Documentation / @etherfold/browser / HostProgress

Type Alias: HostProgress ​

HostProgress = object

Defined in: packages/browser/src/host/envelope.ts:137

WHERE THE FOLD HAS GOT TO, and the evidence of WHERE IT IS RUNNING.

The minimum surface that proves the path end to end: a tab that gets an answer at all has proof the host is alive (which is why there is no alive field -- an answer IS that fact), and the two block numbers are how far the fold has got and how far it has to go.

It is ONE value, delivered two ways ​

The progress case ANSWERS it to a tab that asked, and the progress PUSH carries the same type to a tab that subscribed. There is deliberately not a second, richer shape for the pushed one: two progress types on one port would be two things to keep in step, and the answer to "what did I miss" would differ from the answer to "where are we now".

The derived figures are the HOST's, computed once ​

createIndexerState computes a blocks-processed count and a percentage for the main-thread case, and those are what an app actually binds to a progress bar, so they cross rather than being recomputed on the tab from a third block number. It is the same placement the rows take (declaredRow runs in the host): one implementation rather than two that agree by inspection.

What is NOT reused is the WORD blocksBehind. GenerationProgress.blocksBehind already means how far a non-canonical generation is behind the CANONICAL one, which is a different question with a different answer, so the distance to the chain tip is blocksBehindTip and says which tip in its name.

Properties ​

blocksBehindTip? ​

readonly optional blocksBehindTip?: number

Defined in: packages/browser/src/host/envelope.ts:185

HOW MANY BLOCKS BEHIND THE CHAIN TIP the fold is: the number in "syncing, 400 blocks behind", and 0 at the tip.

Named for the tip it measures against, because blocksBehind is taken: GenerationProgress.blocksBehind is how far a non-canonical generation is behind the CANONICAL one.

This and the two figures below are ABSENT TOGETHER until a tip has been learnt (latestBlock > 0), because every one of them is a statement about a distance to a tip and a host that has not fetched knows of none. Absent rather than 0: "level" and "unknown" are different claims, and an app that renders a progress bar from a 0 it was handed before the first fetch shows a full one.


election? ​

readonly optional election?: TabElectionState

Defined in: packages/browser/src/host/envelope.ts:256

WHAT THE TAB ELECTION MADE OF THIS HOST, or ABSENT where the app did not opt in (ADR-0097): reader while another tab holds the lock and indexes, writer once this host holds it, and tookOver once it became the writer after waiting behind a tab that went away.

A READER's block figures and phase are the LEADER's, heard over the election channel (a leader publishes; it is not polled), so a tab that is not indexing renders "syncing, 400 blocks behind" from the same report the indexing tab renders. host and scope stay this host's own.


failure? ​

readonly optional failure?: PortError

Defined in: packages/browser/src/host/envelope.ts:214

WHY the driver stopped, where it stopped on a failure rather than on a request.

Reported rather than thrown, for the reason a demotion is: the tab asked how far the fold got, and "it stopped, here is why" is the answer to that question. A host that silently reported indexing: false for ever would be indistinguishable from one that had not started.


host ​

readonly host: HostingShape

Defined in: packages/browser/src/host/envelope.ts:139

WHICH hosting shape is answering, as the entry point that obtained the port named it.


hotUpdate? ​

readonly optional hotUpdate?: HostHotUpdate

Defined in: packages/browser/src/host/envelope.ts:244

WHAT THE LAST HOT UPDATE THIS HOST TOOK DID, or ABSENT where it has taken none.

A worker host takes an edited processor from the worker entry's OWN import.meta.hot.accept (IndexerHost.reconfigureFromHotUpdate): the module arrives inside the worker, so the call is made there and no tab made it. This is how a tab learns the verdict anyway, on the push it already listens to. See HostHotUpdate.


indexing ​

readonly indexing: boolean

Defined in: packages/browser/src/host/envelope.ts:150

Whether the host's DRIVER is running: false before it starts and after it stops.


lastToBlock? ​

readonly optional lastToBlock?: number

Defined in: packages/browser/src/host/envelope.ts:167

How far the fold has got. Absent until the container has published a cursor.

THE TRAP, which is the container's and is reported rather than re-decided here: a generation that has loaded and not yet FETCHED publishes 0 for both of these -- it has folded nothing and has not learnt a tip. So equality alone does not mean CAUGHT UP, it means "as far as this cursor knows", and a tab rendering a progress figure has to know which of the two it is looking at. It is left as the container's own figures deliberately: inventing a third value here to disambiguate would be a second meaning of a cursor. What DOES disambiguate the two is phase, which is loading or catching-up until an ADVANCE has said otherwise, and the derived figures below, which are absent until a tip has been learnt at all.


latestBlock? ​

readonly optional latestBlock?: number

Defined in: packages/browser/src/host/envelope.ts:169

The chain tip as of that advance. Absent until the container has published a cursor.


numBlocksProcessedSoFar? ​

readonly optional numBlocksProcessedSoFar?: number

Defined in: packages/browser/src/host/envelope.ts:195

How many blocks this fold has got through, counted from the block it STARTS at (the source's earliest startBlock) rather than from where this session resumed.

createIndexerState's numBlocksProcessedSoFar, under its own name and by its own rule, because it is the numerator of the progress bar an app already draws and the two paths should not disagree about what the word counts.


phase ​

readonly phase: SyncPhase

Defined in: packages/browser/src/host/envelope.ts:152

WHICH of the five coarse things the fold is doing. See SyncPhase.


publication? ​

readonly optional publication?: PublicationState

Defined in: packages/browser/src/host/envelope.ts:225

WHAT THE PUBLICATION INDEX GAVE THIS HOST, or ABSENT where it was given no publication (ADR-0095): SyncingState.publication, carried across.

The same value in every hosting shape, so a tab reading the port renders the lookup (found, or refused with why) and a returning tab's switch (switched, ADR-0096) exactly as a tab reading the main thread's stores does. Its own field and not failure, on the ground SyncingState.publication is not error: no outcome here stops the host.


scope ​

readonly scope: string

Defined in: packages/browser/src/host/envelope.ts:148

WHAT globalThis IS where this answer was computed: 'DedicatedWorkerGlobalScope' in a worker, 'Window' on the main thread.

Measured rather than declared, so "the UI thread is not doing the fold" is a fact a test can assert on instead of a timing threshold. See executionScopeName.


streamSeed? ​

readonly optional streamSeed?: StreamSeedState

Defined in: packages/browser/src/host/envelope.ts:234

WHAT HAPPENED TO THE STREAM SEED this host was asked to install, or ABSENT where none was asked for: SyncingState.streamSeed, carried across.

A refusal is DATA and the host starts anyway (ADR-0064). An install that THROWS leaves installing standing and stops the host, which reports it as failure.


syncPercentage? ​

readonly optional syncPercentage?: number

Defined in: packages/browser/src/host/envelope.ts:204

The same span as a PERCENTAGE, to four decimal places, exactly as createIndexerState rounds it.

100 where there is nothing to process (a tip at or below the block the fold starts at), which is the truthful reading of a fold with no span rather than the division by zero the main-thread version performs there.