Documentation / @etherfold/browser / PortCases
Type Alias: PortCases ​
PortCases =
object
Defined in: packages/browser/src/host/envelope.ts:417
EVERY SURFACE THE PORT CARRIES, as a map from case name to what it takes and what it answers.
A later task adds a key and gets its request typed, its response typed and its clone-safety checked, with no change to the transport, the correlation or either end's plumbing -- which is the property ADR-0082 asked for, and which the four reads below are the first demonstration of.
The store's FOUR reads, as four cases ​
One case per read rather than one read case with a verb inside it: the requests differ in what they carry (an id or a prefix, with or without a block), so a single case would be a union a host has to narrow by hand, and the envelope's own dispatch already is that narrowing. The names are the seam's own (getCurrent / getAsOf / listCurrent / listAsOf), so there is one vocabulary from the store, through the port, to the surface a tab holds.
There are FOUR and there will not be a fifth: the seam has no predicate and no ordering, because a handler runs once per event on a substrate with no query planner (ADR-0021). Richer queries arrive on this same port as the EXECUTOR the-same-query-runs-against-a-worker-and-a-server defines, which owns its own serialisation -- not as more methods on this proxy.
The LIFECYCLE calls, as cases of their own ​
startIndexing, stopIndexing, reconfigure, generations and promotion are the control half of ADR-0082's "status and control" surface, and they are REQUESTS WITH ANSWERS rather than fire-and-forget messages: a tab that asks for a reconfigure learns whether it was accepted, what it created, or -- through the refusal path -- why not. There is deliberately no case that advances the fold by ONE step: a round trip per cycle is the polling this port replaced, and the driver that does the advancing lives in the host.
Properties ​
checkTxInclusion ​
readonlycheckTxInclusion:object
Defined in: packages/browser/src/host/envelope.ts:585
DOES THE INDEXED STATE ALREADY ACCOUNT FOR THESE TRANSACTIONS? One verdict per hash, from the window the host's canonical generation maintains.
A LIST in, a record out, because an app with a pending queue asks about the QUEUE: a call per transaction would be a round trip per transaction for a question every one of them answers off the same window, built once per call (indexWindow).
The verdict crosses WHOLE, and must never become a boolean ​
TxInclusionVerdict is @etherfold/core's own type, carried unchanged: a STATUS and the BASIS for it. Narrowing it at this boundary would destroy the distinction the type exists for -- unknown has two causes (not-synced, window-not-covering) and an app renders those differently from an honest absent, because dropping an optimistic update on "I cannot tell" is the double-count this whole surface exists to prevent.
minedAtBlock crosses PER QUERY and is not decoration: the window is SPARSE, so absent means only "not in the window", and a caller holding a RECEIPT closes that through the below-window branch. A tab is exactly where a caller has a receipt.
A SNAPSHOT, and deliberately not a subscription ​
It is answered against the state at the moment of the call, so an app watching a transaction ASKS AGAIN rather than being handed something live. The window moves as the fold advances and as reorgs are concluded, and a verdict pushed at a tab would be a second progress signal with the same cadence as the one already on this port -- progress is what tells an app that asking again is worth it.
request ​
readonlyrequest:object
request.queries ​
readonlyqueries: readonlyTxInclusionQuery[]
response ​
readonlyresponse:Record<string,TxInclusionVerdict>
connect ​
readonlyconnect:object
Defined in: packages/browser/src/host/envelope.ts:462
WHAT THE TAB HANDS ITS HOST WHEN IT CONNECTS: the cloneable settings, and the chain as a MessagePort speaking @eip-1193/over-port (ADR-0082, amended).
Sent by the port itself, FIRST, on every host it obtains (the first one and every restart), so it is ahead of anything else on the wire and a restarted host is told again what the dead one was told. The provider port rides in the TRANSFER list, which is why this is the one request whose payload is not a plain clone.
Answered with where the fold is, or refused naming the fields that disagree (HostSettingsConflictError). A main-thread host refuses it outright: it takes its provider and settings from init, on the thread that holds them.
request ​
readonlyrequest:object
request.provider? ​
readonlyoptionalprovider?:MessagePort
request.settings ​
readonlysettings:HostSettings
response ​
readonlyresponse:HostProgress
declarations ​
readonlydeclarations:object
Defined in: packages/browser/src/host/envelope.ts:650
WHAT THE HOST'S STORE WAS BUILT WITH, so a tab's surface can be checked against it.
The same-thread surface compares its declarations with the store's at CONSTRUCTION and refuses a disagreement naming both (assertDeclaredBy), because a surface generated from a stale copy types its rows off columns the store does not have. A port cannot answer that question synchronously, so it is asked here -- once, when a surface is built -- and the refusal lands on the first read instead of on the constructor.
request ​
readonlyrequest:undefined
response ​
readonlyresponse: readonlyNormalizedEntity[]
generations ​
readonlygenerations:object
Defined in: packages/browser/src/host/envelope.ts:542
EVERY GENERATION THIS HOST HOLDS, in the order it built them, with the one answering reads marked.
Asked rather than pushed: a generation list changes when a caller RECONFIGURES or a pointer moves, which is a handful of times in a session, and pushing it would be a second signal to keep in step with one nobody is watching between reconfigures.
request ​
readonlyrequest:undefined
response ​
readonlyresponse: readonlyHostGeneration[]
getAsOf ​
readonlygetAsOf:object
Defined in: packages/browser/src/host/envelope.ts:657
One entity as of a block NUMBER. Refused, never answered from the tip, outside retention.
request ​
readonlyrequest:object
request.at ​
readonlyat:number
request.entity ​
readonlyentity:string
request.id ​
readonlyid:EntityId
response ​
readonlyresponse:PortRow|undefined
getCurrent ​
readonlygetCurrent:object
Defined in: packages/browser/src/host/envelope.ts:652
One entity at the tip, or undefined if it is absent.
request ​
readonlyrequest:object
request.entity ​
readonlyentity:string
request.id ​
readonlyid:EntityId
response ​
readonlyresponse:PortRow|undefined
letGo ​
readonlyletGo:object
Defined in: packages/browser/src/host/envelope.ts:508
THIS TAB IS LETTING GO: quiet the host if nothing else holds it, and say whether it did.
Posted by the port itself on its way out (IndexerPort.close), never by an app, and deliberately NOT a stopIndexing: that one is an app asking for the fold to stop, meant for the host, and a SharedWorker host must honour it for every tab. This one is a tab leaving, and a host several tabs hold must not stop for it while the others stay.
The HOST answers it as a stop, always, because a host is never told how many tabs hold it (ADR-0082): what reaches it is only what its endpoint forwards. So the decision is the shape's. A dedicated worker, a main-thread wire and the LAST tab of a SharedWorker forward it, and the host stops once the cycle in flight has landed and answers quiesced: true, which is the only quiet a shape may kill a host on (HostAccess.close). A SharedWorker tab that is NOT the last is detached where it attached (sharedWorker.ts) and answered quiesced: false there, and the fold goes on for the others.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:object
response.quiesced ​
readonlyquiesced:boolean
listAsOf ​
readonlylistAsOf:object
Defined in: packages/browser/src/host/envelope.ts:667
The same listing as of a block NUMBER.
request ​
readonlyrequest:object
request.at ​
readonlyat:number
request.entity ​
readonlyentity:string
request.limit ​
readonlylimit:number
request.prefix ​
readonlyprefix:EntityIdPrefix
response ​
readonlyresponse:Listing<PortRow>
listCurrent ​
readonlylistCurrent:object
Defined in: packages/browser/src/host/envelope.ts:662
The rows of an id PREFIX at the tip, ascending, bounded by a REQUIRED limit.
request ​
readonlyrequest:object
request.entity ​
readonlyentity:string
request.limit ​
readonlylimit:number
request.prefix ​
readonlyprefix:EntityIdPrefix
response ​
readonlyresponse:Listing<PortRow>
ping ​
readonlyping:object
Defined in: packages/browser/src/host/envelope.ts:434
ARE YOU STILL THERE? The one case whose ANSWER is its entire content.
It carries nothing and answers nothing, because the only fact being asked for is that something answered at all. A port PROBES with it when its host has been silent (IndexerPortOptions.watch), and a probe that goes unanswered is how a tab learns the host died -- which is the only way it CAN learn, since no browser fires an event when it evicts a dedicated worker.
Deliberately not progress, which would answer this too. What is polled here is LIVENESS and never STATUS: status is PUSHED (ADR-0082), and a port that asked for a cursor on a timer would be the polling that decision exists to replace, with the cost merely moved to the other end of the wire.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:undefined
progress ​
readonlyprogress:object
Defined in: packages/browser/src/host/envelope.ts:419
How far the fold has got. Takes nothing.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:HostProgress
promotion ​
readonlypromotion:object
Defined in: packages/browser/src/host/envelope.ts:552
THE PROMOTION POLICY IN FORCE, as the container resolved it.
Reported rather than re-derived, and NOTHING IS DEFAULTED AT THIS BOUNDARY: there is one default everywhere (on-catch-up), it lives with the type it belongs to, and a second copy of it in the browser -- or in the tab, one step further out -- is how two runtimes come to disagree about which value an app is running under (CONTEXT.md, canonical pointer).
request ​
readonlyrequest:undefined
response ​
readonlyresponse:UsedPromotionConfig
query ​
readonlyquery:object
Defined in: packages/browser/src/host/envelope.ts:686
ONE QUERY, handed to the handler the host's entry injected, and its answer (ADR-0099). GENERIC: the request and the answer are opaque here, because this package carries the case and never the query language (host/query.ts). The GraphQL executor on this port is workerExecutor in @etherfold/graphql/worker, which owns its own serialisation, so its answers are the bytes every other executor answers.
A host whose entry passed no handler REFUSES it, naming the missing handler.
request ​
readonlyrequest:object
request.request ​
readonlyrequest:unknown
response ​
readonlyresponse:unknown
reconfigure ​
readonlyreconfigure:object
Defined in: packages/browser/src/host/envelope.ts:529
RECONFIGURE THE SOURCE: fold it in a generation BESIDE the live one.
The SOURCE and nothing else, because the source is the only half of a generation that is DATA. A generation is a stream and a fold over it; the fold is code, so changing it is a new worker bundle rather than a message (ADR-0082), and the stream CONFIG is one mutable value on the one keeper a container holds, so it is not settable per generation (GenerationSpec.source).
What the host does with it is the generation machinery unchanged: the new generation folds beside the canonical one, which goes on answering every read, and the canonical pointer moves when the promotion policy says so -- on-catch-up once the new fold reaches the cursor the live one has, immediate at once, manual never on its own.
A REFUSAL crosses as the refusal it is (GenerationCapReachedError, which is the one this case meets), carrying its own fields: see PortError. What the new generation meets later, while it FOLDS, is reported on progress like any other driver failure.
request ​
readonlyrequest:object
request.source ​
readonlysource:IndexingSource<Abi>
response ​
readonlyresponse:HostReconfigure
startIndexing ​
readonlystartIndexing:object
Defined in: packages/browser/src/host/envelope.ts:477
START THE DRIVER, and answer where the fold is now.
Starting a host that is already indexing is an ANSWER and not a refusal: "index" is a state a caller asks for rather than an edge it triggers, so a settings screen that asks twice, or two components that each ask once, leave the host in the state they both asked for. What comes back says which state that is (HostProgress.indexing). One arriving while a STOP is still being honoured waits for that stop to land and then starts afresh, so the pair cannot race into a host that was asked to index and is not.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:HostProgress
stopIndexing ​
readonlystopIndexing:object
Defined in: packages/browser/src/host/envelope.ts:488
STOP THE DRIVER, and answer where the fold stopped.
It ANSWERS WHEN THE CYCLE IN FLIGHT HAS FINISHED, which is what makes it honest: no chain request is made after this response is posted, and the cursor is where a completed cycle would have left it rather than somewhere half a cycle in. A cut-off cycle is not on offer at all -- the cursor is written in the same transaction as the block it describes (ADR-0027), so the consistent thing to do with an advance already under way is to let it land.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:HostProgress
subscribeToProgress ​
readonlysubscribeToProgress:object
Defined in: packages/browser/src/host/envelope.ts:602
START PUSHING progress to this tab, and answer where the fold is NOW.
The current value comes back as the RESPONSE rather than as a push chasing it, which is what makes a tab that attached half way through a fold correct immediately: there is no window in which it holds nothing, and no race between a first push and the answer to a question it also asked.
Named for WHAT it subscribes to rather than taking a topic argument, on the same ground the four reads are four cases: the envelope's dispatch already is that narrowing, and a later push would otherwise make one case's response type depend on its request's contents.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:HostProgress
subscribeToStateMoved ​
readonlysubscribeToStateMoved:object
Defined in: packages/browser/src/host/envelope.ts:630
START PUSHING THE state-moved signal to this tab, and answer NOTHING.
The pair beside subscribeToProgress, and the one place the two differ is the RESPONSE, which is empty here on purpose. Progress is a STATE -- "where is the fold now" has an answer at every instant, so a subscriber is handed it and is correct immediately. The signal is an EVENT: what it says is that a block was applied AT A MOMENT, and replaying the last one at a tab that attached afterwards would tell it something moved when nothing did, under a token it has never held (ADR-0083: best-effort, at-most-once, and the producer holds NOTHING per client).
So a tab that attaches part way through a fold is told nothing until the fold NEXT moves, and what it does in the meantime is READ -- through the four reads it already holds, which answer from where the fold is now. That is the same residual ADR-0083 records for every transport: a reader on a quiet chain learns nothing until a block moves, and buffering per client to close it is the one thing the signal must not do.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:undefined
unsubscribeFromProgress ​
readonlyunsubscribeFromProgress:object
Defined in: packages/browser/src/host/envelope.ts:610
STOP PUSHING progress to this tab.
The host stops POSTING, rather than the tab stopping listening: an unsubscribed tab that still received the messages would be paying the cost the push cadence exists to bound.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:undefined
unsubscribeFromStateMoved ​
readonlyunsubscribeFromStateMoved:object
Defined in: packages/browser/src/host/envelope.ts:638
STOP PUSHING the signal to this tab.
The host stops POSTING, exactly as unsubscribeFromProgress does, and with the same consequence one level down: the host lets go of its own subscription to the container's signal when the last tab lets go of this one.
request ​
readonlyrequest:undefined
response ​
readonlyresponse:undefined
visibility ​
readonlyvisibility:object
Defined in: packages/browser/src/host/envelope.ts:447
THIS TAB IS, OR IS NOT, ON SCREEN: document.visibilityState, told to the host so a worker host can take part in the tab election's FOREGROUND TAKEOVER (ADR-0097, D4 as amended), since a worker has no document of its own.
Sent by the port itself, from a scope that has a document, after the connect and on every visibilitychange (and again to a restarted host). Answered with nothing. A host that does not take part ignores it: the main-thread host (it reads the document it runs beside), a SharedWorker host (one indexer for every tab, not a background tab), and any host with the takeover off or no election at all.
request ​
readonlyrequest:object
request.visibility ​
readonlyvisibility:TabVisibility
response ​
readonlyresponse:undefined