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:
|
```json
|
||||||
Cloudflare Dashboard -> Workers -> KV -> View on the namespace.
|
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
|
## Plausible Analytics
|
||||||
|
|
||||||
|
|
|
||||||
58
src/index.ts
58
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'
|
import * as st from 'simple-runtypes'
|
||||||
|
|
||||||
type Variables = {
|
type Variables = {
|
||||||
|
|
@ -9,6 +9,7 @@ type Variables = {
|
||||||
|
|
||||||
type Bindings = {
|
type Bindings = {
|
||||||
WORKERLINKS_SECRET: string
|
WORKERLINKS_SECRET: string
|
||||||
|
PLAUSIBLE_HOST?: string
|
||||||
KV: KVNamespace
|
KV: KVNamespace
|
||||||
kv: KVNamespace
|
kv: KVNamespace
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +32,18 @@ const bulkValidator = st.dictionary(
|
||||||
url,
|
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
|
// store the path, key and short url for reference in requeests
|
||||||
// e.g. c.get('key')
|
// e.g. c.get('key')
|
||||||
|
|
@ -57,20 +69,48 @@ app.use('*', async (c, next) => {
|
||||||
|
|
||||||
// handle auth
|
// handle auth
|
||||||
app.use('*', async (c, next) => {
|
app.use('*', async (c, next) => {
|
||||||
|
c.res.headers.set('Vary', 'Authorization')
|
||||||
|
|
||||||
if (c.env.WORKERLINKS_SECRET === undefined) {
|
if (c.env.WORKERLINKS_SECRET === undefined) {
|
||||||
return c.text('Secret is not defined. Please add WORKERLINKS_SECRET.')
|
return c.text('Secret is not defined. Please add WORKERLINKS_SECRET.')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (!['GET', 'HEAD'].includes(c.req.method) && !checkAuth(c)) {
|
||||||
!['GET', 'HEAD'].includes(c.req.method) &&
|
return unauthorized(c)
|
||||||
c.req.headers.get('Authorization') !== c.env.WORKERLINKS_SECRET
|
|
||||||
) {
|
|
||||||
return c.json({ code: '401 Unauthorized', message: 'Unauthorized' }, 401)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await next()
|
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
|
// retrieve key
|
||||||
app.get('*', handleGetHead)
|
app.get('*', handleGetHead)
|
||||||
|
|
||||||
|
|
@ -84,7 +124,7 @@ async function handleGetHead(c: Context) {
|
||||||
|
|
||||||
if (urlResult == null) {
|
if (urlResult == null) {
|
||||||
return c.json(
|
return c.json(
|
||||||
{ code: '404 Not Found', message: ' Key does not exist.' },
|
{ code: '404 Not Found', message: 'Key does not exist.' },
|
||||||
404,
|
404,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -108,7 +148,7 @@ app.delete('*', async (c) => {
|
||||||
|
|
||||||
if (urlResult == null) {
|
if (urlResult == null) {
|
||||||
return c.json(
|
return c.json(
|
||||||
{ code: '404 Not Found', message: ' Key does not exist.' },
|
{ code: '404 Not Found', message: 'Key does not exist.' },
|
||||||
404,
|
404,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue