Files
dev/docs/02 notes/falinks public surfaces.md

194 lines
8.7 KiB
Markdown

---
date-created: 2026-08-31 21:32
---
# Falinks Public Surfaces
The project has two components:
- `Falinks`: the library to resolve short links to fully qualified domain names.
- `falinks` cli:
- Non-interactive (use for one off requests or by agents)
- Interactive mode (REPL-style)
- Daemon: running in the background, can be used through unix domain sockets (or another inter-process communication)
- Web server: serves browser requests, including the special `/` management page and 404 page.
The `falinks` CLI should have very light logic (if any) related to short links.
It should be focused on being the front end(s) that uses the library.
`falinks` will use [[machoke]] for the storage layer.
## Design
### `Falinks` public interface
| Method | Parameters | Returns | Description |
| --------------- | --------------------------------- | ----------------------------- | ------------------------------------------------------- |
| `<constructor>` | `falinks::Options` | `Falinks` | Creates the stateful object. See [[falinks public surfaces#falinks::Options]] |
| `get` | `short_link: String` | `Result<String>` | Returns the `url` stored for `short_link` if it exists. |
| `set` | `short_link: String, url: String` | `Result<()>` | Stores `url` with `short_link` key. |
| `delete` | `short_link: String` | `Result<bool>` | Deletes the entry for `<short_link>`. |
| `list` | | `Result<Vec<falinks::Entry>>` | Retrieves all stored, raw values. |
#### falinks::Options
| Key | Type | Default | Description |
| ------------- | ---------------------- | ------- | ------------------------------------------------------------------------------ |
| `socket_path` | `std::path::PathBuf` | | The path for the Unix Domain Socket. Implicitly starts the daemon. |
| `listen_addr` | `std::net::SocketAddr` | | The address for the web server to listen on. Implicitly starts the web server. |
| `store` | `std::path::PathBuf` | tbd | The path to read/write the store. Passed to [[machoke]]. |
#### falinks::Error
- `NotFound`: no entry exists for the provided `<prefix>/<short_link>`.
- `InvalidShortLink`: the provided short link could not be resolved.
- `InvalidUrl`: the target URL is not valid.
- `Store`: [[machoke]] failed while reading or writing the store. Maybe treat this as an "external" error?
#### falinks::Entry
| Field | Type | Description |
| -------------- | -------- | -------------------------------------------------------------------------------------------- |
| `prefix` | `String` | The namespace for the short link. |
| `short_link` | `String` | The short link key. It can contain `/`. |
| `url` | `String` | The target URL. |
| `visit_count` | `u64` | Successful `get` operations increment `visit_count`. |
| `last_used` | `u64` | Unix timestamp in seconds. Successful `get` operations update `last_used`. |
| `last_updated` | `u64` | Unix timestamp in seconds of when the entry was last updated. Metadata updates do not count. |
### `falinks` CLI
| Command | Description |
| -------------------------------------- | ------------------------------------------------------------------------------------- |
| `falinks` | Launches `falinks` interactive mode. |
| `falinks list` | Will return all stored URLs and keys, along with metadata like visit count. |
| `falinks get <short_link>` | Resolve the short link into a URL. See [[falinks public surfaces#Resolving short links]]. |
| `falinks set <short_link> <url>` | Store the `<url>` with `<short_link>` key. `<short_link>` still needs to be resolved. |
| `falinks delete <short_link>` | Delete the entry that matches `<short_link>`. |
| `falinks start [--config-path <path>]` | Starts the daemon, web server or both as configured. See [[falinks public surfaces#falinks::Options]]. |
| `falinks stop` | Stops the running daemon. |
#### Global Flags
| Flag | Description |
| ----------- | --------------------------------------------- |
| `--help` | Prints the help text. |
| `--version` | Prints version information. |
| `--json` | Turns all output and errors machine-readable. |
#### JSON payloads
All JSON command responses must include `ok`.
`--json` does not affect `--help` or `--version`.
> [!info] Successful List
> ```json
> {
> "ok": true,
> "entries": [
> {
> "prefix": "fa",
> "short_link": "home/plex",
> "url": "https://plex.example.com",
> "visit_count": 12,
> "last_used": 1788210000,
> "last_updated": 1788200000
> }
> ]
> }
> ```
> [!info] Successful `get`
> ```json
> {
> "ok": true,
> "url": "https://example.com"
> }
> ```
> [!info] Successful `set`
> ```json
> {
> "ok": true
> }
> ```
> [!info] Successful `delete`
> ```json
> {
> "ok": true,
> "deleted": true
> }
> ```
> [!info] Successful `start`
> ```json
> {
> "ok": true,
> "pid": 1234
> }
> ```
> [!info] Successful `stop`
> ```json
> {
> "ok": true
> }
> ```
> [!info] Error response
> ```json
> {
> "ok": false,
> "error": {
> "code": "not_found",
> "message": "no entry exists for fa/home/plex"
> }
> }
> ```
See [[falinks public surfaces#falinks::Error]] for more details on the variants.
### `falinks` daemon IPC
Daemon IPC uses newline-delimited JSON over the Unix Domain Socket.
Each request and response is one JSON object followed by a newline.
Requests mirror the CLI commands:
```json
{"command":"get","short_link":"fa/home/plex"}
{"command":"set","short_link":"fa/home/plex","url":"https://plex.example.com"}
{"command":"delete","short_link":"fa/home/plex"}
{"command":"list"}
{"command":"stop"}
```
Responses use the same payload shapes as `falinks --json`.
See [[falinks public surfaces#JSON payloads]].
### `falinks` web server
| Request | Return Code | | Description |
| --------------------------------------------------- | ----------- | ----------------- | ------------------------------------------------------------------------------ |
| `GET <prefix>/` | `200` | Falinks Dashboard | The web dashboard to manage `falinks`. All prefixes return the same dashboard. |
| `GET <prefix>/<short_link>` | `307` | `<url>` | Returns a temporary redirect to the stored `<url>` |
| | `404` | 404 Page | If the `<prefix>/<short_link>` entry was not found. |
| `POST <prefix>/<short_link> body: {"url": "<url>"}` | `201` | | Creates the `<prefix>/<short_link>` entry for `<url>` |
| `DELETE <prefix>/<short_link>` | `200` | | Deletes the `<prefix>/<short_link>` entry. |
| | `204` | | No entry found for `<prefix>/<short_link>` |
### Resolving short links
`[{http | https}://]<prefix>/<short_link>`
- The presence of either `http://` or `https://` indicates this short link should be resolved through the machine's DNS. Otherwise, it will be resolved through the daemon on the machine.
- `<prefix>` can technically be anything, the library will support that. But I will only use `go` or `fa` (to be decided). Prefixes do not share keys.
- `<short_link>` can be nested (`home/plex`), although it has no semantic meaning.