forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import assert from 'node:assert'
2
3import {DAY, SECOND} from '@atproto/common'
4import {Express} from 'express'
5
6import {AppContext} from '../context.js'
7import {handler} from './util.js'
8
9export default function (ctx: AppContext, app: Express) {
10 return app.get(
11 '/:linkId',
12 handler(async (req, res) => {
13 const linkId = req.params.linkId
14 const contentType = req.accepts(['html', 'json'])
15 assert(
16 typeof linkId === 'string',
17 'express guarantees id parameter is a string',
18 )
19 const found = await ctx.db.db
20 .selectFrom('link')
21 .selectAll()
22 .where('id', '=', linkId)
23 .executeTakeFirst()
24 if (!found) {
25 // potentially broken or mistyped link
26 res.setHeader('Cache-Control', 'no-store')
27 if (contentType === 'json') {
28 return res
29 .status(404)
30 .json({
31 error: 'NotFound',
32 message: 'Link not found',
33 })
34 .end()
35 }
36 // send the user to the app
37 res.setHeader('Location', `https://${ctx.cfg.service.appHostname}`)
38 return res.status(302).end()
39 }
40 // build url from original url in order to preserve query params
41 const url = new URL(
42 req.originalUrl,
43 `https://${ctx.cfg.service.appHostname}`,
44 )
45 url.pathname = found.path
46 res.setHeader('Cache-Control', `max-age=${(7 * DAY) / SECOND}`)
47 if (contentType === 'json') {
48 return res.json({url: url.href}).end()
49 }
50 res.setHeader('Location', url.href)
51 return res.status(301).end()
52 }),
53 )
54}