Skip to content

The interface

The interface is split in two, and the cut is deliberate:

  • @reply2social/core — plain TypeScript. Which routes exist, what shape their responses have, and what each “no” means. Zero framework dependencies.
  • @reply2social/svelte — how it is painted. Thin on purpose.

Wrappers

@reply2social/core — framework-free

injects

transporte.ts

pedir() and FalloApi

esquemas.ts

zod: the shape of everything

cliente.ts

the service routes

vista.ts

legible(): a 15-line store

vista_*.ts

one per screen

@reply2social/svelte

react / vue / whatever comes

The host

supplies the transport: cookies, tokens, base URL

The transport comes in as a parameter and is not resolved inside. How the viewer authenticates belongs to the host: on Antisionista it is a session cookie, on another installation it could be a token. If the core knew about cookies it would be useless on the second installation — and it would be the one module you have to rewrite in order to port it.

The layers, and what each one decides

uses

throws

«type»

Transporte

+llamar(ruta, opts) : Promise<Response>

FalloApi

+clase: ClaseDeFallo

+message: string

+status?: number

+detalle?: string

+reintentable: bool

Cliente

+emisiones

+cuentas

+fuentes

+flujos

+archivo

+alertas

+cursores

+programacion

+consentimientos

+cauce

«interface»

Legible<T>

+subscribe(fn) : Desuscribir

VistaArchivo

+cargar()

+filtrar(cambios)

+alternar(fila)

+sembrar()

VistaFuentes

+cargar()

+probar()

+crear()

+otorgar(evidencia)

+semaforoDe(destino) : Marca

ClaseDeFallo: what each “no” means

A raw HTTP error is of no use to a screen. 401 and 503 are both “you do not get through”, and you want to do different things with each.

ClassWhenWhat the screen should do
sesion401Send the user to log in again
permiso403Say the role is not enough; do not retry
no_disponible503“Could not be queried” — not “there is nothing”
conflicto409Already exists: explain it, do not retry
peticion400Something in the form is wrong
servidor5xxRetryable
rednever arrivedRetryable
contratoshape does not matchPanel and service on different versions

contrato exists as a class of its own. When the service returns something the panel does not understand, what happened is almost always that they are on different versions —one was deployed and the other was not— and the message says so. Without that class it showed up as a server error and people looked for the problem in the wrong place.

One view per screen

Each view is a function that takes the client and returns a readable store plus its actions. The contract is subscribe, which is the same one Svelte uses — and that is why the wrapper can be so thin.

ViewScreenWhat it cannot get wrong
vista_por_aprobarTo approveApproving in bulk without saying how many and towards where
vista_historialHistoryShowing consented material and attribution-published material as equals
vista_archivoArchiveSending items through another source’s route
vista_fuentesFlowsDrawing in green something that was not tested
vista_altaAccount sign-upRetrying by itself forever
vista_programacionSchedulingSaying “active” by reading the configuration instead of the heartbeat
vista_rescateHistorical rescuePainting a rate-limit pause as if it were an error
vista_avisosNoticesShowing only what was delivered successfully

Why the rules live in the core and not in the template.

Every one of those rules is a decision that was hard to find, and several came out of an incident. If they lived in the .svelte file, the day the React wrapper exists they would have to be reimplemented — and one of them would get lost. They are in TypeScript, with a test each, so the port inherits the scars and not only the shape.

An example: a flow’s traffic light

It is the most important rule in the interface, and it fits in a diagram.

no

yes

no

yes

no

yes

no

yes

no

yes

would_emit

would_not_emit

uncertain

draw a connector

was the probe run?

AT REST state

verdict

does it have permission?

✗ no permission

is there a client

for that network?

✗ no client

is the route active?

⏸ disabled

is the destination active?

⏸ destination paused

? untested

✓ tested, emits

✗ N steps fail

? unconfirmed

Notice that no path on the left branch reaches green. With the data from the listing you can tell that something is broken, but not that it works: for that you have to ask the network. The best thing an untested flow says is “untested”. A green tick at rest would be a promise drawn exactly where people look most.

destino_activo === false, not !destino_activo. The panel and the service are different processes: during a deployment, the panel talks for a while to a version of the service that does not send that field yet. With the simple negation, that undefined would paint every flow as paused — and a false alarm on every deployment teaches people to ignore the alarm.