figbus/elm-urbit-api/3.0.0

NOTE: the latest version is 4.0.1

Urbit

Data Types

type Session

A session represents an active connection to an urbit ship.

url : Session -> String

Get a Session's url.

Get a Session's ship.

uid : Session -> String

Get a Session's uid.

Get a Session's lastEventId.

type alias InMsg =
{ lastEventId : Int
, data : InMsgData
}

Represents an incoming message.

= Poke Int (Result String ())
| Subscribe Int (Result String ())
| Diff Int Value
| Quit Int

An incoming message may be one of the following:

  • Poke represents a response for a previous poke
  • Subscribe represents a response for a subscription requests
  • Diff represents a new incoming diff for a subscription
  • Quit means you have been kicked from a subscription and should likely attempt to resubscribe

In all cases the first Int value represents the Id of the message it is relevant to.

type OutMsg

Represents an outgoing message.

Connection Setup

These are required in order to maintain an active connection to an urbit ship and to perform poke/subscription requests.

{ ship : Atom
, url : String
, channelId : String
, code : String
}
-> (Result Error Session -> msg)
-> Cmd msg

Connect to an urbit ship and return a Session on success. Should be followed by setupEventSource (this must be done as a separate step due to the nature of Elm ports).

You can generate a unique channelId any way you wish, however the provided genChannelId function is recommended.

{ ship : Atom
, url : String
, channelId : String
}
-> (Result Error Session -> msg)
-> Cmd msg

Alternative to connect that does not require a code.

Note: Ensure the correct cookie is set through some other means beforehand or else this will not work. Hosting from within an urbit using the :file-server app with public set to false should work, for example.

setupEventSource : (String -> Cmd msg) -> Session -> Cmd msg

This will set up the realtime communication channel with urbit. Because Elm does not support the EventSource API required, this must be done using ports. Elm does not allow ports to be published as part of a package, but luckily the setup for this is fairly straightforward.

First, copy/paste the following into your js file and replace any references to app with the variable name of your running Elm app:

app.ports.setupUrbitEventSource.subscribe((url) => {
  const eventSource = new EventSource(url, { withCredentials: true });

  eventSource.onmessage = function (event) {
    app.ports.onUrbitMessage.send({ message: event });
  };

  eventSource.onerror = function (event) {
    app.ports.onUrbitMessage.send({ error: event });
  };
});

Next, declare a port module and the following ports to handle the initial setup and incoming messages:

port setupUrbitEventSource : String -> Cmd msg


port onUrbitMessage : (JE.Value -> msg) -> Sub msg

Now, the newly created setupUrbitEventSource can be passed as the first argument to our setupEventSource function and used to perform the necessary setup. Similarly, the onUrbitMessage function can be passed as the first argument to messages below to set up the subscription to incoming events.

setupCommand =
    Urbit.setupEventSource setupUrbitEventSource session


messagesSubscription =
    Urbit.messages onUrbitMessage GotUrbitMessage

See the Elm guide for further information regarding ports.

messages : ((Value -> msg) -> Sub msg) -> (Result Error InMsg -> msg) -> Sub msg

Subscribe to incoming messages from urbit. See setupEventSource above for instructions on how to use this. Every message received must be acknowledged by using the related ack function, otherwise urbit will stop accepting any further messages.

ack : Int -> OutMsg

Acknowledge an incoming message by its Id. Must be performed for every incoming message received.

Stateful Requests

{ ship : Atom
, app : String
, mark : String
, json : Value
}
-> OutMsg

Poke an app on a ship.

{ ship : Atom
, app : String
, path : String
}
-> OutMsg

Subscribe to ship events on some path.

Unsubscribe from an existing subscription by its Id.

Safely deletes a channel.

send : Session -> (Result Error () -> msg) -> OutMsg -> ( Session, Cmd msg )

Sends an outgoing message to urbit. Returns a tuple of a new session and the command.

-> (Result Error () -> msg)
-> List OutMsg
-> ( Session, Cmd msg )

Sends multiple outgoing messages to urbit in one request. Returns a tuple of a new session and the command.

sendTask : Session -> OutMsg -> ( Session, Task Error () )

Sends an outgoing message to urbit as a task. Returns a tuple of a new session and the task.

sendBatchTask : Session -> List OutMsg -> ( Session, Task Error () )

Sends multiple outgoing messages to urbit in one request as a task. Returns a tuple of a new session and the task.

Stateless Requests

These do not require an active connection, however they do at least require you to be authenticated.

{ url : String
, code : String
}
-> (Result Error () -> msg)
-> Cmd msg

Login to an urbit without maintaining an active connection. This will allow for stateless scry and spider requests that require authentication, but not others.

Note: This is not required if you have already used connect to authenticate.

{ url : String
, app : String
, path : String
, mark : String
, decoder : Decoder a
}
-> (Result Error a -> msg)
-> Cmd msg

Make a scry request.

{ url : String
, inputMark : String
, outputMark : String
, threadName : String
, body : Value
, decoder : Decoder output
}
-> (Result Error output -> msg)
-> Cmd msg

Start a thread and get the response.

Helpers

genChannelId : Posix -> Generator String

Recommended way to create a unique id for a session's channel. Takes the current time and returns a random generator which can then be used to generate the full ID.