Prerequisites [#prerequisites]
Before starting, make sure we have:
* [**Bun**](https://bun.sh/) installed
* **Orbitport API credentials** — a client ID and client secret. If we don't have them yet, let's follow the [Authentication guide](/docs/how-to/authentication) to create an account at accounts.spacecomputer.io.
Set up the project [#set-up-the-project]
```bash
mkdir decision-picker && cd decision-picker
bun add @spacecomputer-io/orbitport-sdk-ts react react-dom @types/react @types/react-dom @types/bun
```
Create a `.env` file with our credentials from the [Authentication guide](/docs/how-to/authentication):
```bash title=".env"
ORBITPORT_CLIENT_ID=your_client_id
ORBITPORT_CLIENT_SECRET=your_client_secret
```
Create the app [#create-the-app]
The whole project is two files: a server that handles the API and serves a React page.
Let's start with Bun. Bun is amazing because it runs typescript natively on its own engine, and even provides an HTTP server. Perfect for a simple project that will decide the fate of my dinner tonight.
`server.tsx` — API + static server [#servertsx--api--static-server]
So here's the plan: our API credentials must stay server-side. We'll use Bun's built-in HTTP server to expose an `/api/decide` endpoint that calls the Orbitport SDK, and serve our React app as a static bundle.
```tsx title="server.tsx"
import { OrbitportSDK } from "@spacecomputer-io/orbitport-sdk-ts";
// we instantiate the SDK here
const sdk = new OrbitportSDK({
config: {
clientId: process.env.ORBITPORT_CLIENT_ID,
clientSecret: process.env.ORBITPORT_CLIENT_SECRET,
},
});
// and build the actual page we will show: more on that in the next file
const build = await Bun.build({ entrypoints: ["./app.tsx"] });
const appJs = await build.outputs[0]!.text();
// REST service, yey
Bun.serve({
port: 3000,
async fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/api/decide") {
// from the initialized cTRNG, we want the seed and the source so we can show on the frontend
const { data: { data: seed, src: source } } = await sdk.ctrng.random();
// it's a bit ugly, but this just maps the seed value into either 0 or 1
const pick = parseInt(seed.slice(0, 4), 16) % 2
return Response.json({ pick, seed, source });
}
if (url.pathname === "/app.js")
return new Response(appJs, { headers: { "Content-Type": "application/javascript" } });
return new Response(``, {
headers: { "Content-Type": "text/html" },
});
},
});
console.log("http://localhost:3000");
```
The SDK handles authentication automatically based on the contents of `.env`. It requests an OAuth2 token, caches it, and refreshes it when needed.
The `seed` is a hex string of random bytes from the satellite. We take the first two bytes, convert to a number, and modulo 2 gives us 0 or 1. The frontend maps that to whichever options the user typed in.
Can't decide? Let a satellite pick for you.
{[optionA, optionB][result.pick]}
seed: {result.seed} · source: {result.source}
> )}