Account declaration & invites (#289)
* schemas * database & buffing up schemas * declaration on createAccount, + fixing up test client * fix up dev-env * schema comments * nsid for declaration actorType * declaration description * oops token schema slipped in * declaration -> declarationCid * missed a couple of db things
This commit is contained in:
parent
6bf748bc70
commit
2fb128d94f
lexicons
atproto.com
bsky.app
packages
api/src
dev-env/src/mock
pds
@ -22,12 +22,13 @@
|
||||
"encoding": "application/json",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": ["accessJwt", "refreshJwt", "username", "did"],
|
||||
"required": ["accessJwt", "refreshJwt", "username", "did", "declarationCid"],
|
||||
"properties": {
|
||||
"accessJwt": { "type": "string" },
|
||||
"refreshJwt": { "type": "string" },
|
||||
"username": { "type": "string" },
|
||||
"did": { "type": "string" }
|
||||
"did": { "type": "string" },
|
||||
"declarationCid": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
29
lexicons/bsky.app/declaration.json
Normal file
29
lexicons/bsky.app/declaration.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"lexicon": 1,
|
||||
"id": "app.bsky.declaration",
|
||||
"description": "Context for an account that is considered intrinsic to it and alters the fundamental understanding of an account of changed. A declaration should be treated as immutable.",
|
||||
"type": "record",
|
||||
"key": "literal:self",
|
||||
"record": {
|
||||
"type": "object",
|
||||
"required": ["actorType"],
|
||||
"properties": {
|
||||
"actorType": {
|
||||
"oneOf": [
|
||||
{"$ref": "#/defs/actorKnown"},
|
||||
{"$ref": "#/defs/actorUnknown"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defs": {
|
||||
"actorKnown": {
|
||||
"type": "string",
|
||||
"enum": ["app.bsky.actorUser", "app.bsky.actorScene"]
|
||||
},
|
||||
"actorUnknown": {
|
||||
"type": "string",
|
||||
"not": {"enum": ["app.bsky.actorUser", "app.bsky.actorScene"]}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,14 @@
|
||||
"type": "object",
|
||||
"required": ["subject", "createdAt"],
|
||||
"properties": {
|
||||
"subject": { "type": "string" },
|
||||
"subject": {
|
||||
"type": "object",
|
||||
"required": ["did", "declarationCid"],
|
||||
"properties": {
|
||||
"did": {"type": "string"},
|
||||
"declarationCid": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"createdAt": {"type": "string", "format": "date-time"}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"$comment": "Expected values are 'like', 'repost', 'follow', 'badge', 'mention' and 'reply'."
|
||||
"$comment": "Expected values are 'like', 'repost', 'follow', 'badge', 'invite', 'mention' and 'reply'."
|
||||
},
|
||||
"reasonSubject": {"type": "string"},
|
||||
"record": {"type": "object"},
|
||||
|
22
lexicons/bsky.app/invite.json
Normal file
22
lexicons/bsky.app/invite.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"lexicon": 1,
|
||||
"id": "app.bsky.invite",
|
||||
"type": "record",
|
||||
"key": "tid",
|
||||
"record": {
|
||||
"type": "object",
|
||||
"required": ["group", "subject", "createdAt"],
|
||||
"properties": {
|
||||
"group": {"type": "string"},
|
||||
"subject": {
|
||||
"type": "object",
|
||||
"required": ["did", "declarationCid"],
|
||||
"properties": {
|
||||
"did": {"type": "string"},
|
||||
"declarationCid": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"createdAt": {"type": "string", "format": "date-time"}
|
||||
}
|
||||
}
|
||||
}
|
29
lexicons/bsky.app/inviteAccept.json
Normal file
29
lexicons/bsky.app/inviteAccept.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"lexicon": 1,
|
||||
"id": "app.bsky.inviteAccept",
|
||||
"type": "record",
|
||||
"key": "tid",
|
||||
"record": {
|
||||
"type": "object",
|
||||
"required": ["group", "invite", "createdAt"],
|
||||
"properties": {
|
||||
"group": {
|
||||
"type": "object",
|
||||
"required": ["did", "declarationCid"],
|
||||
"properties": {
|
||||
"did": {"type": "string"},
|
||||
"declarationCid": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"invite": {
|
||||
"type": "object",
|
||||
"required": ["uri", "cid"],
|
||||
"properties": {
|
||||
"uri": {"type": "string"},
|
||||
"cid": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"createdAt": {"type": "string", "format": "date-time"}
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ import * as ComAtprotoSyncUpdateRepo from './types/com/atproto/syncUpdateRepo'
|
||||
import * as AppBskyBadge from './types/app/bsky/badge'
|
||||
import * as AppBskyBadgeAccept from './types/app/bsky/badgeAccept'
|
||||
import * as AppBskyBadgeOffer from './types/app/bsky/badgeOffer'
|
||||
import * as AppBskyDeclaration from './types/app/bsky/declaration'
|
||||
import * as AppBskyFollow from './types/app/bsky/follow'
|
||||
import * as AppBskyGetAuthorFeed from './types/app/bsky/getAuthorFeed'
|
||||
import * as AppBskyGetBadgeMembers from './types/app/bsky/getBadgeMembers'
|
||||
@ -45,6 +46,8 @@ import * as AppBskyGetUserFollowers from './types/app/bsky/getUserFollowers'
|
||||
import * as AppBskyGetUserFollows from './types/app/bsky/getUserFollows'
|
||||
import * as AppBskyGetUsersSearch from './types/app/bsky/getUsersSearch'
|
||||
import * as AppBskyGetUsersTypeahead from './types/app/bsky/getUsersTypeahead'
|
||||
import * as AppBskyInvite from './types/app/bsky/invite'
|
||||
import * as AppBskyInviteAccept from './types/app/bsky/inviteAccept'
|
||||
import * as AppBskyLike from './types/app/bsky/like'
|
||||
import * as AppBskyMediaEmbed from './types/app/bsky/mediaEmbed'
|
||||
import * as AppBskyPost from './types/app/bsky/post'
|
||||
@ -78,6 +81,7 @@ export * as ComAtprotoSyncUpdateRepo from './types/com/atproto/syncUpdateRepo'
|
||||
export * as AppBskyBadge from './types/app/bsky/badge'
|
||||
export * as AppBskyBadgeAccept from './types/app/bsky/badgeAccept'
|
||||
export * as AppBskyBadgeOffer from './types/app/bsky/badgeOffer'
|
||||
export * as AppBskyDeclaration from './types/app/bsky/declaration'
|
||||
export * as AppBskyFollow from './types/app/bsky/follow'
|
||||
export * as AppBskyGetAuthorFeed from './types/app/bsky/getAuthorFeed'
|
||||
export * as AppBskyGetBadgeMembers from './types/app/bsky/getBadgeMembers'
|
||||
@ -92,6 +96,8 @@ export * as AppBskyGetUserFollowers from './types/app/bsky/getUserFollowers'
|
||||
export * as AppBskyGetUserFollows from './types/app/bsky/getUserFollows'
|
||||
export * as AppBskyGetUsersSearch from './types/app/bsky/getUsersSearch'
|
||||
export * as AppBskyGetUsersTypeahead from './types/app/bsky/getUsersTypeahead'
|
||||
export * as AppBskyInvite from './types/app/bsky/invite'
|
||||
export * as AppBskyInviteAccept from './types/app/bsky/inviteAccept'
|
||||
export * as AppBskyLike from './types/app/bsky/like'
|
||||
export * as AppBskyMediaEmbed from './types/app/bsky/mediaEmbed'
|
||||
export * as AppBskyPost from './types/app/bsky/post'
|
||||
@ -430,7 +436,10 @@ export class BskyNS {
|
||||
badge: BadgeRecord
|
||||
badgeAccept: BadgeAcceptRecord
|
||||
badgeOffer: BadgeOfferRecord
|
||||
declaration: DeclarationRecord
|
||||
follow: FollowRecord
|
||||
invite: InviteRecord
|
||||
inviteAccept: InviteAcceptRecord
|
||||
like: LikeRecord
|
||||
mediaEmbed: MediaEmbedRecord
|
||||
post: PostRecord
|
||||
@ -442,7 +451,10 @@ export class BskyNS {
|
||||
this.badge = new BadgeRecord(service)
|
||||
this.badgeAccept = new BadgeAcceptRecord(service)
|
||||
this.badgeOffer = new BadgeOfferRecord(service)
|
||||
this.declaration = new DeclarationRecord(service)
|
||||
this.follow = new FollowRecord(service)
|
||||
this.invite = new InviteRecord(service)
|
||||
this.inviteAccept = new InviteAcceptRecord(service)
|
||||
this.like = new LikeRecord(service)
|
||||
this.mediaEmbed = new MediaEmbedRecord(service)
|
||||
this.post = new PostRecord(service)
|
||||
@ -805,6 +817,64 @@ export class BadgeOfferRecord {
|
||||
}
|
||||
}
|
||||
|
||||
export class DeclarationRecord {
|
||||
_service: ServiceClient
|
||||
|
||||
constructor(service: ServiceClient) {
|
||||
this._service = service
|
||||
}
|
||||
|
||||
async list(
|
||||
params: Omit<ComAtprotoRepoListRecords.QueryParams, 'collection'>
|
||||
): Promise<{
|
||||
cursor?: string,
|
||||
records: { uri: string, value: AppBskyDeclaration.Record }[],
|
||||
}> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repoListRecords', {
|
||||
collection: 'app.bsky.declaration',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async get(
|
||||
params: Omit<ComAtprotoRepoGetRecord.QueryParams, 'collection'>
|
||||
): Promise<{ uri: string, cid: string, value: AppBskyDeclaration.Record }> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repoGetRecord', {
|
||||
collection: 'app.bsky.declaration',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async create(
|
||||
params: Omit<ComAtprotoRepoCreateRecord.QueryParams, 'collection'>,
|
||||
record: AppBskyDeclaration.Record,
|
||||
headers?: Record<string, string>
|
||||
): Promise<{ uri: string, cid: string }> {
|
||||
record.$type = 'app.bsky.declaration'
|
||||
const res = await this._service.xrpc.call(
|
||||
'com.atproto.repoCreateRecord',
|
||||
{ collection: 'app.bsky.declaration', ...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.repoDeleteRecord',
|
||||
{ collection: 'app.bsky.declaration', ...params },
|
||||
undefined,
|
||||
{ headers }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class FollowRecord {
|
||||
_service: ServiceClient
|
||||
|
||||
@ -863,6 +933,122 @@ export class FollowRecord {
|
||||
}
|
||||
}
|
||||
|
||||
export class InviteRecord {
|
||||
_service: ServiceClient
|
||||
|
||||
constructor(service: ServiceClient) {
|
||||
this._service = service
|
||||
}
|
||||
|
||||
async list(
|
||||
params: Omit<ComAtprotoRepoListRecords.QueryParams, 'collection'>
|
||||
): Promise<{
|
||||
cursor?: string,
|
||||
records: { uri: string, value: AppBskyInvite.Record }[],
|
||||
}> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repoListRecords', {
|
||||
collection: 'app.bsky.invite',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async get(
|
||||
params: Omit<ComAtprotoRepoGetRecord.QueryParams, 'collection'>
|
||||
): Promise<{ uri: string, cid: string, value: AppBskyInvite.Record }> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repoGetRecord', {
|
||||
collection: 'app.bsky.invite',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async create(
|
||||
params: Omit<ComAtprotoRepoCreateRecord.QueryParams, 'collection'>,
|
||||
record: AppBskyInvite.Record,
|
||||
headers?: Record<string, string>
|
||||
): Promise<{ uri: string, cid: string }> {
|
||||
record.$type = 'app.bsky.invite'
|
||||
const res = await this._service.xrpc.call(
|
||||
'com.atproto.repoCreateRecord',
|
||||
{ collection: 'app.bsky.invite', ...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.repoDeleteRecord',
|
||||
{ collection: 'app.bsky.invite', ...params },
|
||||
undefined,
|
||||
{ headers }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class InviteAcceptRecord {
|
||||
_service: ServiceClient
|
||||
|
||||
constructor(service: ServiceClient) {
|
||||
this._service = service
|
||||
}
|
||||
|
||||
async list(
|
||||
params: Omit<ComAtprotoRepoListRecords.QueryParams, 'collection'>
|
||||
): Promise<{
|
||||
cursor?: string,
|
||||
records: { uri: string, value: AppBskyInviteAccept.Record }[],
|
||||
}> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repoListRecords', {
|
||||
collection: 'app.bsky.inviteAccept',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async get(
|
||||
params: Omit<ComAtprotoRepoGetRecord.QueryParams, 'collection'>
|
||||
): Promise<{ uri: string, cid: string, value: AppBskyInviteAccept.Record }> {
|
||||
const res = await this._service.xrpc.call('com.atproto.repoGetRecord', {
|
||||
collection: 'app.bsky.inviteAccept',
|
||||
...params,
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
async create(
|
||||
params: Omit<ComAtprotoRepoCreateRecord.QueryParams, 'collection'>,
|
||||
record: AppBskyInviteAccept.Record,
|
||||
headers?: Record<string, string>
|
||||
): Promise<{ uri: string, cid: string }> {
|
||||
record.$type = 'app.bsky.inviteAccept'
|
||||
const res = await this._service.xrpc.call(
|
||||
'com.atproto.repoCreateRecord',
|
||||
{ collection: 'app.bsky.inviteAccept', ...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.repoDeleteRecord',
|
||||
{ collection: 'app.bsky.inviteAccept', ...params },
|
||||
undefined,
|
||||
{ headers }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class LikeRecord {
|
||||
_service: ServiceClient
|
||||
|
||||
|
@ -39,7 +39,13 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['accessJwt', 'refreshJwt', 'username', 'did'],
|
||||
required: [
|
||||
'accessJwt',
|
||||
'refreshJwt',
|
||||
'username',
|
||||
'did',
|
||||
'declarationCid',
|
||||
],
|
||||
properties: {
|
||||
accessJwt: {
|
||||
type: 'string',
|
||||
@ -53,6 +59,9 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
$defs: {},
|
||||
},
|
||||
@ -1629,7 +1638,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
reason: {
|
||||
type: 'string',
|
||||
$comment:
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'mention' and 'reply'.",
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'invite', 'mention' and 'reply'.",
|
||||
},
|
||||
reasonSubject: {
|
||||
type: 'string',
|
||||
@ -1688,7 +1697,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
reason: {
|
||||
type: 'string',
|
||||
$comment:
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'mention' and 'reply'.",
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'invite', 'mention' and 'reply'.",
|
||||
},
|
||||
reasonSubject: {
|
||||
type: 'string',
|
||||
@ -2592,7 +2601,10 @@ export const ids = {
|
||||
AppBskyBadge: 'app.bsky.badge',
|
||||
AppBskyBadgeAccept: 'app.bsky.badgeAccept',
|
||||
AppBskyBadgeOffer: 'app.bsky.badgeOffer',
|
||||
AppBskyDeclaration: 'app.bsky.declaration',
|
||||
AppBskyFollow: 'app.bsky.follow',
|
||||
AppBskyInvite: 'app.bsky.invite',
|
||||
AppBskyInviteAccept: 'app.bsky.inviteAccept',
|
||||
AppBskyLike: 'app.bsky.like',
|
||||
AppBskyMediaEmbed: 'app.bsky.mediaEmbed',
|
||||
AppBskyPost: 'app.bsky.post',
|
||||
@ -2823,6 +2835,54 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.declaration': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.declaration',
|
||||
description:
|
||||
'Context for an account that is considered intrinsic to it and alters the fundamental understanding of an account of changed. A declaration should be treated as immutable.',
|
||||
type: 'record',
|
||||
key: 'literal:self',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['actorType'],
|
||||
properties: {
|
||||
actorType: {
|
||||
oneOf: [
|
||||
{
|
||||
$ref: '#/$defs/actorKnown',
|
||||
},
|
||||
{
|
||||
$ref: '#/$defs/actorUnknown',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
$defs: {
|
||||
actorKnown: {
|
||||
type: 'string',
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
actorUnknown: {
|
||||
type: 'string',
|
||||
not: {
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defs: {
|
||||
actorKnown: {
|
||||
type: 'string',
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
actorUnknown: {
|
||||
type: 'string',
|
||||
not: {
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.follow': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.follow',
|
||||
@ -2834,7 +2894,89 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
|
||||
required: ['subject', 'createdAt'],
|
||||
properties: {
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['did', 'declarationCid'],
|
||||
properties: {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
},
|
||||
$defs: {},
|
||||
},
|
||||
},
|
||||
'app.bsky.invite': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.invite',
|
||||
type: 'record',
|
||||
key: 'tid',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['group', 'subject', 'createdAt'],
|
||||
properties: {
|
||||
group: {
|
||||
type: 'string',
|
||||
},
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['did', 'declarationCid'],
|
||||
properties: {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
},
|
||||
$defs: {},
|
||||
},
|
||||
},
|
||||
'app.bsky.inviteAccept': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.inviteAccept',
|
||||
type: 'record',
|
||||
key: 'tid',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['group', 'invite', 'createdAt'],
|
||||
properties: {
|
||||
group: {
|
||||
type: 'object',
|
||||
required: ['did', 'declarationCid'],
|
||||
properties: {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
invite: {
|
||||
type: 'object',
|
||||
required: ['uri', 'cid'],
|
||||
properties: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
},
|
||||
cid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
|
10
packages/api/src/types/app/bsky/declaration.ts
Normal file
10
packages/api/src/types/app/bsky/declaration.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export type ActorKnown = 'app.bsky.actorUser' | 'app.bsky.actorScene'
|
||||
export type ActorUnknown = string
|
||||
|
||||
export interface Record {
|
||||
actorType: ActorKnown | ActorUnknown;
|
||||
[k: string]: unknown;
|
||||
}
|
@ -2,7 +2,11 @@
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
subject: string;
|
||||
subject: {
|
||||
did: string,
|
||||
declarationCid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
|
13
packages/api/src/types/app/bsky/invite.ts
Normal file
13
packages/api/src/types/app/bsky/invite.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
group: string;
|
||||
subject: {
|
||||
did: string,
|
||||
declarationCid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
17
packages/api/src/types/app/bsky/inviteAccept.ts
Normal file
17
packages/api/src/types/app/bsky/inviteAccept.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
group: {
|
||||
did: string,
|
||||
declarationCid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
invite: {
|
||||
uri: string,
|
||||
cid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
@ -23,6 +23,7 @@ export interface OutputSchema {
|
||||
refreshJwt: string;
|
||||
username: string;
|
||||
did: string;
|
||||
declarationCid: string;
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
|
@ -47,6 +47,7 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
interface User {
|
||||
email: string
|
||||
did: string
|
||||
declarationCid: string
|
||||
username: string
|
||||
password: string
|
||||
api: ServiceClient
|
||||
@ -55,6 +56,7 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
{
|
||||
email: 'alice@test.com',
|
||||
did: '',
|
||||
declarationCid: '',
|
||||
username: `alice.test`,
|
||||
password: 'hunter2',
|
||||
api: clients.alice,
|
||||
@ -62,6 +64,7 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
{
|
||||
email: 'bob@test.com',
|
||||
did: '',
|
||||
declarationCid: '',
|
||||
username: `bob.test`,
|
||||
password: 'hunter2',
|
||||
api: clients.bob,
|
||||
@ -69,6 +72,7 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
{
|
||||
email: 'carla@test.com',
|
||||
did: '',
|
||||
declarationCid: '',
|
||||
username: `carla.test`,
|
||||
password: 'hunter2',
|
||||
api: clients.carla,
|
||||
@ -85,6 +89,7 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
{ email: user.email, username: user.username, password: user.password },
|
||||
)
|
||||
user.did = res.data.did
|
||||
user.declarationCid = res.data.declarationCid
|
||||
user.api.setHeader('Authorization', `Bearer ${res.data.accessJwt}`)
|
||||
await user.api.app.bsky.profile.create(
|
||||
{ did: user.did },
|
||||
@ -96,21 +101,24 @@ export async function generateMockSetup(env: DevEnv) {
|
||||
}
|
||||
|
||||
// everybody follows everybody
|
||||
const follow = async (author: User, subject: string) => {
|
||||
const follow = async (author: User, subject: User) => {
|
||||
await author.api.app.bsky.follow.create(
|
||||
{ did: author.did },
|
||||
{
|
||||
subject,
|
||||
subject: {
|
||||
did: subject.did,
|
||||
declarationCid: subject.declarationCid,
|
||||
},
|
||||
createdAt: date.next().value,
|
||||
},
|
||||
)
|
||||
}
|
||||
await follow(alice, bob.did)
|
||||
await follow(alice, carla.did)
|
||||
await follow(bob, alice.did)
|
||||
await follow(bob, carla.did)
|
||||
await follow(carla, alice.did)
|
||||
await follow(carla, bob.did)
|
||||
await follow(alice, bob)
|
||||
await follow(alice, carla)
|
||||
await follow(bob, alice)
|
||||
await follow(bob, carla)
|
||||
await follow(carla, alice)
|
||||
await follow(carla, bob)
|
||||
|
||||
// a set of posts and reposts
|
||||
const posts: { uri: string; cid: string }[] = []
|
||||
|
@ -55,7 +55,7 @@ export default function (server: Server) {
|
||||
// Followee's posts and reposts, and requester's posts
|
||||
const followingIdsSubquery = db.db
|
||||
.selectFrom('app_bsky_follow as follow')
|
||||
.select('follow.subject')
|
||||
.select('follow.subjectDid')
|
||||
.where('follow.creator', '=', requester)
|
||||
repostsQb = repostsQb
|
||||
.where('creator', '!=', requester)
|
||||
|
@ -38,7 +38,7 @@ export default function (server: Server) {
|
||||
.as('followsCount'),
|
||||
db.db
|
||||
.selectFrom('app_bsky_follow')
|
||||
.whereRef('subject', '=', ref('user_did.did'))
|
||||
.whereRef('subjectDid', '=', ref('user_did.did'))
|
||||
.select(countAll.as('count'))
|
||||
.as('followersCount'),
|
||||
db.db
|
||||
@ -49,7 +49,7 @@ export default function (server: Server) {
|
||||
db.db
|
||||
.selectFrom('app_bsky_follow')
|
||||
.where('creator', '=', requester)
|
||||
.whereRef('subject', '=', ref('user_did.did'))
|
||||
.whereRef('subjectDid', '=', ref('user_did.did'))
|
||||
.select('uri')
|
||||
.as('requesterFollow'),
|
||||
])
|
||||
|
@ -18,7 +18,7 @@ export default function (server: Server) {
|
||||
|
||||
let followersReq = db.db
|
||||
.selectFrom('app_bsky_follow as follow')
|
||||
.where('follow.subject', '=', subject.did)
|
||||
.where('follow.subjectDid', '=', subject.did)
|
||||
.innerJoin('user_did as creator', 'creator.did', 'follow.creator')
|
||||
.leftJoin(
|
||||
'app_bsky_profile as profile',
|
||||
|
@ -19,11 +19,11 @@ export default function (server: Server) {
|
||||
let followsReq = db.db
|
||||
.selectFrom('app_bsky_follow as follow')
|
||||
.where('follow.creator', '=', creator.did)
|
||||
.innerJoin('user_did as subject', 'subject.did', 'follow.subject')
|
||||
.innerJoin('user_did as subject', 'subject.did', 'follow.subjectDid')
|
||||
.leftJoin(
|
||||
'app_bsky_profile as profile',
|
||||
'profile.creator',
|
||||
'follow.subject',
|
||||
'follow.subjectDid',
|
||||
)
|
||||
.select([
|
||||
'subject.did as did',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { InvalidRequestError } from '@atproto/xrpc-server'
|
||||
import { Repo } from '@atproto/repo'
|
||||
import { RepoStructure } from '@atproto/repo'
|
||||
import { PlcClient } from '@atproto/plc'
|
||||
import { Server } from '../../../lexicon'
|
||||
import * as locals from '../../../locals'
|
||||
@ -8,6 +8,8 @@ import { UserAlreadyExistsError } from '../../../db'
|
||||
import SqlBlockstore from '../../../sql-blockstore'
|
||||
import { ensureUsernameValid } from './util/username'
|
||||
import { grantRefreshToken } from './util/auth'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import * as schema from '../../../lexicon/schemas'
|
||||
|
||||
export default function (server: Server) {
|
||||
server.com.atproto.getAccountsConfig((_params, _input, _req, res) => {
|
||||
@ -124,22 +126,46 @@ export default function (server: Server) {
|
||||
// Setup repo root
|
||||
const authStore = locals.getAuthstore(res, did)
|
||||
const blockstore = new SqlBlockstore(dbTxn, did, now)
|
||||
const repo = await Repo.create(blockstore, did, authStore)
|
||||
const repo = await RepoStructure.create(blockstore, did, authStore)
|
||||
|
||||
await dbTxn.db
|
||||
.insertInto('repo_root')
|
||||
.values({
|
||||
did: did,
|
||||
root: repo.cid.toString(),
|
||||
indexedAt: now,
|
||||
const declaration = {
|
||||
$type: 'app.bsky.declaration',
|
||||
actorType: 'app.bsky.actorUser',
|
||||
}
|
||||
const declarationCid = await blockstore.put(declaration)
|
||||
const uri = new AtUri(`${did}/${schema.ids.AppBskyDeclaration}/self`)
|
||||
|
||||
await repo
|
||||
.stageUpdate({
|
||||
action: 'create',
|
||||
collection: uri.collection,
|
||||
rkey: uri.rkey,
|
||||
cid: declarationCid,
|
||||
})
|
||||
.execute()
|
||||
.createCommit(authStore, async (_prev, curr) => {
|
||||
await dbTxn.db
|
||||
.insertInto('repo_root')
|
||||
.values({
|
||||
did: did,
|
||||
root: curr.toString(),
|
||||
indexedAt: now,
|
||||
})
|
||||
.execute()
|
||||
return null
|
||||
})
|
||||
|
||||
await dbTxn.indexRecord(uri, declarationCid, declaration, now)
|
||||
|
||||
const access = auth.createAccessToken(did)
|
||||
const refresh = auth.createRefreshToken(did)
|
||||
await grantRefreshToken(dbTxn, refresh.payload)
|
||||
|
||||
return { did, accessJwt: access.jwt, refreshJwt: refresh.jwt }
|
||||
return {
|
||||
did,
|
||||
declarationCid,
|
||||
accessJwt: access.jwt,
|
||||
refreshJwt: refresh.jwt,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
@ -149,6 +175,7 @@ export default function (server: Server) {
|
||||
did: result.did,
|
||||
accessJwt: result.accessJwt,
|
||||
refreshJwt: result.refreshJwt,
|
||||
declarationCid: result.declarationCid.toString(),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
@ -5,16 +5,19 @@ import * as refreshToken from './tables/refresh-token'
|
||||
import * as record from './tables/record'
|
||||
import * as ipldBlock from './tables/ipld-block'
|
||||
import * as ipldBlockCreator from './tables/ipld-block-creator'
|
||||
import * as invite from './tables/invite'
|
||||
import * as inviteCode from './tables/invite-code'
|
||||
import * as notification from './tables/user-notification'
|
||||
import * as declaration from './records/declaration'
|
||||
import * as profile from './records/profile'
|
||||
import * as post from './records/post'
|
||||
import * as like from './records/like'
|
||||
import * as repost from './records/repost'
|
||||
import * as follow from './records/follow'
|
||||
import * as profile from './records/profile'
|
||||
import * as badge from './records/badge'
|
||||
import * as badgeAccept from './records/badgeAccept'
|
||||
import * as badgeOffer from './records/badgeOffer'
|
||||
import * as invite from './records/invite'
|
||||
import * as inviteAccept from './records/inviteAccept'
|
||||
|
||||
export type DatabaseSchema = user.PartialDB &
|
||||
userDid.PartialDB &
|
||||
@ -23,13 +26,16 @@ export type DatabaseSchema = user.PartialDB &
|
||||
record.PartialDB &
|
||||
ipldBlock.PartialDB &
|
||||
ipldBlockCreator.PartialDB &
|
||||
invite.PartialDB &
|
||||
inviteCode.PartialDB &
|
||||
notification.PartialDB &
|
||||
declaration.PartialDB &
|
||||
profile.PartialDB &
|
||||
post.PartialDB &
|
||||
like.PartialDB &
|
||||
repost.PartialDB &
|
||||
follow.PartialDB &
|
||||
profile.PartialDB &
|
||||
badge.PartialDB &
|
||||
badgeAccept.PartialDB &
|
||||
badgeOffer.PartialDB
|
||||
badgeOffer.PartialDB &
|
||||
invite.PartialDB &
|
||||
inviteAccept.PartialDB
|
||||
|
@ -4,6 +4,9 @@ import SqliteDB from 'better-sqlite3'
|
||||
import { Pool as PgPool, types as pgTypes } from 'pg'
|
||||
import { ValidationResult, ValidationResultCode } from '@atproto/lexicon'
|
||||
import { DbRecordPlugin, NotificationsPlugin } from './types'
|
||||
import * as Declaration from '../lexicon/types/app/bsky/declaration'
|
||||
import * as Invite from '../lexicon/types/app/bsky/invite'
|
||||
import * as InviteAccept from '../lexicon/types/app/bsky/inviteAccept'
|
||||
import * as Badge from '../lexicon/types/app/bsky/badge'
|
||||
import * as BadgeAccept from '../lexicon/types/app/bsky/badgeAccept'
|
||||
import * as BadgeOffer from '../lexicon/types/app/bsky/badgeOffer'
|
||||
@ -12,10 +15,13 @@ import * as Like from '../lexicon/types/app/bsky/like'
|
||||
import * as Post from '../lexicon/types/app/bsky/post'
|
||||
import * as Profile from '../lexicon/types/app/bsky/profile'
|
||||
import * as Repost from '../lexicon/types/app/bsky/repost'
|
||||
import declarationPlugin, { AppBskyDeclaration } from './records/declaration'
|
||||
import postPlugin, { AppBskyPost } from './records/post'
|
||||
import likePlugin, { AppBskyLike } from './records/like'
|
||||
import repostPlugin, { AppBskyRepost } from './records/repost'
|
||||
import followPlugin, { AppBskyFollow } from './records/follow'
|
||||
import invitePlugin, { AppBskyInvite } from './records/invite'
|
||||
import inviteAcceptPlugin, { AppBskyInviteAccept } from './records/inviteAccept'
|
||||
import badgePlugin, { AppBskyBadge } from './records/badge'
|
||||
import badgeAcceptPlugin, { AppBskyBadgeAccept } from './records/badgeAccept'
|
||||
import badgeOfferPlugin, { AppBskyBadgeOffer } from './records/badgeOffer'
|
||||
@ -36,11 +42,14 @@ import { UserDid } from './tables/user-did'
|
||||
export class Database {
|
||||
migrator: Migrator
|
||||
records: {
|
||||
declaration: DbRecordPlugin<Declaration.Record, AppBskyDeclaration>
|
||||
post: DbRecordPlugin<Post.Record, AppBskyPost>
|
||||
like: DbRecordPlugin<Like.Record, AppBskyLike>
|
||||
repost: DbRecordPlugin<Repost.Record, AppBskyRepost>
|
||||
follow: DbRecordPlugin<Follow.Record, AppBskyFollow>
|
||||
profile: DbRecordPlugin<Profile.Record, AppBskyProfile>
|
||||
invite: DbRecordPlugin<Invite.Record, AppBskyInvite>
|
||||
inviteAccept: DbRecordPlugin<InviteAccept.Record, AppBskyInviteAccept>
|
||||
badge: DbRecordPlugin<Badge.Record, AppBskyBadge>
|
||||
badgeAccept: DbRecordPlugin<BadgeAccept.Record, AppBskyBadgeAccept>
|
||||
badgeOffer: DbRecordPlugin<BadgeOffer.Record, AppBskyBadgeOffer>
|
||||
@ -53,10 +62,13 @@ export class Database {
|
||||
public schema?: string,
|
||||
) {
|
||||
this.records = {
|
||||
declaration: declarationPlugin(db),
|
||||
post: postPlugin(db),
|
||||
like: likePlugin(db),
|
||||
repost: repostPlugin(db),
|
||||
follow: followPlugin(db),
|
||||
invite: invitePlugin(db),
|
||||
inviteAccept: inviteAcceptPlugin(db),
|
||||
badge: badgePlugin(db),
|
||||
badgeAccept: badgeAcceptPlugin(db),
|
||||
badgeOffer: badgeOfferPlugin(db),
|
||||
|
@ -8,14 +8,17 @@ const repoRootTable = 'repo_root'
|
||||
const recordTable = 'record'
|
||||
const ipldBlockTable = 'ipld_block'
|
||||
const ipldBlockCreatorTable = 'ipld_block_creator'
|
||||
const inviteTable = 'invite_code'
|
||||
const inviteCodeTable = 'invite_code'
|
||||
const inviteUseTable = 'invite_code_use'
|
||||
const notificationTable = 'user_notification'
|
||||
const declarationTable = 'app_bsky_declaration'
|
||||
const profileTable = 'app_bsky_profile'
|
||||
const profileBadgeTable = 'app_bsky_profile_badge'
|
||||
const badgeTable = 'app_bsky_badge'
|
||||
const badgeOfferTable = 'app_bsky_badge_offer'
|
||||
const badgeAcceptTable = 'app_bsky_badge_accept'
|
||||
const inviteTable = 'app_bsky_invite'
|
||||
const inviteAcceptTable = 'app_bsky_invite_accept'
|
||||
const followTable = 'app_bsky_follow'
|
||||
const postTable = 'app_bsky_post'
|
||||
const postEntityTable = 'app_bsky_post_entity'
|
||||
@ -113,9 +116,9 @@ export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
|
||||
.addColumn('did', 'varchar', (col) => col.notNull())
|
||||
.addPrimaryKeyConstraint(`${ipldBlockCreatorTable}_pkey`, ['cid', 'did'])
|
||||
.execute()
|
||||
// Invites
|
||||
// Invite Codes
|
||||
await db.schema
|
||||
.createTable(inviteTable)
|
||||
.createTable(inviteCodeTable)
|
||||
.addColumn('code', 'varchar', (col) => col.primaryKey())
|
||||
.addColumn('availableUses', 'integer', (col) => col.notNull())
|
||||
.addColumn('disabled', 'int2', (col) => col.defaultTo(0))
|
||||
@ -142,6 +145,15 @@ export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
|
||||
.addColumn('reasonSubject', 'varchar')
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
// Declarations
|
||||
await db.schema
|
||||
.createTable(declarationTable)
|
||||
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
||||
.addColumn('cid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('creator', 'varchar', (col) => col.notNull())
|
||||
.addColumn('actorType', 'varchar', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
// Profiles
|
||||
await db.schema
|
||||
.createTable(profileTable)
|
||||
@ -205,13 +217,38 @@ export async function up(db: Kysely<unknown>, dialect: Dialect): Promise<void> {
|
||||
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
// Invites (Records)
|
||||
await db.schema
|
||||
.createTable(inviteTable)
|
||||
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
||||
.addColumn('cid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('creator', 'varchar', (col) => col.notNull())
|
||||
.addColumn('group', 'varchar', (col) => col.notNull())
|
||||
.addColumn('subjectDid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('subjectDeclarationCid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
await db.schema
|
||||
.createTable(inviteAcceptTable)
|
||||
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
||||
.addColumn('cid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('creator', 'varchar', (col) => col.notNull())
|
||||
.addColumn('groupDid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('groupDeclarationCid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('inviteUri', 'varchar', (col) => col.notNull())
|
||||
.addColumn('inviteCid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
// Follows
|
||||
await db.schema
|
||||
.createTable(followTable)
|
||||
.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('subjectDid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('subjectDeclarationCid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.execute()
|
||||
@ -265,14 +302,17 @@ export async function down(db: Kysely<unknown>): Promise<void> {
|
||||
await db.schema.dropTable(postEntityTable).execute()
|
||||
await db.schema.dropTable(postTable).execute()
|
||||
await db.schema.dropTable(followTable).execute()
|
||||
await db.schema.dropTable(inviteAcceptTable).execute()
|
||||
await db.schema.dropTable(inviteTable).execute()
|
||||
await db.schema.dropTable(badgeAcceptTable).execute()
|
||||
await db.schema.dropTable(badgeOfferTable).execute()
|
||||
await db.schema.dropTable(badgeTable).execute()
|
||||
await db.schema.dropTable(profileBadgeTable).execute()
|
||||
await db.schema.dropTable(profileTable).execute()
|
||||
await db.schema.dropTable(declarationTable).execute()
|
||||
await db.schema.dropTable(notificationTable).execute()
|
||||
await db.schema.dropTable(inviteUseTable).execute()
|
||||
await db.schema.dropTable(inviteTable).execute()
|
||||
await db.schema.dropTable(inviteCodeTable).execute()
|
||||
await db.schema.dropTable(ipldBlockCreatorTable).execute()
|
||||
await db.schema.dropTable(ipldBlockTable).execute()
|
||||
await db.schema.dropTable(recordTable).execute()
|
||||
|
97
packages/pds/src/db/records/declaration.ts
Normal file
97
packages/pds/src/db/records/declaration.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import { Kysely } from 'kysely'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import * as Declaration from '../../lexicon/types/app/bsky/declaration'
|
||||
import { DbRecordPlugin, Notification } from '../types'
|
||||
import * as schemas from '../schemas'
|
||||
|
||||
const type = schemas.ids.AppBskyDeclaration
|
||||
const tableName = 'app_bsky_declaration'
|
||||
|
||||
export interface AppBskyDeclaration {
|
||||
uri: string
|
||||
cid: string
|
||||
creator: string
|
||||
actorType: string
|
||||
indexedAt: string
|
||||
}
|
||||
|
||||
export type PartialDB = { [tableName]: AppBskyDeclaration }
|
||||
|
||||
const validator = schemas.records.createRecordValidator(type)
|
||||
const matchesSchema = (obj: unknown): obj is Declaration.Record => {
|
||||
return validator.isValid(obj)
|
||||
}
|
||||
const validateSchema = (obj: unknown) => validator.validate(obj)
|
||||
|
||||
const translateDbObj = (dbObj: AppBskyDeclaration): Declaration.Record => {
|
||||
return {
|
||||
actorType: dbObj.actorType,
|
||||
}
|
||||
}
|
||||
|
||||
const getFn =
|
||||
(db: Kysely<PartialDB>) =>
|
||||
async (uri: AtUri): Promise<Declaration.Record | null> => {
|
||||
const found = await db
|
||||
.selectFrom(tableName)
|
||||
.selectAll()
|
||||
.where('uri', '=', uri.toString())
|
||||
.executeTakeFirst()
|
||||
return !found ? null : translateDbObj(found)
|
||||
}
|
||||
|
||||
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,
|
||||
actorType: obj.actorType,
|
||||
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[] => {
|
||||
return []
|
||||
}
|
||||
|
||||
export const makePlugin = (
|
||||
db: Kysely<PartialDB>,
|
||||
): DbRecordPlugin<Declaration.Record, AppBskyDeclaration> => {
|
||||
return {
|
||||
collection: type,
|
||||
tableName,
|
||||
validateSchema,
|
||||
matchesSchema,
|
||||
translateDbObj,
|
||||
get: getFn(db),
|
||||
insert: insertFn(db),
|
||||
delete: deleteFn(db),
|
||||
notifsForRecord,
|
||||
}
|
||||
}
|
||||
|
||||
export default makePlugin
|
@ -11,7 +11,8 @@ export interface AppBskyFollow {
|
||||
uri: string
|
||||
cid: string
|
||||
creator: string
|
||||
subject: string
|
||||
subjectDid: string
|
||||
subjectDeclarationCid: string
|
||||
createdAt: string
|
||||
indexedAt: string
|
||||
}
|
||||
@ -26,7 +27,10 @@ const validateSchema = (obj: unknown) => validator.validate(obj)
|
||||
|
||||
const translateDbObj = (dbObj: AppBskyFollow): Follow.Record => {
|
||||
return {
|
||||
subject: dbObj.subject,
|
||||
subject: {
|
||||
did: dbObj.subjectDid,
|
||||
declarationCid: dbObj.subjectDeclarationCid,
|
||||
},
|
||||
createdAt: dbObj.createdAt,
|
||||
}
|
||||
}
|
||||
@ -57,7 +61,8 @@ const insertFn =
|
||||
uri: uri.toString(),
|
||||
cid: cid.toString(),
|
||||
creator: uri.host,
|
||||
subject: obj.subject,
|
||||
subjectDid: obj.subject.did,
|
||||
subjectDeclarationCid: obj.subject.declarationCid,
|
||||
createdAt: obj.createdAt,
|
||||
indexedAt: timestamp || new Date().toISOString(),
|
||||
}
|
||||
@ -82,7 +87,7 @@ const notifsForRecord = (
|
||||
throw new Error(`Record does not match schema: ${type}`)
|
||||
}
|
||||
const notif = {
|
||||
userDid: obj.subject,
|
||||
userDid: obj.subject.did,
|
||||
author: uri.host,
|
||||
recordUri: uri.toString(),
|
||||
recordCid: cid.toString(),
|
||||
|
119
packages/pds/src/db/records/invite.ts
Normal file
119
packages/pds/src/db/records/invite.ts
Normal file
@ -0,0 +1,119 @@
|
||||
import { Kysely } from 'kysely'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import * as Invite from '../../lexicon/types/app/bsky/invite'
|
||||
import { DbRecordPlugin, Notification } from '../types'
|
||||
import * as schemas from '../schemas'
|
||||
|
||||
const type = schemas.ids.AppBskyInvite
|
||||
const tableName = 'app_bsky_invite'
|
||||
|
||||
export interface AppBskyInvite {
|
||||
uri: string
|
||||
cid: string
|
||||
creator: string
|
||||
group: string
|
||||
subjectDid: string
|
||||
subjectDeclarationCid: string
|
||||
createdAt: string
|
||||
indexedAt: string
|
||||
}
|
||||
|
||||
export type PartialDB = { [tableName]: AppBskyInvite }
|
||||
|
||||
const validator = schemas.records.createRecordValidator(type)
|
||||
const matchesSchema = (obj: unknown): obj is Invite.Record => {
|
||||
return validator.isValid(obj)
|
||||
}
|
||||
const validateSchema = (obj: unknown) => validator.validate(obj)
|
||||
|
||||
const translateDbObj = (dbObj: AppBskyInvite): Invite.Record => {
|
||||
return {
|
||||
group: dbObj.group,
|
||||
subject: {
|
||||
did: dbObj.subjectDid,
|
||||
declarationCid: dbObj.subjectDeclarationCid,
|
||||
},
|
||||
createdAt: dbObj.createdAt,
|
||||
}
|
||||
}
|
||||
|
||||
const getFn =
|
||||
(db: Kysely<PartialDB>) =>
|
||||
async (uri: AtUri): Promise<Invite.Record | null> => {
|
||||
const found = await db
|
||||
.selectFrom(tableName)
|
||||
.selectAll()
|
||||
.where('uri', '=', uri.toString())
|
||||
.executeTakeFirst()
|
||||
return !found ? null : translateDbObj(found)
|
||||
}
|
||||
|
||||
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,
|
||||
group: obj.group,
|
||||
subjectDid: obj.subject.did,
|
||||
subjectDeclarationCid: obj.subject.declarationCid,
|
||||
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 notif = {
|
||||
userDid: obj.subject.did,
|
||||
author: uri.host,
|
||||
recordUri: uri.toString(),
|
||||
recordCid: cid.toString(),
|
||||
reason: 'invite',
|
||||
reasonSubject: obj.group,
|
||||
}
|
||||
return [notif]
|
||||
}
|
||||
|
||||
export const makePlugin = (
|
||||
db: Kysely<PartialDB>,
|
||||
): DbRecordPlugin<Invite.Record, AppBskyInvite> => {
|
||||
return {
|
||||
collection: type,
|
||||
tableName,
|
||||
validateSchema,
|
||||
matchesSchema,
|
||||
translateDbObj,
|
||||
get: getFn(db),
|
||||
insert: insertFn(db),
|
||||
delete: deleteFn(db),
|
||||
notifsForRecord,
|
||||
}
|
||||
}
|
||||
|
||||
export default makePlugin
|
113
packages/pds/src/db/records/inviteAccept.ts
Normal file
113
packages/pds/src/db/records/inviteAccept.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { Kysely } from 'kysely'
|
||||
import { AtUri } from '@atproto/uri'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import * as InviteAccept from '../../lexicon/types/app/bsky/inviteAccept'
|
||||
import { DbRecordPlugin, Notification } from '../types'
|
||||
import * as schemas from '../schemas'
|
||||
|
||||
const type = schemas.ids.AppBskyInviteAccept
|
||||
const tableName = 'app_bsky_invite_accept'
|
||||
|
||||
export interface AppBskyInviteAccept {
|
||||
uri: string
|
||||
cid: string
|
||||
creator: string
|
||||
groupDid: string
|
||||
groupDeclarationCid: string
|
||||
inviteUri: string
|
||||
inviteCid: string
|
||||
createdAt: string
|
||||
indexedAt: string
|
||||
}
|
||||
|
||||
export type PartialDB = { [tableName]: AppBskyInviteAccept }
|
||||
|
||||
const validator = schemas.records.createRecordValidator(type)
|
||||
const matchesSchema = (obj: unknown): obj is InviteAccept.Record => {
|
||||
return validator.isValid(obj)
|
||||
}
|
||||
const validateSchema = (obj: unknown) => validator.validate(obj)
|
||||
|
||||
const translateDbObj = (dbObj: AppBskyInviteAccept): InviteAccept.Record => {
|
||||
return {
|
||||
group: {
|
||||
did: dbObj.groupDid,
|
||||
declarationCid: dbObj.groupDeclarationCid,
|
||||
},
|
||||
invite: {
|
||||
uri: dbObj.inviteUri,
|
||||
cid: dbObj.inviteCid,
|
||||
},
|
||||
createdAt: dbObj.createdAt,
|
||||
}
|
||||
}
|
||||
|
||||
const getFn =
|
||||
(db: Kysely<PartialDB>) =>
|
||||
async (uri: AtUri): Promise<InviteAccept.Record | null> => {
|
||||
const found = await db
|
||||
.selectFrom(tableName)
|
||||
.selectAll()
|
||||
.where('uri', '=', uri.toString())
|
||||
.executeTakeFirst()
|
||||
return !found ? null : translateDbObj(found)
|
||||
}
|
||||
|
||||
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,
|
||||
groupDid: obj.group.did,
|
||||
groupDeclarationCid: obj.group.declarationCid,
|
||||
inviteUri: obj.invite.uri,
|
||||
inviteCid: obj.invite.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[] => {
|
||||
return []
|
||||
}
|
||||
|
||||
export const makePlugin = (
|
||||
db: Kysely<PartialDB>,
|
||||
): DbRecordPlugin<InviteAccept.Record, AppBskyInviteAccept> => {
|
||||
return {
|
||||
collection: type,
|
||||
tableName,
|
||||
validateSchema,
|
||||
matchesSchema,
|
||||
translateDbObj,
|
||||
get: getFn(db),
|
||||
insert: insertFn(db),
|
||||
delete: deleteFn(db),
|
||||
notifsForRecord,
|
||||
}
|
||||
}
|
||||
|
||||
export default makePlugin
|
@ -38,5 +38,6 @@ export type NotificationReason =
|
||||
| 'repost'
|
||||
| 'follow'
|
||||
| 'badge'
|
||||
| 'invite'
|
||||
| 'mention'
|
||||
| 'reply'
|
||||
|
@ -39,7 +39,13 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['accessJwt', 'refreshJwt', 'username', 'did'],
|
||||
required: [
|
||||
'accessJwt',
|
||||
'refreshJwt',
|
||||
'username',
|
||||
'did',
|
||||
'declarationCid',
|
||||
],
|
||||
properties: {
|
||||
accessJwt: {
|
||||
type: 'string',
|
||||
@ -53,6 +59,9 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
$defs: {},
|
||||
},
|
||||
@ -1629,7 +1638,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
reason: {
|
||||
type: 'string',
|
||||
$comment:
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'mention' and 'reply'.",
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'invite', 'mention' and 'reply'.",
|
||||
},
|
||||
reasonSubject: {
|
||||
type: 'string',
|
||||
@ -1688,7 +1697,7 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
|
||||
reason: {
|
||||
type: 'string',
|
||||
$comment:
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'mention' and 'reply'.",
|
||||
"Expected values are 'like', 'repost', 'follow', 'badge', 'invite', 'mention' and 'reply'.",
|
||||
},
|
||||
reasonSubject: {
|
||||
type: 'string',
|
||||
@ -2592,7 +2601,10 @@ export const ids = {
|
||||
AppBskyBadge: 'app.bsky.badge',
|
||||
AppBskyBadgeAccept: 'app.bsky.badgeAccept',
|
||||
AppBskyBadgeOffer: 'app.bsky.badgeOffer',
|
||||
AppBskyDeclaration: 'app.bsky.declaration',
|
||||
AppBskyFollow: 'app.bsky.follow',
|
||||
AppBskyInvite: 'app.bsky.invite',
|
||||
AppBskyInviteAccept: 'app.bsky.inviteAccept',
|
||||
AppBskyLike: 'app.bsky.like',
|
||||
AppBskyMediaEmbed: 'app.bsky.mediaEmbed',
|
||||
AppBskyPost: 'app.bsky.post',
|
||||
@ -2823,6 +2835,54 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.declaration': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.declaration',
|
||||
description:
|
||||
'Context for an account that is considered intrinsic to it and alters the fundamental understanding of an account of changed. A declaration should be treated as immutable.',
|
||||
type: 'record',
|
||||
key: 'literal:self',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['actorType'],
|
||||
properties: {
|
||||
actorType: {
|
||||
oneOf: [
|
||||
{
|
||||
$ref: '#/$defs/actorKnown',
|
||||
},
|
||||
{
|
||||
$ref: '#/$defs/actorUnknown',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
$defs: {
|
||||
actorKnown: {
|
||||
type: 'string',
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
actorUnknown: {
|
||||
type: 'string',
|
||||
not: {
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
defs: {
|
||||
actorKnown: {
|
||||
type: 'string',
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
actorUnknown: {
|
||||
type: 'string',
|
||||
not: {
|
||||
enum: ['app.bsky.actorUser', 'app.bsky.actorScene'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'app.bsky.follow': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.follow',
|
||||
@ -2834,7 +2894,89 @@ export const recordSchemaDict: Record<string, RecordSchema> = {
|
||||
required: ['subject', 'createdAt'],
|
||||
properties: {
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['did', 'declarationCid'],
|
||||
properties: {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
},
|
||||
$defs: {},
|
||||
},
|
||||
},
|
||||
'app.bsky.invite': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.invite',
|
||||
type: 'record',
|
||||
key: 'tid',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['group', 'subject', 'createdAt'],
|
||||
properties: {
|
||||
group: {
|
||||
type: 'string',
|
||||
},
|
||||
subject: {
|
||||
type: 'object',
|
||||
required: ['did', 'declarationCid'],
|
||||
properties: {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
format: 'date-time',
|
||||
},
|
||||
},
|
||||
$defs: {},
|
||||
},
|
||||
},
|
||||
'app.bsky.inviteAccept': {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.inviteAccept',
|
||||
type: 'record',
|
||||
key: 'tid',
|
||||
record: {
|
||||
type: 'object',
|
||||
required: ['group', 'invite', 'createdAt'],
|
||||
properties: {
|
||||
group: {
|
||||
type: 'object',
|
||||
required: ['did', 'declarationCid'],
|
||||
properties: {
|
||||
did: {
|
||||
type: 'string',
|
||||
},
|
||||
declarationCid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
invite: {
|
||||
type: 'object',
|
||||
required: ['uri', 'cid'],
|
||||
properties: {
|
||||
uri: {
|
||||
type: 'string',
|
||||
},
|
||||
cid: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
createdAt: {
|
||||
type: 'string',
|
||||
|
10
packages/pds/src/lexicon/types/app/bsky/declaration.ts
Normal file
10
packages/pds/src/lexicon/types/app/bsky/declaration.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export type ActorKnown = 'app.bsky.actorUser' | 'app.bsky.actorScene'
|
||||
export type ActorUnknown = string
|
||||
|
||||
export interface Record {
|
||||
actorType: ActorKnown | ActorUnknown;
|
||||
[k: string]: unknown;
|
||||
}
|
@ -2,7 +2,11 @@
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
subject: string;
|
||||
subject: {
|
||||
did: string,
|
||||
declarationCid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
||||
|
13
packages/pds/src/lexicon/types/app/bsky/invite.ts
Normal file
13
packages/pds/src/lexicon/types/app/bsky/invite.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
group: string;
|
||||
subject: {
|
||||
did: string,
|
||||
declarationCid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
17
packages/pds/src/lexicon/types/app/bsky/inviteAccept.ts
Normal file
17
packages/pds/src/lexicon/types/app/bsky/inviteAccept.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
export interface Record {
|
||||
group: {
|
||||
did: string,
|
||||
declarationCid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
invite: {
|
||||
uri: string,
|
||||
cid: string,
|
||||
[k: string]: unknown,
|
||||
};
|
||||
createdAt: string;
|
||||
[k: string]: unknown;
|
||||
}
|
@ -40,6 +40,7 @@ export interface OutputSchema {
|
||||
refreshJwt: string;
|
||||
username: string;
|
||||
did: string;
|
||||
declarationCid: string;
|
||||
}
|
||||
|
||||
export type Handler = (
|
||||
|
@ -5,94 +5,83 @@ export default async (sc: SeedClient) => {
|
||||
await sc.createAccount('bob', users.bob)
|
||||
await sc.createAccount('carol', users.carol)
|
||||
await sc.createAccount('dan', users.dan)
|
||||
const alice = sc.dids.alice
|
||||
const bob = sc.dids.bob
|
||||
const carol = sc.dids.carol
|
||||
const dan = sc.dids.dan
|
||||
|
||||
await sc.createProfile(
|
||||
sc.dids.alice,
|
||||
alice,
|
||||
users.alice.displayName,
|
||||
users.alice.description,
|
||||
)
|
||||
await sc.createProfile(
|
||||
sc.dids.bob,
|
||||
users.bob.displayName,
|
||||
users.bob.description,
|
||||
)
|
||||
await sc.follow(sc.dids.alice, sc.dids.bob)
|
||||
await sc.follow(sc.dids.alice, sc.dids.carol)
|
||||
await sc.follow(sc.dids.alice, sc.dids.dan)
|
||||
await sc.follow(sc.dids.carol, sc.dids.alice)
|
||||
await sc.follow(sc.dids.bob, sc.dids.alice)
|
||||
await sc.follow(sc.dids.bob, sc.dids.carol)
|
||||
await sc.follow(sc.dids.dan, sc.dids.bob)
|
||||
await sc.post(sc.dids.alice, posts.alice[0])
|
||||
await sc.post(sc.dids.bob, posts.bob[0])
|
||||
await sc.post(sc.dids.carol, posts.carol[0])
|
||||
await sc.post(sc.dids.dan, posts.dan[0])
|
||||
await sc.post(sc.dids.dan, posts.dan[1], [
|
||||
await sc.createProfile(bob, users.bob.displayName, users.bob.description)
|
||||
await sc.follow(alice, sc.userRef(bob))
|
||||
await sc.follow(alice, sc.userRef(carol))
|
||||
await sc.follow(alice, sc.userRef(dan))
|
||||
await sc.follow(carol, sc.userRef(alice))
|
||||
await sc.follow(bob, sc.userRef(alice))
|
||||
await sc.follow(bob, sc.userRef(carol))
|
||||
await sc.follow(dan, sc.userRef(bob))
|
||||
await sc.post(alice, posts.alice[0])
|
||||
await sc.post(bob, posts.bob[0])
|
||||
await sc.post(carol, posts.carol[0])
|
||||
await sc.post(dan, posts.dan[0])
|
||||
await sc.post(dan, posts.dan[1], [
|
||||
{
|
||||
index: [0, 18],
|
||||
type: 'mention',
|
||||
value: sc.dids.alice,
|
||||
value: alice,
|
||||
},
|
||||
])
|
||||
await sc.post(sc.dids.alice, posts.alice[1])
|
||||
await sc.post(sc.dids.bob, posts.bob[1])
|
||||
await sc.post(sc.dids.alice, posts.alice[2])
|
||||
await sc.like(sc.dids.bob, sc.posts[sc.dids.alice][1].ref)
|
||||
await sc.like(sc.dids.bob, sc.posts[sc.dids.alice][2].ref)
|
||||
await sc.like(sc.dids.carol, sc.posts[sc.dids.alice][1].ref)
|
||||
await sc.like(sc.dids.carol, sc.posts[sc.dids.alice][2].ref)
|
||||
await sc.like(sc.dids.dan, sc.posts[sc.dids.alice][1].ref)
|
||||
await sc.post(alice, posts.alice[1])
|
||||
await sc.post(bob, posts.bob[1])
|
||||
await sc.post(alice, posts.alice[2])
|
||||
await sc.like(bob, sc.posts[alice][1].ref)
|
||||
await sc.like(bob, sc.posts[alice][2].ref)
|
||||
await sc.like(carol, sc.posts[alice][1].ref)
|
||||
await sc.like(carol, sc.posts[alice][2].ref)
|
||||
await sc.like(dan, sc.posts[alice][1].ref)
|
||||
await sc.reply(
|
||||
sc.dids.bob,
|
||||
sc.posts[sc.dids.alice][1].ref,
|
||||
sc.posts[sc.dids.alice][1].ref,
|
||||
bob,
|
||||
sc.posts[alice][1].ref,
|
||||
sc.posts[alice][1].ref,
|
||||
replies.bob[0],
|
||||
)
|
||||
await sc.reply(
|
||||
sc.dids.carol,
|
||||
sc.posts[sc.dids.alice][1].ref,
|
||||
sc.posts[sc.dids.alice][1].ref,
|
||||
carol,
|
||||
sc.posts[alice][1].ref,
|
||||
sc.posts[alice][1].ref,
|
||||
replies.carol[0],
|
||||
)
|
||||
await sc.reply(
|
||||
sc.dids.alice,
|
||||
sc.posts[sc.dids.alice][1].ref,
|
||||
sc.replies[sc.dids.bob][0].ref,
|
||||
alice,
|
||||
sc.posts[alice][1].ref,
|
||||
sc.replies[bob][0].ref,
|
||||
replies.alice[0],
|
||||
)
|
||||
await sc.repost(sc.dids.carol, sc.posts[sc.dids.dan][1].ref)
|
||||
await sc.repost(sc.dids.dan, sc.posts[sc.dids.alice][1].ref)
|
||||
await sc.repost(carol, sc.posts[dan][1].ref)
|
||||
await sc.repost(dan, sc.posts[alice][1].ref)
|
||||
|
||||
await sc.createBadge(sc.dids.bob, 'employee')
|
||||
await sc.createBadge(sc.dids.bob, 'tag', 'cool')
|
||||
await sc.createBadge(sc.dids.carol, 'tag', 'neat')
|
||||
await sc.createBadge(sc.dids.carol, 'tag', 'cringe')
|
||||
await sc.createBadge(bob, 'employee')
|
||||
await sc.createBadge(bob, 'tag', 'cool')
|
||||
await sc.createBadge(carol, 'tag', 'neat')
|
||||
await sc.createBadge(carol, 'tag', 'cringe')
|
||||
|
||||
await sc.offerBadge(sc.dids.bob, sc.dids.alice, sc.badges[sc.dids.bob][0])
|
||||
await sc.offerBadge(sc.dids.bob, sc.dids.alice, sc.badges[sc.dids.bob][1])
|
||||
await sc.offerBadge(sc.dids.bob, sc.dids.bob, sc.badges[sc.dids.bob][1])
|
||||
await sc.offerBadge(sc.dids.bob, sc.dids.carol, sc.badges[sc.dids.bob][1])
|
||||
await sc.offerBadge(sc.dids.bob, sc.dids.dan, sc.badges[sc.dids.bob][1])
|
||||
await sc.offerBadge(sc.dids.carol, sc.dids.alice, sc.badges[sc.dids.carol][0])
|
||||
await sc.offerBadge(bob, alice, sc.badges[bob][0])
|
||||
await sc.offerBadge(bob, alice, sc.badges[bob][1])
|
||||
await sc.offerBadge(bob, bob, sc.badges[bob][1])
|
||||
await sc.offerBadge(bob, carol, sc.badges[bob][1])
|
||||
await sc.offerBadge(bob, dan, sc.badges[bob][1])
|
||||
await sc.offerBadge(carol, alice, sc.badges[carol][0])
|
||||
|
||||
await sc.acceptBadge(alice, sc.badges[bob][1], sc.badgeOffers[bob][alice][1])
|
||||
await sc.acceptBadge(bob, sc.badges[bob][1], sc.badgeOffers[bob][bob][0])
|
||||
await sc.acceptBadge(carol, sc.badges[bob][1], sc.badgeOffers[bob][carol][0])
|
||||
await sc.acceptBadge(
|
||||
sc.dids.alice,
|
||||
sc.badges[sc.dids.bob][1],
|
||||
sc.badgeOffers[sc.dids.bob][sc.dids.alice][1],
|
||||
)
|
||||
await sc.acceptBadge(
|
||||
sc.dids.bob,
|
||||
sc.badges[sc.dids.bob][1],
|
||||
sc.badgeOffers[sc.dids.bob][sc.dids.bob][0],
|
||||
)
|
||||
await sc.acceptBadge(
|
||||
sc.dids.carol,
|
||||
sc.badges[sc.dids.bob][1],
|
||||
sc.badgeOffers[sc.dids.bob][sc.dids.carol][0],
|
||||
)
|
||||
await sc.acceptBadge(
|
||||
sc.dids.alice,
|
||||
sc.badges[sc.dids.carol][0],
|
||||
sc.badgeOffers[sc.dids.carol][sc.dids.alice][0],
|
||||
alice,
|
||||
sc.badges[carol][0],
|
||||
sc.badgeOffers[carol][alice][0],
|
||||
)
|
||||
|
||||
return sc
|
||||
|
@ -5,7 +5,7 @@ import { CID } from 'multiformats/cid'
|
||||
// Makes it simple to create data via the XRPC client,
|
||||
// and keeps track of all created data in memory for convenience.
|
||||
|
||||
class Reference {
|
||||
class RecordRef {
|
||||
uri: AtUri
|
||||
cid: CID
|
||||
|
||||
@ -30,6 +30,27 @@ class Reference {
|
||||
}
|
||||
}
|
||||
|
||||
class UserRef {
|
||||
did: string
|
||||
declarationCid: CID
|
||||
|
||||
constructor(did: string, declarationCid: CID | string) {
|
||||
this.did = did
|
||||
this.declarationCid = CID.parse(declarationCid.toString())
|
||||
}
|
||||
|
||||
get raw(): { did: string; declarationCid: string } {
|
||||
return {
|
||||
did: this.did.toString(),
|
||||
declarationCid: this.declarationCid.toString(),
|
||||
}
|
||||
}
|
||||
|
||||
get declarationStr(): string {
|
||||
return this.declarationCid.toString()
|
||||
}
|
||||
}
|
||||
|
||||
export class SeedClient {
|
||||
accounts: Record<
|
||||
string,
|
||||
@ -40,6 +61,7 @@ export class SeedClient {
|
||||
username: string
|
||||
email: string
|
||||
password: string
|
||||
ref: UserRef
|
||||
}
|
||||
>
|
||||
profiles: Record<
|
||||
@ -47,16 +69,16 @@ export class SeedClient {
|
||||
{
|
||||
displayName: string
|
||||
description: string
|
||||
ref: Reference
|
||||
ref: RecordRef
|
||||
}
|
||||
>
|
||||
follows: Record<string, Record<string, Reference>>
|
||||
posts: Record<string, { text: string; ref: Reference }[]>
|
||||
follows: Record<string, Record<string, RecordRef>>
|
||||
posts: Record<string, { text: string; ref: RecordRef }[]>
|
||||
likes: Record<string, Record<string, AtUri>>
|
||||
replies: Record<string, { text: string; ref: Reference }[]>
|
||||
reposts: Record<string, Reference[]>
|
||||
badges: Record<string, Reference[]>
|
||||
badgeOffers: Record<string, Record<string, Reference[]>>
|
||||
replies: Record<string, { text: string; ref: RecordRef }[]>
|
||||
reposts: Record<string, RecordRef[]>
|
||||
badges: Record<string, RecordRef[]>
|
||||
badgeOffers: Record<string, Record<string, RecordRef[]>>
|
||||
dids: Record<string, string>
|
||||
|
||||
constructor(public client: ServiceClient) {
|
||||
@ -86,6 +108,7 @@ export class SeedClient {
|
||||
...data,
|
||||
email: params.email,
|
||||
password: params.password,
|
||||
ref: new UserRef(data.did, data.declarationCid),
|
||||
}
|
||||
return this.accounts[shortName]
|
||||
}
|
||||
@ -99,20 +122,23 @@ export class SeedClient {
|
||||
this.profiles[by] = {
|
||||
displayName,
|
||||
description,
|
||||
ref: new Reference(res.uri, res.cid),
|
||||
ref: new RecordRef(res.uri, res.cid),
|
||||
}
|
||||
return this.profiles[by]
|
||||
}
|
||||
|
||||
async follow(from: string, to: string) {
|
||||
async follow(from: string, to: UserRef) {
|
||||
const res = await this.client.app.bsky.follow.create(
|
||||
{ did: from },
|
||||
{ subject: to, createdAt: new Date().toISOString() },
|
||||
{
|
||||
subject: to.raw,
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
this.getHeaders(from),
|
||||
)
|
||||
this.follows[from] ??= {}
|
||||
this.follows[from][to] = new Reference(res.uri, res.cid)
|
||||
return this.follows[from][to]
|
||||
this.follows[from][to.did] = new RecordRef(res.uri, res.cid)
|
||||
return this.follows[from][to.did]
|
||||
}
|
||||
|
||||
async post(by: string, text: string, entities?: any) {
|
||||
@ -124,13 +150,13 @@ export class SeedClient {
|
||||
this.posts[by] ??= []
|
||||
const post = {
|
||||
text,
|
||||
ref: new Reference(res.uri, res.cid),
|
||||
ref: new RecordRef(res.uri, res.cid),
|
||||
}
|
||||
this.posts[by].push(post)
|
||||
return post
|
||||
}
|
||||
|
||||
async like(by: string, subject: Reference) {
|
||||
async like(by: string, subject: RecordRef) {
|
||||
const res = await this.client.app.bsky.like.create(
|
||||
{ did: by },
|
||||
{ subject: subject.raw, createdAt: new Date().toISOString() },
|
||||
@ -141,7 +167,7 @@ export class SeedClient {
|
||||
return this.likes[by][subject.uriStr]
|
||||
}
|
||||
|
||||
async reply(by: string, root: Reference, parent: Reference, text: string) {
|
||||
async reply(by: string, root: RecordRef, parent: RecordRef, text: string) {
|
||||
const res = await this.client.app.bsky.post.create(
|
||||
{ did: by },
|
||||
{
|
||||
@ -157,20 +183,20 @@ export class SeedClient {
|
||||
this.replies[by] ??= []
|
||||
const reply = {
|
||||
text,
|
||||
ref: new Reference(res.uri, res.cid),
|
||||
ref: new RecordRef(res.uri, res.cid),
|
||||
}
|
||||
this.replies[by].push(reply)
|
||||
return reply
|
||||
}
|
||||
|
||||
async repost(by: string, subject: Reference) {
|
||||
async repost(by: string, subject: RecordRef) {
|
||||
const res = await this.client.app.bsky.repost.create(
|
||||
{ did: by },
|
||||
{ subject: subject.raw, createdAt: new Date().toISOString() },
|
||||
this.getHeaders(by),
|
||||
)
|
||||
this.reposts[by] ??= []
|
||||
const repost = new Reference(res.uri, res.cid)
|
||||
const repost = new RecordRef(res.uri, res.cid)
|
||||
this.reposts[by].push(repost)
|
||||
return repost
|
||||
}
|
||||
@ -188,12 +214,12 @@ export class SeedClient {
|
||||
this.getHeaders(by),
|
||||
)
|
||||
this.badges[by] ??= []
|
||||
const badge = new Reference(res.uri, res.cid)
|
||||
const badge = new RecordRef(res.uri, res.cid)
|
||||
this.badges[by].push(badge)
|
||||
return badge
|
||||
}
|
||||
|
||||
async offerBadge(from: string, to: string, badge: Reference) {
|
||||
async offerBadge(from: string, to: string, badge: RecordRef) {
|
||||
const res = await this.client.app.bsky.badgeOffer.create(
|
||||
{ did: from },
|
||||
{
|
||||
@ -205,12 +231,12 @@ export class SeedClient {
|
||||
)
|
||||
this.badgeOffers[from] ??= {}
|
||||
this.badgeOffers[from][to] ??= []
|
||||
const offer = new Reference(res.uri, res.cid)
|
||||
const offer = new RecordRef(res.uri, res.cid)
|
||||
this.badgeOffers[from][to].push(offer)
|
||||
return offer
|
||||
}
|
||||
|
||||
async acceptBadge(by: string, badge: Reference, offer: Reference) {
|
||||
async acceptBadge(by: string, badge: RecordRef, offer: RecordRef) {
|
||||
await this.client.app.bsky.badgeAccept.create(
|
||||
{ did: by },
|
||||
{
|
||||
@ -222,6 +248,10 @@ export class SeedClient {
|
||||
)
|
||||
}
|
||||
|
||||
userRef(did: string): UserRef {
|
||||
return this.accounts[did].ref
|
||||
}
|
||||
|
||||
getHeaders(did: string) {
|
||||
return SeedClient.getHeaders(this.accounts[did].accessJwt)
|
||||
}
|
||||
|
@ -6,18 +6,23 @@ export default async (sc: SeedClient) => {
|
||||
await sc.createAccount('carol', users.carol)
|
||||
await sc.createAccount('dan', users.dan)
|
||||
await sc.createAccount('eve', users.eve)
|
||||
await sc.follow(sc.dids.alice, sc.dids.bob)
|
||||
await sc.follow(sc.dids.alice, sc.dids.carol)
|
||||
await sc.follow(sc.dids.alice, sc.dids.dan)
|
||||
await sc.follow(sc.dids.alice, sc.dids.eve)
|
||||
await sc.follow(sc.dids.carol, sc.dids.alice)
|
||||
await sc.follow(sc.dids.bob, sc.dids.alice)
|
||||
await sc.follow(sc.dids.bob, sc.dids.carol)
|
||||
await sc.follow(sc.dids.dan, sc.dids.alice)
|
||||
await sc.follow(sc.dids.dan, sc.dids.bob)
|
||||
await sc.follow(sc.dids.dan, sc.dids.eve)
|
||||
await sc.follow(sc.dids.eve, sc.dids.alice)
|
||||
await sc.follow(sc.dids.eve, sc.dids.carol)
|
||||
const alice = sc.dids.alice
|
||||
const bob = sc.dids.bob
|
||||
const carol = sc.dids.carol
|
||||
const dan = sc.dids.dan
|
||||
const eve = sc.dids.eve
|
||||
await sc.follow(alice, sc.userRef(bob))
|
||||
await sc.follow(alice, sc.userRef(carol))
|
||||
await sc.follow(alice, sc.userRef(dan))
|
||||
await sc.follow(alice, sc.userRef(eve))
|
||||
await sc.follow(carol, sc.userRef(alice))
|
||||
await sc.follow(bob, sc.userRef(alice))
|
||||
await sc.follow(bob, sc.userRef(carol))
|
||||
await sc.follow(dan, sc.userRef(alice))
|
||||
await sc.follow(dan, sc.userRef(bob))
|
||||
await sc.follow(dan, sc.userRef(eve))
|
||||
await sc.follow(eve, sc.userRef(alice))
|
||||
await sc.follow(eve, sc.userRef(carol))
|
||||
}
|
||||
|
||||
const users = {
|
||||
|
@ -283,7 +283,10 @@ Array [
|
||||
"record": Object {
|
||||
"$type": "app.bsky.follow",
|
||||
"createdAt": "1970-01-01T00:00:00.000Z",
|
||||
"subject": "user(1)",
|
||||
"subject": Object {
|
||||
"declarationCid": "cids(18)",
|
||||
"did": "user(1)",
|
||||
},
|
||||
},
|
||||
"uri": "record(17)",
|
||||
},
|
||||
@ -292,14 +295,17 @@ Array [
|
||||
"did": "user(0)",
|
||||
"name": "carol.test",
|
||||
},
|
||||
"cid": "cids(18)",
|
||||
"cid": "cids(19)",
|
||||
"indexedAt": "1970-01-01T00:00:00.000Z",
|
||||
"isRead": true,
|
||||
"reason": "follow",
|
||||
"record": Object {
|
||||
"$type": "app.bsky.follow",
|
||||
"createdAt": "1970-01-01T00:00:00.000Z",
|
||||
"subject": "user(1)",
|
||||
"subject": Object {
|
||||
"declarationCid": "cids(18)",
|
||||
"did": "user(1)",
|
||||
},
|
||||
},
|
||||
"uri": "record(18)",
|
||||
},
|
||||
@ -589,7 +595,10 @@ Array [
|
||||
"record": Object {
|
||||
"$type": "app.bsky.follow",
|
||||
"createdAt": "1970-01-01T00:00:00.000Z",
|
||||
"subject": "user(1)",
|
||||
"subject": Object {
|
||||
"declarationCid": "cids(18)",
|
||||
"did": "user(1)",
|
||||
},
|
||||
},
|
||||
"uri": "record(17)",
|
||||
},
|
||||
@ -598,14 +607,17 @@ Array [
|
||||
"did": "user(0)",
|
||||
"name": "carol.test",
|
||||
},
|
||||
"cid": "cids(18)",
|
||||
"cid": "cids(19)",
|
||||
"indexedAt": "1970-01-01T00:00:00.000Z",
|
||||
"isRead": false,
|
||||
"reason": "follow",
|
||||
"record": Object {
|
||||
"$type": "app.bsky.follow",
|
||||
"createdAt": "1970-01-01T00:00:00.000Z",
|
||||
"subject": "user(1)",
|
||||
"subject": Object {
|
||||
"declarationCid": "cids(18)",
|
||||
"did": "user(1)",
|
||||
},
|
||||
},
|
||||
"uri": "record(18)",
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user