(hovered = null)}>
{#if !supported}
This viewer cannot draw steps
The host it runs in has not wired the steps question. The Screens and Flow views still work.
{:else if !asked}
What happens from where?
{#if chooser === 'routes'}
Pick an endpoint and this view draws everything it sets in motion — its handler and what runs
before it, the calls into the database, a queue, another service, and every response it can
send — one box per step, an arrow for every way one leads to the next, and on each arrow the
condition under which it happens. Or search a symbol and choose What happens from here .
{:else}
Pick a screen and this view draws everything it sets in motion — its handlers, the calls that
cross into native code, the events that come back, the state it writes, the requests that leave
the app — one box per step, an arrow for every way one leads to the next, and on each arrow the
condition under which it happens. Or search a symbol and choose What happens from here .
{/if}
{#if chooser === null}
Reading {screens === null ? 'screens' : 'endpoints'}…
{:else if chooser === 'none'}
No screens or endpoints in this graph. Open a symbol from the search box and follow What happens from here ,
or link here directly with #/steps?symbol=<name> .
{:else if chooser === 'screens' && screens !== null}
{:else if routes !== null}
{#each routeGroups(routes) as group (group.file)}
{group.file} {group.entries.length}
{/each}
{/if}
{:else if error !== null}
The steps could not be read
{error}
{:else if loading && payload === null}
{:else if model !== null && payload !== null && readAs === 'order' && !orderReadable}
This has no body to read in order
Nothing the picture holds is written inside this symbol — a screen renders handlers that fire on
events, and they have no order between them. Read it as what it sets in motion instead.
What it sets in motion →
{:else if model !== null && payload !== null}
{
selected = null;
hovered = null;
panelHot = null;
}}
>
{#if hovered !== null && hoveredInfo !== null}
{nameOf(hoveredInfo.from)} → {nameOf(hoveredInfo.to)}
{#each hoveredInfo.links.slice(0, 5) as link (link.id)}
{#if link.trigger}FIRES FROM {triggerWords(link.trigger)} in {link.trigger.in} {/if}
{#if link.via.length > 0}via {stepViaText(link)} {/if}
{#if link.within}inside {link.within}(…) {/if}
{#if link.sites.length > 1}{link.sites.length} ways {/if}
{@render words(conditionTokens(link.when))}
{#if link.label}{link.label} {/if}
{#if link.sites[0]}{#if link.sites[0].status}{link.sites[0].status} · {/if}{siteWords(link.sites[0])} {/if}
{/each}
{#if hoveredInfo.links.length > 5}
+{hoveredInfo.links.length - 5} more
{/if}
{/if}
{/if}
{#if payload !== null && model !== null && (readAs === 'tree' || orderReadable)}
(legendOpen = next)}
/>
{/if}
{#if selectedInfo !== null && lists !== null}
{#if selectedInfo.step.cut === 'screen'}
Another {kindWord('screen', payload.project, selectedInfo.step)} — a chapter of its own. Start here (or double-click its box) to see what happens on it, or continue through {kindWords('screen', payload.project)[1]} from the summary.
{:else if selectedInfo.step.cut === 'component'}
The event lands in a component of another screen — a picture of its own. Start here (or double-click its box) to see it, or continue through screens from the summary.
{:else if selectedInfo.step.cut !== null}
The walk was cut at this step ({selectedInfo.step.cut === 'depth'
? 'the picture’s depth'
: selectedInfo.step.cut === 'fan-out'
? 'more calls than the walk follows from one node'
: selectedInfo.step.cut === 'folded'
? 'as much plumbing as it folds from one step'
: 'the picture’s size'}). Start here to see on.
{/if}
{#if selectedInfo.step.effect && selectedInfo.step.effect.apis.length > 1}
{selectedInfo.step.effect.apis.join(' · ')}
{/if}
{#if selectedInfo.step.effect?.category === 'response'}
{selectedInfo.step.effect.statuses?.length ? 'One way the endpoint answers — each row below is a site that sends it, with the condition it answers under; its other outcomes are the boxes beside it.' : 'Replies whose status the code does not spell out — each row below is one, with the condition it answers under.'}
{/if}
{#if selectedInfo.step.events && selectedInfo.step.events.length > 1}
⇠ {selectedInfo.step.events.join(' · ')}
{/if}
{#if pills !== null && pills.hidden > 0}
{pills.hidden} condition{pills.hidden === 1 ? '' : 's'} not drawn on the picture for want of
room — hover a row below to see {pills.hidden === 1 ? 'it' : 'each'} on its line.
{/if}
Arrives from {lists.arrivesFrom.length}
{#if lists.arrivesFrom.length === 0}
{selectedInfo.step.anchor ? 'The anchor — the picture starts here.' : 'Nothing in the picture leads here.'}
{/if}
{#each lists.arrivesFrom as link (link.id)}
{@const sc = scenarios(link.sites)}
{@const fallback = payload.steps.find((s) => s.id === link.from)?.node?.id ?? null}
onRowHover(link)}
onmouseleave={() => onRowHover(null)}
onfocusin={() => onRowHover(link)}
onfocusout={() => onRowHover(null)}
>
(selected = link.from)}>{nameOf(link.from)}
{#if link.trigger}
FIRES FROM {triggerWords(link.trigger)} in {link.trigger.in}
{/if}
{#if link.via.length > 0}
via {stepViaText(link)}
{/if}
{#if link.within}
inside {link.within}(…)
{/if}
{#if sc.common.length > 0}
{@render words(commonTokens(sc.common))}
{/if}
{#if link.label}
{link.label}
{/if}
{#if sc.rows.length > 1}
{sc.rows.length} ways
{/if}
{#each sc.rows as row (row.site.file + row.site.line)}
{@const href = siteHref(link, row.site, fallback)}
{/each}
{#if stripHref(link)}
Open as a flow → {/if}
{/each}
Leads to {lists.leadsTo.length}
{#if lists.leadsTo.length === 0}
{selectedInfo.step.kind === 'effect'
? 'Outside the index: the graph cannot follow it further.'
: selectedInfo.step.cut === 'screen' || selectedInfo.step.cut === 'component'
? 'Not entered — a boundary. Start here for its own picture, or continue through from the summary.'
: 'Nothing the walk follows leaves this step.'}
{/if}
{#each lists.leadsTo as link (link.id)}
{@const sc = scenarios(link.sites)}
{@const fallback = selectedInfo.step.screen?.component?.id ?? selectedInfo.step.node?.id ?? null}
onRowHover(link)}
onmouseleave={() => onRowHover(null)}
onfocusin={() => onRowHover(link)}
onfocusout={() => onRowHover(null)}
>
(selected = link.to)}>{nameOf(link.to)}
{#if link.trigger}
FIRES FROM {triggerWords(link.trigger)} in {link.trigger.in}
{/if}
{#if link.via.length > 0}
via {stepViaText(link)}
{/if}
{#if link.within}
inside {link.within}(…)
{/if}
{#if sc.common.length > 0}
{@render words(commonTokens(sc.common))}
{/if}
{#if link.label}
{link.label}
{/if}
{#if sc.rows.length > 1}
{sc.rows.length} ways
{/if}
{#each sc.rows as row (row.site.file + row.site.line)}
{@const href = siteHref(link, row.site, fallback)}
{/each}
{#if stripHref(link)}
Open as a flow → {/if}
{/each}
{:else}
{#if payload.ambiguous.length > 0}
{payload.ambiguous.length} other symbol{payload.ambiguous.length === 1 ? '' : 's'} share this name:
{#each payload.ambiguous as other, i (other.id)}
{#if i > 0},{/if}
{other.kind} in {basename(other.file)}
{/each}
{/if}
Read as:
in order
what it sets in motion
{payload.steps.length} steps · {payload.links.length} links · depth
navigate(rewrite({ depth: Number((e.currentTarget as HTMLSelectElement).value) }))}
>
{#each DEPTHS as d (d)}
{d}
{/each}
{#if !DEPTHS.includes(payload.depth)}{payload.depth} {/if}
navigate(rewrite({ through: (e.currentTarget as HTMLInputElement).checked }))} />
Continue through {kindWords('screen', payload.project)[1]}
— otherwise another {kindWord('screen', payload.project)} is drawn as a boundary, and is a click from being the next anchor.
{#each ['screen', 'trigger', 'bridge', 'event', 'store', 'effect'] as const as kind (kind)}
{#if model.counts[kind] > 0}
{@const words = kindWords(kind, payload.project)}
{model.counts[kind]} {model.counts[kind] === 1 ? words[0] : words[1]}
{/if}
{/each}
{#if readAs === 'order'}
● The anchor is at the top, and each row down is what happens next: a line
means and then , and where the code forks the line says what has to hold. A call written inside
another call's arguments happens first — the token is signed before the reply that carries it — and an
arm that answers, returns or throws simply has nothing leaving it. Click a step for its sites and the
whole condition; a step is the next anchor.
{:else}
● The anchor is at the top; each row down is one more step away from
it. Click a step and each of its links is labelled at the far end of its line with the last
condition checked before it happens; hover the line, or its row here, for the whole chain and the
plumbing it travels through. A step is the next anchor, and any link opens as a Flow strip.
{/if}
{#if payload.truncated.steps > 0 || payload.truncated.hubs > 0 || payload.truncated.chrome > 0}
Not drawn:
{#if payload.truncated.steps > 0}{payload.truncated.steps} step{payload.truncated.steps === 1 ? '' : 's'} past the picture’s size limit;{/if}
{#if payload.truncated.hubs > 0}{payload.truncated.hubs} walk{payload.truncated.hubs === 1 ? '' : 's'} that reached a hub;{/if}
{#if payload.truncated.chrome > 0}{payload.truncated.chrome} into shared chrome.{/if}
{/if}
Most connected
{#each [...payload.steps].sort((a, b) => (model.layout.nodes.find((n) => n.id === b.id)?.ports.top.length ?? 0) + (model.layout.nodes.find((n) => n.id === b.id)?.ports.bottom.length ?? 0) - ((model.layout.nodes.find((n) => n.id === a.id)?.ports.top.length ?? 0) + (model.layout.nodes.find((n) => n.id === a.id)?.ports.bottom.length ?? 0))).slice(0, 8) as step (step.id)}
(selected = step.id)}>{model.nodes.get(step.id)?.label ?? step.label} {kindWord(step.kind, payload.project, step)}
{/each}
{/if}