mirror of
https://github.com/narrrl/narl-workspace.git
synced 2026-11-03 16:41:27 +01:00
capture: a token writes down from outside the browser
POST /api/capture takes a line of text and puts it on a card in an inbox, or at the end of today's diary entry, starting the entry when there is none yet. It answers a logged-in browser, and also a request that carries an Authorization: Bearer token from :token add, so a phone shortcut, a script or curl can capture with no tab open. A token is nwc_ and 32 random bytes. It is shown once, copied, and stored only as its SHA-256, the way a share key is. Only the capture route reads the header. The Session extractor never does, so a token opens nothing else. Wrong tokens go through the login's backoff on a throttle of their own. A removed token is refused from the next request on, because each capture looks the hash up again. A card lands where :card puts one outside the board: the inbox of the space named by "space", or else of the first space with a board. That rule now lives server-side as boards::inbox_of. The first line of the text becomes the title and the rest becomes the notes. Diary text becomes "- HH:MM text" in WORKSPACE_TIMEZONE, appended to the first document written today at the top of the diary. That is the entry :today opens. The append keeps a revision and indexes links like any other save. :token lists, adds and removes tokens, and completes their names after rm. The message that shows a new token stays in the status bar instead of fading, because it cannot be shown again.
This commit is contained in:
1 parent
a42f9074a2
commit
f629f5af97
13 files changed
+758
-9
No files matched your search
@@ -125,7 +125,8 @@ list (`:bn` and `:bp` walk the tiles), `:delete [id]` deletes, `:copy` puts the
|
||||
`:clear` drops the search, `:trash` lists what was deleted, `:reload` re-reads the folder, `:stats` counts words
|
||||
and lines, `:search!` searches every space, `:set clipboard` / `:set
|
||||
noclipboard` mirrors vim yanks to the system clipboard, `:logout` ends the
|
||||
session, `:logout!` every session and `:sessions rm <n>` one other. The tree has its own: `:space [name]` switches (`:space! <name>`
|
||||
session, `:logout!` every session and `:sessions rm <n>` one other, and
|
||||
`:token` manages the tokens that capture from outside (see below). The tree has its own: `:space [name]` switches (`:space! <name>`
|
||||
makes one, `:rmspace [name]` puts one in the trash with everything in it), `:mkdir <name>`
|
||||
makes a folder, `:cd <name|..|/>` walks it and `:mv <folder|..|/>` moves what is
|
||||
selected, and `:import` uploads a folder into the one being browsed
|
||||
@@ -241,6 +242,41 @@ the list left / right on its board, and `T` writes today's entry. The bar shows
|
||||
whenever either is above zero, and the agenda opens by itself once a day when
|
||||
something is late or due, so nothing has to be remembered to be looked at.
|
||||
|
||||
## Capturing from elsewhere
|
||||
|
||||
A thought arrives when no tab is open. `POST /api/capture` writes it down from
|
||||
anything that can send a request — a phone shortcut, a script, `curl` — with a
|
||||
token in place of a session:
|
||||
|
||||
```text
|
||||
:token add phone makes one, shows it once and copies it
|
||||
:token lists them, with when each was last used
|
||||
:token rm phone and that one captures nothing from the next request on
|
||||
```
|
||||
|
||||
```sh
|
||||
curl -H "Authorization: Bearer nwc_…" -H 'content-type: application/json' \
|
||||
-d '{"text":"call the bank"}' https://your-host/api/capture
|
||||
```
|
||||
|
||||
`"to": "card"`, the default, puts a card in an inbox: the one of the space
|
||||
named by `"space": "<slug>"`, or else of the first space that has a board,
|
||||
the same as `:card` outside the board. The first line is the card's title and
|
||||
the rest its notes. `"to": "diary"` adds `- 14:05 call the bank` to the end of
|
||||
today's entry, in `WORKSPACE_TIMEZONE`, and starts the entry when there is
|
||||
none yet. The answer says where it went: `{"to":"card","id":7,"where":"work/backlog"}`.
|
||||
|
||||
A token opens this one route and nothing else — it reads nothing, not even the
|
||||
list of spaces — and only its SHA-256 is kept, the way a share key is. Wrong
|
||||
tokens slow down like wrong passwords, on a line of their own, so guessing at
|
||||
them does not hold up the login.
|
||||
|
||||
On an iPhone, a Shortcut with *Ask for Input* followed by *Get Contents of
|
||||
URL* does it: method `POST`, a header `Authorization` of `Bearer nwc_…`, and a
|
||||
JSON body with `text` set to the input. On Android, *HTTP Shortcuts* does the
|
||||
same with a text-input variable in the body. Either one goes on the home
|
||||
screen, or behind the share sheet.
|
||||
|
||||
## Not losing things
|
||||
|
||||
Every change is written to `localStorage` as it is typed and to the server a
|
||||
@@ -689,7 +725,7 @@ both halves.
|
||||
## API
|
||||
|
||||
Everything except the login, the health check and the two share routes
|
||||
requires the session cookie. Media answers `Range` requests, so a video seeks,
|
||||
requires the session cookie; `/api/capture` takes a token instead. Media answers `Range` requests, so a video seeks,
|
||||
sealed or not.
|
||||
|
||||
| method | path | purpose |
|
||||
@@ -707,6 +743,9 @@ sealed or not.
|
||||
| `POST` | `/api/trash/{id}/restore` | back where it was deleted from, or to its space when that folder is gone |
|
||||
| `GET` | `/api/spaces/{id}/board` | the lists and cards of one space |
|
||||
| `GET` | `/api/agenda` | open cards due within a week or in hand, on every board, and whether the diary has today |
|
||||
| `POST` | `/api/capture` | `{ text, to: "card" \| "diary", space? }`, with a session or `Authorization: Bearer` a token |
|
||||
| `GET`/`POST` | `/api/tokens` | the capture tokens / make one, `{ name }`, answered with the token this once |
|
||||
| `DELETE` | `/api/tokens/{id}` | remove a capture token |
|
||||
| `POST` | `/api/spaces/{id}/lists` | add a list |
|
||||
| `PUT`/`DELETE` | `/api/lists/{id}` | rename / delete a list and its cards |
|
||||
| `POST` | `/api/lists/{id}/cards` | add a card |
|
||||
|
||||
Reference in new issue
Block a user