-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsend-interactions.ts
More file actions
66 lines (57 loc) · 2.19 KB
/
Copy pathsend-interactions.ts
File metadata and controls
66 lines (57 loc) · 2.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import express from 'express'
import { AppContext } from '../config'
import { validateAuth } from '../auth'
import { addSeen } from '../redis'
import { recordInteractions, REWARD_WEIGHTS, RewardRow } from '../interactions'
const SEEN_EVENT = 'app.bsky.feed.defs#interactionSeen'
// app.bsky.feed.sendInteractions — the AppView proxies client interaction
// events with the viewer's signed service JWT. interactionSeen drives the
// unseen-only feed; like/repost/requestMore/clickthrough/… and the negative
// requestLess are recorded with a signed weight in the interactions table as a
// durable reward signal for tuning. The reward signal is collected only — it
// does not yet feed back into ranking. Not in the bundled lexicon, so it's
// wired as a plain XRPC route.
export default function (app: express.Application, ctx: AppContext) {
app.post(
'/xrpc/app.bsky.feed.sendInteractions',
express.json({ limit: '500kb' }),
async (req, res) => {
let viewerDid: string | null = null
try {
viewerDid = await validateAuth(req, ctx.cfg.serviceDid, ctx.didResolver)
} catch {
viewerDid = null
}
const interactions = Array.isArray(req.body?.interactions)
? req.body.interactions
: []
if (viewerDid) {
const seen: string[] = []
const rewards: RewardRow[] = []
const now = new Date().toISOString()
for (const it of interactions) {
const event = it?.event
const item = it?.item
if (typeof event !== 'string' || typeof item !== 'string') continue
if (event === SEEN_EVENT) {
seen.push(item)
continue
}
const weight = REWARD_WEIGHTS[event]
if (weight === undefined) continue // non-reward / unknown event
rewards.push({
viewer_did: viewerDid,
subject_uri: item,
event,
weight,
created_at: now,
})
}
if (seen.length > 0) await addSeen(ctx.redis, viewerDid, seen)
if (rewards.length > 0) await recordInteractions(ctx.db, rewards)
}
// sendInteractions has an empty response body
res.json({})
},
)
}