···
export function createRouter(ctx: AppContext): RequestListener {
-
app.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)
···
// OAuth callback to complete session creation
handler(async (req: Request, res: Response) => {
const params = new URLSearchParams(req.originalUrl.split('?')[1])
···
session.did = oauth.session.did
-
if (oauth.state?.startsWith('status:')) {
-
const status = oauth.state.slice(7)
-
const agent = new Agent(oauth.session)
-
await updateStatus(agent, status)
-
const message = err instanceof Error ? err.message : 'Unknown error'
-
return res.redirect(`/?error=${encodeURIComponent(message)}`)
// Redirect to the homepage
···
handler((req: Request, res: Response) => {
-
const state = ifString(req.query.state)
-
res.type('html').send(page(login({ state })))
express.urlencoded({ extended: true }),
handler(async (req: Request, res: Response) => {
const input = ifString(req.body.input)
-
const state = ifString(req.body.state)
-
.send(page(login({ error: 'invalid input' })))
// Initiate the OAuth flow
const url = await ctx.oauthClient.authorize(input, {
scope: 'atproto transition:generic',
res.redirect(url.toString())
···
: "couldn't initiate login"
-
res.type('html').send(page(login({ state, error })))
handler(async (req: Request, res: Response) => {
const service = env.PDS_URL ?? 'https://bsky.social'
const url = await ctx.oauthClient.authorize(service, {
scope: 'atproto transition:generic',
-
state: ifString(req.query.state),
res.redirect(url.toString())
···
handler(async (req: Request, res: Response) => {
const session = await getIronSession<Session>(req, res, {
···
handler(async (req: Request, res: Response) => {
const error = ifString(req.query.error)
···
// Serve the logged-out view
-
.send(page(home({ error, statuses, didHandleMap })))
// Fetch additional information about the logged-in user
···
express.urlencoded({ extended: true }),
handler(async (req: Request, res: Response) => {
-
const status = req.body?.status
// If the user is signed in, get an agent which communicates with their server
const agent = await getSessionAgent(req, res, ctx)
-
return void res.redirect(
-
`/login?state=status:${encodeURIComponent(status)}`,
-
await updateStatus(agent, status)
-
return res.redirect('/')
const message = err instanceof Error ? err.message : 'Unknown error'
-
return res.redirect(`/?error=${encodeURIComponent(message)}`)
-
async function updateStatus(agent: Agent, status: unknown) {
-
if (typeof status !== 'string' || !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) {
-
throw new Error('Invalid status record')
-
// Write the status record to the user's repository
-
const res = await agent.com.atproto.repo
-
collection: 'xyz.statusphere.status',
-
ctx.logger.error({ err }, 'failed to write record')
-
throw new Error('Failed to write record', { cause: err })
-
// Optimistically update our SQLite
-
// This isn't strictly necessary because the write event will be
-
// handled in #/firehose/ingestor.ts, but it ensures that future reads
-
// will be up-to-date after this method finishes.
-
authorDid: agent.assertDid,
-
createdAt: record.createdAt,
-
indexedAt: new Date().toISOString(),
-
'failed to update computed view; ignoring as it should be caught by the firehose',
···
export function createRouter(ctx: AppContext): RequestListener {
+
const router = express()
+
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)
···
// OAuth callback to complete session creation
handler(async (req: Request, res: Response) => {
const params = new URLSearchParams(req.originalUrl.split('?')[1])
···
session.did = oauth.session.did
// Redirect to the homepage
···
handler((req: Request, res: Response) => {
+
res.type('html').send(page(login({})))
express.urlencoded({ extended: true }),
handler(async (req: Request, res: Response) => {
const input = ifString(req.body.input)
+
res.type('html').send(page(login({ error: 'invalid input' })))
// Initiate the OAuth flow
const url = await ctx.oauthClient.authorize(input, {
scope: 'atproto transition:generic',
res.redirect(url.toString())
···
: "couldn't initiate login"
+
res.type('html').send(page(login({ error })))
handler(async (req: Request, res: Response) => {
const service = env.PDS_URL ?? 'https://bsky.social'
const url = await ctx.oauthClient.authorize(service, {
scope: 'atproto transition:generic',
res.redirect(url.toString())
···
handler(async (req: Request, res: Response) => {
const session = await getIronSession<Session>(req, res, {
···
handler(async (req: Request, res: Response) => {
const error = ifString(req.query.error)
···
// Serve the logged-out view
+
res.type('html').send(page(home({ error, statuses, didHandleMap })))
// Fetch additional information about the logged-in user
···
express.urlencoded({ extended: true }),
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)
+
res.redirect(`/login}`)
+
const status = req.body?.status
+
if (typeof status !== 'string' || !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) {
+
res.status(400).type('html').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',
+
ctx.logger.error({ err }, 'failed to write record')
+
.send('<h1>Error: Failed to write record</h1>')
+
// Optimistically update our SQLite
+
// This isn't strictly necessary because the write event will be
+
// handled in #/firehose/ingestor.ts, but it ensures that future reads
+
// will be up-to-date after this method finishes.
+
authorDid: agent.assertDid,
+
createdAt: record.createdAt,
+
indexedAt: new Date().toISOString(),
+
'failed to update computed view; ignoring as it should be caught by the firehose',
const message = err instanceof Error ? err.message : 'Unknown error'
+
res.redirect(`/?error=${encodeURIComponent(message)}`)