parent
da8f055816
commit
e6471a7419
lexicons/app/bsky
packages
api/src/client
pds/src
db
lexicon
24
lexicons/app/bsky/feed/trend.json
Normal file
24
lexicons/app/bsky/feed/trend.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"lexicon": 1,
|
||||
"id": "app.bsky.feed.trend",
|
||||
"type": "record",
|
||||
"key": "tid",
|
||||
"record": {
|
||||
"type": "object",
|
||||
"required": ["subject", "createdAt"],
|
||||
"properties": {
|
||||
"subject": {"$ref": "#/defs/subject"},
|
||||
"createdAt": {"type": "string", "format": "date-time"}
|
||||
}
|
||||
},
|
||||
"defs": {
|
||||
"subject": {
|
||||
"type": "object",
|
||||
"required": ["uri", "cid"],
|
||||
"properties": {
|
||||
"uri": {"type": "string"},
|
||||
"cid": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"$comment": "Expected values are 'vote', 'repost', 'follow', 'invite', 'mention' and 'reply'."
|
||||
"$comment": "Expected values are 'vote', 'repost', 'trend', 'follow', 'invite', 'mention' and 'reply'."
|
||||
},
|
||||
"reasonSubject": {"type": "string"},
|
||||
"record": {"type": "object"},
|
||||
|
@ -44,6 +44,7 @@ import * as AppBskyFeedMediaEmbed from './types/app/bsky/feed/mediaEmbed'
|
||||
import * as AppBskyFeedPost from './types/app/bsky/feed/post'
|
||||
import * as AppBskyFeedRepost from './types/app/bsky/feed/repost'
|
||||
import * as AppBskyFeedSetVote from './types/app/bsky/feed/setVote'
|
||||
import * as AppBskyFeedTrend from './types/app/bsky/feed/trend'
|
||||
import * as AppBskyFeedVote from './types/app/bsky/feed/vote'
|
||||
import * as AppBskyGraphAssertion from './types/app/bsky/graph/assertion'
|
||||
import * as AppBskyGraphConfirmation from './types/app/bsky/graph/confirmation'
|
||||
@ -95,6 +96,7 @@ export * as AppBskyFeedMediaEmbed from './types/app/bsky/feed/mediaEmbed'
|
||||
export * as AppBskyFeedPost from './types/app/bsky/feed/post'
|
||||
export * as AppBskyFeedRepost from './types/app/bsky/feed/repost'
|
||||
export * as AppBskyFeedSetVote from './types/app/bsky/feed/setVote'
|
||||
export * as AppBskyFeedTrend from './types/app/bsky/feed/trend'
|
||||
export * as AppBskyFeedVote from './types/app/bsky/feed/vote'
|
||||
export * as AppBskyGraphAssertion from './types/app/bsky/graph/assertion'
|
||||
export * as AppBskyGraphConfirmation from './types/app/bsky/graph/confirmation'
|
||||
@ -640,6 +642,7 @@ export class FeedNS {
|
||||
mediaEmbed: MediaEmbedRecord
|
||||
post: PostRecord
|
||||
repost: RepostRecord
|
||||
trend: TrendRecord
|
||||
vote: VoteRecord
|
||||
|
||||
constructor(service: ServiceClient) {
|
||||
@ -647,6 +650,7 @@ export class FeedNS {
|
||||
this.mediaEmbed = new MediaEmbedRecord(service)
|
||||
this.post = new PostRecord(service)
|
||||
this.repost = new RepostRecord(service)
|
||||
this.trend = new TrendRecord(service)
|
||||
this.vote = new VoteRecord(service)
|
||||
}
|
||||
|
||||
@ -904,6 +908,67 @@ export class RepostRecord {
|
||||
}
|
||||
}
|
||||
|
||||
export class TrendRecord {
|
||||
_service: ServiceClient
|
||||
|
||||
constructor(service: ServiceClient) {
|
||||
this._service = service
|
||||
}
|
||||
|
||||
async list(
|
||||
params: Omit<ComAtprotoRepoListRecords.QueryParams, 'collection'>
|
||||
): Promise<{
|
||||
cursor?: string,
|
||||
records: { uri: string, value: AppBskyFeedTrend.Record }[],
|
||||
}> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repo.listRecords', {
|
||||
collection: 'app.bsky.feed.trend',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async get(
|
||||
params: Omit<ComAtprotoRepoGetRecord.QueryParams, 'collection'>
|
||||
): Promise<{ uri: string, cid: string, value: AppBskyFeedTrend.Record }> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repo.getRecord', {
|
||||
collection: 'app.bsky.feed.trend',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async create(
|
||||
params: Omit<
|
||||
ComAtprotoRepoCreateRecord.InputSchema,
|
||||
'collection' | 'record'
|
||||
>,
|
||||
record: AppBskyFeedTrend.Record,
|
||||
headers?: Record<string, string>
|
||||
): Promise<{ uri: string, cid: string }> {
|
||||
record.$type = 'app.bsky.feed.trend'
|
||||
const res = await this._service.xrpc.call(
|
||||
'com.atproto.repo.createRecord',
|
||||
undefined,
|
||||
{ collection: 'app.bsky.feed.trend', ...params, record },
|
||||
{ encoding: 'application/json', headers }
|
||||
)
|
||||
return res.data
|
||||
}
|
||||
|
||||
async delete(
|
||||
params: Omit<ComAtprotoRepoDeleteRecord.QueryParams, 'collection'>,
|
||||
headers?: Record<string, string>
|
||||
): Promise<void> {
|
||||
await this._service.xrpc.call(
|
||||
'com.atproto.repo.deleteRecord',
|
||||
undefined,
|
||||
{ collection: 'app.bsky.feed.trend', ...params },
|
||||
{ headers }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class VoteRecord {
|
||||
_service: ServiceClient
|
||||
|
||||
|
@ -2820,7 +2820,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
reason: {
|
||||
type: 'string',
|
||||
$comment:
|
||||
"Expected values are 'vote', 'repost', 'follow', 'invite', 'mention' and 'reply'.",
|
||||
"Expected values are 'vote', 'repost', 'trend', 'follow', 'invite', 'mention' and 'reply'.",
|
||||
},
|
||||
reasonSubject: {
|
||||
type: 'string',
|
||||
@ -2879,7 +2879,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
reason: {
|
||||
type: 'string',
|
||||
$comment:
|
||||
"Expected values are 'vote', 'repost', 'follow', 'invite', 'mention' and 'reply'.",
|
||||
"Expected values are 'vote', 'repost', 'trend', 'follow', 'invite', 'mention' and 'reply'.",
|
||||
},
|
||||
reasonSubject: {
|
||||
type: 'string',
|
||||
@ -2931,6 +2931,7 @@ export const ids = {
|
||||
AppBskyFeedMediaEmbed: 'app.bsky.feed.mediaEmbed',
|
||||
AppBskyFeedPost: 'app.bsky.feed.post',
|
||||
AppBskyFeedRepost: 'app.bsky.feed.repost',
|
||||
AppBskyFeedTrend: 'app.bsky.feed.trend',
|
||||
AppBskyFeedVote: 'app.bsky.feed.vote',
|
||||
AppBskyGraphAssertion: 'app.bsky.graph.assertion',
|
||||
AppBskyGraphConfirmation: 'app.bsky.graph.confirmation',
|
||||
@ -3209,6 +3210,53 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.feed.trend': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.feed.trend',
|
||||
type: 'record',
|
||||
key: 'tid',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['subject', 'createdAt'],
|
||||
properties: {
|
||||
subject: {
|
||||
$ref: '#/$defs/subject',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
},
|
||||
$defs: {
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['uri', 'cid'],
|
||||
properties: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
},
|
||||
cid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defs: {
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['uri', 'cid'],
|
||||
properties: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
},
|
||||
cid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.feed.vote': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.feed.vote',
|
||||
|
13
packages/api/src/client/types/app/bsky/feed/trend.ts
Normal file
13
packages/api/src/client/types/app/bsky/feed/trend.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
subject: Subject;
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface Subject {
|
||||
uri: string;
|
||||
cid: string;
|
||||
[k: string]: unknown;
|
||||
}
|
@ -13,6 +13,7 @@ import * as profile from './records/profile'
|
||||
import * as post from './records/post'
|
||||
import * as vote from './records/vote'
|
||||
import * as repost from './records/repost'
|
||||
import * as trend from './records/trend'
|
||||
import * as follow from './records/follow'
|
||||
|
||||
export type DatabaseSchema = user.PartialDB &
|
||||
@ -29,5 +30,6 @@ export type DatabaseSchema = user.PartialDB &
|
||||
post.PartialDB &
|
||||
vote.PartialDB &
|
||||
repost.PartialDB &
|
||||
trend.PartialDB &
|
||||
follow.PartialDB &
|
||||
assertion.PartialDB
|
||||
|
@ -8,6 +8,7 @@ import * as Declaration from './records/declaration'
|
||||
import * as Post from './records/post'
|
||||
import * as Vote from './records/vote'
|
||||
import * as Repost from './records/repost'
|
||||
import * as Trend from './records/trend'
|
||||
import * as Follow from './records/follow'
|
||||
import * as Assertion from './records/assertion'
|
||||
import * as Confirmation from './records/confirmation'
|
||||
@ -33,6 +34,7 @@ export class Database {
|
||||
post: Post.PluginType
|
||||
vote: Vote.PluginType
|
||||
repost: Repost.PluginType
|
||||
trend: Trend.PluginType
|
||||
follow: Follow.PluginType
|
||||
profile: Profile.PluginType
|
||||
assertion: Assertion.PluginType
|
||||
@ -50,6 +52,7 @@ export class Database {
|
||||
post: Post.makePlugin(db),
|
||||
vote: Vote.makePlugin(db),
|
||||
repost: Repost.makePlugin(db),
|
||||
trend: Trend.makePlugin(db),
|
||||
follow: Follow.makePlugin(db),
|
||||
assertion: Assertion.makePlugin(db),
|
||||
confirmation: Confirmation.makePlugin(db),
|
||||
|
@ -19,6 +19,7 @@ const followTable = 'follow'
|
||||
const postTable = 'post'
|
||||
const postEntityTable = 'post_entity'
|
||||
const repostTable = 'repost'
|
||||
const trendTable = 'trend'
|
||||
const voteTable = 'vote'
|
||||
|
||||
export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
|
||||
@ -227,6 +228,16 @@ export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
|
||||
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
await db.schema
|
||||
.createTable(trendTable)
|
||||
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
||||
.addColumn('cid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('creator', 'varchar', (col) => col.notNull())
|
||||
.addColumn('subject', 'varchar', (col) => col.notNull())
|
||||
.addColumn('subjectCid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
await db.schema
|
||||
.createTable(voteTable)
|
||||
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
||||
@ -242,6 +253,7 @@ export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
|
||||
|
||||
export async function down(db: Kysely<unknown>): Promise<void> {
|
||||
await db.schema.dropTable(voteTable).execute()
|
||||
await db.schema.dropTable(trendTable).execute()
|
||||
await db.schema.dropTable(repostTable).execute()
|
||||
await db.schema.dropTable(postEntityTable).execute()
|
||||
await db.schema.dropTable(postTable).execute()
|
||||
|
93
packages/pds/src/db/records/trend.ts
Normal file
93
packages/pds/src/db/records/trend.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import { Kysely } from 'kysely'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import * as Trend from '../../lexicon/types/app/bsky/feed/trend'
|
||||
import { DbRecordPlugin, Notification } from '../types'
|
||||
import * as schemas from '../schemas'
|
||||
import { CID } from 'multiformats/cid'
|
||||
|
||||
const type = schemas.ids.AppBskyFeedTrend
|
||||
const tableName = 'trend'
|
||||
|
||||
export interface BskyTrend {
|
||||
uri: string
|
||||
cid: string
|
||||
creator: string
|
||||
subject: string
|
||||
subjectCid: string
|
||||
createdAt: string
|
||||
indexedAt: string
|
||||
}
|
||||
|
||||
export type PartialDB = { [tableName]: BskyTrend }
|
||||
|
||||
const validator = schemas.records.createRecordValidator(type)
|
||||
const matchesSchema = (obj: unknown): obj is Trend.Record => {
|
||||
return validator.isValid(obj)
|
||||
}
|
||||
const validateSchema = (obj: unknown) => validator.validate(obj)
|
||||
|
||||
const insertFn =
|
||||
(db: Kysely<PartialDB>) =>
|
||||
async (
|
||||
uri: AtUri,
|
||||
cid: CID,
|
||||
obj: unknown,
|
||||
timestamp?: string,
|
||||
): Promise<void> => {
|
||||
if (!matchesSchema(obj)) {
|
||||
throw new Error(`Record does not match schema: ${type}`)
|
||||
}
|
||||
await db
|
||||
.insertInto(tableName)
|
||||
.values({
|
||||
uri: uri.toString(),
|
||||
cid: cid.toString(),
|
||||
creator: uri.host,
|
||||
subject: obj.subject.uri,
|
||||
subjectCid: obj.subject.cid,
|
||||
createdAt: obj.createdAt,
|
||||
indexedAt: timestamp || new Date().toISOString(),
|
||||
})
|
||||
.execute()
|
||||
}
|
||||
|
||||
const deleteFn =
|
||||
(db: Kysely<PartialDB>) =>
|
||||
async (uri: AtUri): Promise<void> => {
|
||||
await db.deleteFrom(tableName).where('uri', '=', uri.toString()).execute()
|
||||
}
|
||||
|
||||
const notifsForRecord = (
|
||||
uri: AtUri,
|
||||
cid: CID,
|
||||
obj: unknown,
|
||||
): Notification[] => {
|
||||
if (!matchesSchema(obj)) {
|
||||
throw new Error(`Record does not match schema: ${type}`)
|
||||
}
|
||||
const subjectUri = new AtUri(obj.subject.uri)
|
||||
const notif = {
|
||||
userDid: subjectUri.host,
|
||||
author: uri.host,
|
||||
recordUri: uri.toString(),
|
||||
recordCid: cid.toString(),
|
||||
reason: 'trend',
|
||||
reasonSubject: subjectUri.toString(),
|
||||
}
|
||||
return [notif]
|
||||
}
|
||||
|
||||
export type PluginType = DbRecordPlugin<Trend.Record>
|
||||
|
||||
export const makePlugin = (db: Kysely<PartialDB>): PluginType => {
|
||||
return {
|
||||
collection: type,
|
||||
validateSchema,
|
||||
matchesSchema,
|
||||
insert: insertFn(db),
|
||||
delete: deleteFn(db),
|
||||
notifsForRecord,
|
||||
}
|
||||
}
|
||||
|
||||
export default makePlugin
|
@ -33,6 +33,7 @@ export type Notification = {
|
||||
export type NotificationReason =
|
||||
| 'vote'
|
||||
| 'repost'
|
||||
| 'trend'
|
||||
| 'follow'
|
||||
| 'invite'
|
||||
| 'reply'
|
||||
|
@ -2931,6 +2931,7 @@ export const ids = {
|
||||
AppBskyFeedMediaEmbed: 'app.bsky.feed.mediaEmbed',
|
||||
AppBskyFeedPost: 'app.bsky.feed.post',
|
||||
AppBskyFeedRepost: 'app.bsky.feed.repost',
|
||||
AppBskyFeedTrend: 'app.bsky.feed.trend',
|
||||
AppBskyFeedVote: 'app.bsky.feed.vote',
|
||||
AppBskyGraphAssertion: 'app.bsky.graph.assertion',
|
||||
AppBskyGraphConfirmation: 'app.bsky.graph.confirmation',
|
||||
@ -3209,6 +3210,53 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.feed.trend': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.feed.trend',
|
||||
type: 'record',
|
||||
key: 'tid',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['subject', 'createdAt'],
|
||||
properties: {
|
||||
subject: {
|
||||
$ref: '#/$defs/subject',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
},
|
||||
$defs: {
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['uri', 'cid'],
|
||||
properties: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
},
|
||||
cid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defs: {
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['uri', 'cid'],
|
||||
properties: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
},
|
||||
cid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.feed.vote': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.feed.vote',
|
||||
|
13
packages/pds/src/lexicon/types/app/bsky/feed/trend.ts
Normal file
13
packages/pds/src/lexicon/types/app/bsky/feed/trend.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
subject: Subject;
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface Subject {
|
||||
uri: string;
|
||||
cid: string;
|
||||
[k: string]: unknown;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user