Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Weft The book

Events from a service

A trigger that waits for a Slack message, a new row in a sheet, a page changing in Notion. The service has something to tell you, and there are two roads it can travel.

The two roads

Dial out. weft makes an authenticated call that hands back a socket address, connects out, and holds the line. Nothing needs to reach your machine, so this works from a laptop behind a router.

Dial in. The service posts each event to an address you published. That needs a public address, and it is the only road a shared application can use, and the only road most services offer at all.

You never choose. You name a connection and a filter, and the transport follows from what the service declares and what your environment can serve. On a cloud install, if the service can push these events for your account, weft takes the push, so nothing has to stay running between events. Otherwise weft dials out when it can, because that needs nothing from you.

What a topic declares

A service declares a map of topics, because one provider can genuinely report along several independent channels at once.

KeyWhat it says
fieldsThe named facts of one event, and where each lives in the payload. A dotted path, or header:X-Some-Header (a push that sends that header twice with two different values is refused)
accountWhich stored value names the account on a connection, and where the same id sits on an event. That pair is what routes a shared application’s events to the right connection
socketPresent when the service offers dial out
webhookPresent when the service dials in

Everything downstream works on the names. Subscriptions filter on them and triggers fan them out, so neither a filter nor a trigger node ever writes a provider’s path.

Receiving a push

A webhook topic declares how the provider’s pushes are handled:

KeyWhat it is
verifyHow a push is checked: hmac, signature (Ed25519 or ECDSA), oidc, or token_echo (the push carries back a token weft minted). For every key, go and read checking a signed request
handshakeThe one-off proof of ownership: echo a field from the body, echo a query parameter, or call a URL back
eventPathWhere the event sits inside the envelope
routeByaccount (the default: the event names the provider account) or subscription (it names an id weft minted when it subscribed)
idPathWhere a push carries the subscription id weft minted. Needed with routeBy: subscription, and with token_echo
tokenPathWhere a push carries the token weft minted. Needed with token_echo
decodeFor an event wrapped in base64 or a form encoding
subscribeThe calls that create, renew and cancel the subscription

The secret is never in the recipe. Every scheme is a protocol with holes, and the material comes from the operator’s application config, or from a token weft minted. That is what lets a recipe live in source.

What activation does

For a dial-in topic, the first subscribe happens then. So a missing public address or a provider refusing is that activation’s error, not a mystery three days later:

this trigger cannot be served on the 'slack' connection: the service declares
no transport for this topic

And the one you are most likely to meet:

this trigger needs 'slack' to deliver events TO your weft, which requires your
weft to be reachable from the internet, and it is not. If you accept making its
public trigger surface reachable, rerun `./setup.sh --public-url`, then `weft
activate`, or, when the trigger is already on, turn it off and on again
(`weft deactivate --trigger <name>`, then `weft activate --trigger <name>`);
or use a connection that supports dialing out (your own provider app), where the
service offers one. See https://weavemindai.github.io/weft/connections/events.html

A decision that a trigger cannot be served is final for that registration. Retrying would work out the same facts again. Reconnecting the account re-registers it and works them out afresh.

If a topic is not in the connection’s snapshot, the account predates it:

'slack' declares no event topic named 'reactions'; reconnect the account (an
older connection may predate the topic)

Renewal

Most providers expire a subscription. The recipe says the margin, and weft re-subscribes before the deadline.

A renewal is a fresh subscribe, with a new id and a new token, because the providers surveyed have no extend verb, and reusing the token would make the old and new channels impossible to tell apart.

If a topic declares no unsubscribe, deactivating cannot hurry it and the subscription lapses on its own expiry.

An application-wide subscription

Some apps want every install’s events rather than one account’s. That only works over dial out, because a push receiver routes each event to one account’s connections and could never deliver “every install of your app”.

an app-wide subscription only works over a dial-out transport, and this topic
declares none

Which triggers need a public address

Only the ones where the provider pushes. A timer, a poller, a socket weft dials out to and a form somebody fills in all work with nothing reachable from outside.

For the address itself, go and read a public address. For declaring a topic, go and read declaring a service.