Add listing functionality (#13)
* Ignore dist directory when formatting * Add list endpoint (`/`) * Document list endpoint
This commit is contained in:
parent
038f80db03
commit
9e34fb15e6
3 changed files with 76 additions and 12 deletions
1
.prettierignore
Normal file
1
.prettierignore
Normal file
|
|
@ -0,0 +1 @@
|
|||
dist/
|
||||
29
README.md
29
README.md
|
|
@ -102,10 +102,33 @@ erisa@Tuturu:~$ curl -X POST -H "Authorization: mysecret" https://erisa.link/ \
|
|||
}
|
||||
```
|
||||
|
||||
It is a planned feature to be able to list all URLs via a `GET` on `/` with `Authorization`.
|
||||
You can list all URLs by sending a `GET` to `/` (with the `Authorization` header set to your secret, of course).
|
||||
|
||||
For the time being you can view them from your Cloudflare Dashboard:
|
||||
Cloudflare Dashboard -> Workers -> KV -> View on the namespace.
|
||||
```json
|
||||
kot@Starry:~$ curl -H "Authorization: mysecret" "https://erisa.link/?prefix=%2F&limit=1"
|
||||
{
|
||||
"list_complete": false,
|
||||
"cursor": "AAAAAJhOXekucRAqut7Xs7Q2f09GCZyStWBfONvq6u5JP05Bg-z5FM5gf7krRaDrsvyxqfDuvFWUHIZp2n9OZ7Au92h-x68xwg8-bwerIoPd7fesG5w-ZB6f6oXopZHNXDCscmVUQ0OIaDEOx_6pruyEcCKfD3WpOstj6lO_sYJG_zQKdBgmYvLoMFQpK-cK7t8mCLWQA2t351xc9sJ08SM0JniY73t7bOdSxF3ADVTV6ihMSti0Z6svhpknfCn9VHjT",
|
||||
"links": [
|
||||
{
|
||||
"key": "/0031qr7q7"
|
||||
},
|
||||
{
|
||||
"key": "/00ybqita"
|
||||
},
|
||||
{
|
||||
"key": "/02ji9wlg"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The endpoint is paginated by default (1000/page). Just send `cursor` in the query string to access the next page.
|
||||
|
||||
You can set `limit` in the query string to `0` to retrieve all URLs.
|
||||
|
||||
You can also view URLs from your Cloudflare Dashboard:
|
||||
`Cloudflare Dashboard -> Workers -> KV -> View` on the namespace.
|
||||
|
||||
## Plausible Analytics
|
||||
|
||||
|
|
|
|||
54
src/index.ts
54
src/index.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { Context, Hono } from 'hono'
|
||||
import { Context as HonoContext, Env as HonoEnv, Hono } from 'hono'
|
||||
import * as st from 'simple-runtypes'
|
||||
|
||||
type Variables = {
|
||||
|
|
@ -9,6 +9,7 @@ type Variables = {
|
|||
|
||||
type Bindings = {
|
||||
WORKERLINKS_SECRET: string
|
||||
PLAUSIBLE_HOST?: string
|
||||
KV: KVNamespace
|
||||
kv: KVNamespace
|
||||
}
|
||||
|
|
@ -31,7 +32,18 @@ const bulkValidator = st.dictionary(
|
|||
url,
|
||||
)
|
||||
|
||||
const app = new Hono<{ Variables: Variables; Bindings: Bindings }>()
|
||||
const checkAuth = (c: Context) =>
|
||||
c.req.headers.get('Authorization') === c.env.WORKERLINKS_SECRET
|
||||
|
||||
const unauthorized = (c: Context) =>
|
||||
c.json({ code: '401 Unauthorized', message: 'Unauthorized' }, 401)
|
||||
|
||||
type Env = {
|
||||
Bindings: Bindings
|
||||
Variables: Variables
|
||||
}
|
||||
type Context = HonoContext<Env>
|
||||
const app = new Hono<Env>()
|
||||
|
||||
// store the path, key and short url for reference in requeests
|
||||
// e.g. c.get('key')
|
||||
|
|
@ -57,20 +69,48 @@ app.use('*', async (c, next) => {
|
|||
|
||||
// handle auth
|
||||
app.use('*', async (c, next) => {
|
||||
c.res.headers.set('Vary', 'Authorization')
|
||||
|
||||
if (c.env.WORKERLINKS_SECRET === undefined) {
|
||||
return c.text('Secret is not defined. Please add WORKERLINKS_SECRET.')
|
||||
}
|
||||
|
||||
if (
|
||||
!['GET', 'HEAD'].includes(c.req.method) &&
|
||||
c.req.headers.get('Authorization') !== c.env.WORKERLINKS_SECRET
|
||||
) {
|
||||
return c.json({ code: '401 Unauthorized', message: 'Unauthorized' }, 401)
|
||||
if (!['GET', 'HEAD'].includes(c.req.method) && !checkAuth(c)) {
|
||||
return unauthorized(c)
|
||||
}
|
||||
|
||||
await next()
|
||||
})
|
||||
|
||||
// retrieve list of keys
|
||||
app.get('/', async (c) => {
|
||||
if (c.req.header('Authorization')) {
|
||||
if (!checkAuth(c)) {
|
||||
return unauthorized(c)
|
||||
}
|
||||
|
||||
let { prefix, cursor, limit: limitStr } = c.req.query()
|
||||
prefix = prefix ? decodeURIComponent(prefix) : ''
|
||||
cursor = cursor ? decodeURIComponent(cursor) : ''
|
||||
let limit = limitStr ? parseInt(decodeURIComponent(limitStr)) : 1000
|
||||
|
||||
let { keys, ...list } = await c.env.KV.list({
|
||||
limit,
|
||||
prefix,
|
||||
cursor,
|
||||
})
|
||||
|
||||
return c.json({
|
||||
...list,
|
||||
links: keys.map((key) => ({
|
||||
key: key.name,
|
||||
})),
|
||||
})
|
||||
} else {
|
||||
return handleGetHead(c)
|
||||
}
|
||||
})
|
||||
|
||||
// retrieve key
|
||||
app.get('*', handleGetHead)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue