···
import { handler } from '#/lib/http'
import { ifString } from '#/lib/util'
import { page } from '#/lib/view'
-
import { home, STATUS_OPTIONS } from '#/pages/home'
import { login } from '#/pages/login'
type Session = { did?: string }
···
-
export function createRouter(ctx: AppContext): RequestListener {
-
router.use('/public', express.static(path.join(__dirname, 'pages', 'public')))
'/oauth-client-metadata.json',
handler((req: Request, res: Response) => {
res.json(ctx.oauthClient.clientMetadata)
···
'/.well-known/jwks.json',
handler((req: Request, res: Response) => {
res.json(ctx.oauthClient.jwks)
···
handler(async (req: Request, res: Response) => {
const params = new URLSearchParams(req.originalUrl.split('?')[1])
// Load the session cookie
···
handler(async (req: Request, res: Response) => {
return res.type('html').send(page(login({})))
···
handler(async (req: Request, res: Response) => {
const input = ifString(req.body.input)
return res.type('html').send(page(login({ error: 'invalid input' })))
···
handler(async (req: Request, res: Response) => {
const service = env.PDS_URL ?? 'https://bsky.social'
const url = await ctx.oauthClient.authorize(service, {
···
handler(async (req: Request, res: Response) => {
const session = await getIronSession<Session>(req, res, {
password: env.COOKIE_SECRET,
···
handler(async (req: Request, res: Response) => {
// If the user is signed in, get an agent which communicates with their server
const agent = await getSessionAgent(req, res, ctx)
···
return res.type('html').send(page(home({ statuses, didHandleMap })))
// Fetch additional information about the logged-in user
const profileResponse = await agent.com.atproto.repo
···
// Serve the logged-in view
···
handler(async (req: Request, res: Response) => {
// If the user is signed in, get an agent which communicates with their server
const agent = await getSessionAgent(req, res, ctx)
-
return res.redirect(`/login`)
-
const status = ifString(req.body?.status)
-
if (!status || !STATUS_OPTIONS.includes(status)) {
-
throw new Error('Invalid status')
// Construct & validate their status record
const rkey = TID.nextStr()
$type: 'xyz.statusphere.status',
createdAt: new Date().toISOString(),
if (!Status.validateRecord(record).success) {
···
.send('<h1>Error: Invalid status</h1>')
-
// Write the status record to the user's repository
const res = await agent.com.atproto.repo.putRecord({
collection: 'xyz.statusphere.status',
···
···
import { handler } from '#/lib/http'
import { ifString } from '#/lib/util'
import { page } from '#/lib/view'
+
import { home } from '#/pages/home'
import { login } from '#/pages/login'
+
const MAX_AGE = env.NODE_ENV === 'production' ? 60 : 0
type Session = { did?: string }
···
+
export const createRouter = (ctx: AppContext): RequestListener => {
+
express.static(path.join(__dirname, 'pages', 'public'), {
+
maxAge: MAX_AGE * 1000,
'/oauth-client-metadata.json',
handler((req: Request, res: Response) => {
+
res.setHeader('cache-control', `max-age=${MAX_AGE}, public`)
res.json(ctx.oauthClient.clientMetadata)
···
'/.well-known/jwks.json',
handler((req: Request, res: Response) => {
+
res.setHeader('cache-control', `max-age=${MAX_AGE}, public`)
res.json(ctx.oauthClient.jwks)
···
handler(async (req: Request, res: Response) => {
+
res.setHeader('cache-control', 'no-store')
const params = new URLSearchParams(req.originalUrl.split('?')[1])
// Load the session cookie
···
handler(async (req: Request, res: Response) => {
+
res.setHeader('cache-control', `max-age=${MAX_AGE}, public`)
return res.type('html').send(page(login({})))
···
handler(async (req: Request, res: Response) => {
+
res.setHeader('cache-control', 'no-store')
const input = ifString(req.body.input)
return res.type('html').send(page(login({ error: 'invalid input' })))
+
// @NOTE "input" can be a handle, a DID or a service URL (PDS).
+
// Initiate the OAuth flow
+
const url = await ctx.oauthClient.authorize(input, {
+
scope: 'atproto transition:generic',
+
res.redirect(url.toString())
+
ctx.logger.error({ err }, 'oauth authorize failed')
+
err instanceof OAuthResolverError
+
: "couldn't initiate login"
+
return res.type('html').send(page(login({ error })))
···
handler(async (req: Request, res: Response) => {
+
res.setHeader('cache-control', `max-age=${MAX_AGE}, public`)
const service = env.PDS_URL ?? 'https://bsky.social'
const url = await ctx.oauthClient.authorize(service, {
···
handler(async (req: Request, res: Response) => {
+
// Never store this route
+
res.setHeader('cache-control', 'no-store')
const session = await getIronSession<Session>(req, res, {
password: env.COOKIE_SECRET,
···
handler(async (req: Request, res: Response) => {
+
// Prevent caching of this page when the credentials change
+
res.setHeader('Vary', 'Cookie')
// If the user is signed in, get an agent which communicates with their server
const agent = await getSessionAgent(req, res, ctx)
···
return res.type('html').send(page(home({ statuses, didHandleMap })))
+
// Make sure this page does not get cached in public caches (proxies)
+
res.setHeader('cache-control', 'private')
// Fetch additional information about the logged-in user
const profileResponse = await agent.com.atproto.repo
···
// Serve the logged-in view
+
.send(page(home({ statuses, didHandleMap, profile, myStatus })))
···
handler(async (req: Request, res: Response) => {
+
// Never store this route
+
res.setHeader('cache-control', 'no-store')
// If the user is signed in, get an agent which communicates with their server
const agent = await getSessionAgent(req, res, ctx)
+
.send('<h1>Error: Session required</h1>')
// Construct & validate their status record
const rkey = TID.nextStr()
$type: 'xyz.statusphere.status',
+
status: req.body?.status,
createdAt: new Date().toISOString(),
+
// Make sure the record generated from the input is valid
if (!Status.validateRecord(record).success) {
···
.send('<h1>Error: Invalid status</h1>')
+
// Write the status record to the user's repository
const res = await agent.com.atproto.repo.putRecord({
collection: 'xyz.statusphere.status',
···
+
return res.redirect('/')