Notification preferences V2 endpoints (#3901)
Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com> Co-authored-by: rafael <rafael@blueskyweb.xyz>
This commit is contained in:
parent
cd4bed3c9e
commit
a48671e730
8
.changeset/violet-trees-dress.md
Normal file
8
.changeset/violet-trees-dress.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
"@atproto/ozone": patch
|
||||
"@atproto/bsky": patch
|
||||
"@atproto/api": patch
|
||||
"@atproto/pds": patch
|
||||
---
|
||||
|
||||
Add notification preferences V2 lexicons
|
@ -5,6 +5,64 @@
|
||||
"recordDeleted": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
},
|
||||
"chatPreference": {
|
||||
"type": "object",
|
||||
"required": ["filter", "push"],
|
||||
"properties": {
|
||||
"filter": { "type": "string", "knownValues": ["all", "accepted"] },
|
||||
"push": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
"filterablePreference": {
|
||||
"type": "object",
|
||||
"required": ["filter", "list", "push"],
|
||||
"properties": {
|
||||
"filter": { "type": "string", "knownValues": ["all", "follows"] },
|
||||
"list": { "type": "boolean" },
|
||||
"push": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
"preference": {
|
||||
"type": "object",
|
||||
"required": ["list", "push"],
|
||||
"properties": {
|
||||
"list": { "type": "boolean" },
|
||||
"push": { "type": "boolean" }
|
||||
}
|
||||
},
|
||||
"preferences": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"chat",
|
||||
"follow",
|
||||
"like",
|
||||
"likeViaRepost",
|
||||
"mention",
|
||||
"quote",
|
||||
"reply",
|
||||
"repost",
|
||||
"repostViaRepost",
|
||||
"starterpackJoined",
|
||||
"subscribedPost",
|
||||
"unverified",
|
||||
"verified"
|
||||
],
|
||||
"properties": {
|
||||
"chat": { "type": "ref", "ref": "#chatPreference" },
|
||||
"follow": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"like": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"likeViaRepost": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"mention": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"quote": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"reply": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"repost": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"repostViaRepost": { "type": "ref", "ref": "#filterablePreference" },
|
||||
"starterpackJoined": { "type": "ref", "ref": "#preference" },
|
||||
"subscribedPost": { "type": "ref", "ref": "#preference" },
|
||||
"unverified": { "type": "ref", "ref": "#preference" },
|
||||
"verified": { "type": "ref", "ref": "#preference" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
lexicons/app/bsky/notification/getPreferences.json
Normal file
27
lexicons/app/bsky/notification/getPreferences.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"lexicon": 1,
|
||||
"id": "app.bsky.notification.getPreferences",
|
||||
"defs": {
|
||||
"main": {
|
||||
"type": "query",
|
||||
"description": "Get notification-related preferences for an account. Requires auth.",
|
||||
"parameters": {
|
||||
"type": "params",
|
||||
"properties": {}
|
||||
},
|
||||
"output": {
|
||||
"encoding": "application/json",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": ["preferences"],
|
||||
"properties": {
|
||||
"preferences": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#preferences"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
83
lexicons/app/bsky/notification/putPreferencesV2.json
Normal file
83
lexicons/app/bsky/notification/putPreferencesV2.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"lexicon": 1,
|
||||
"id": "app.bsky.notification.putPreferencesV2",
|
||||
"defs": {
|
||||
"main": {
|
||||
"type": "procedure",
|
||||
"description": "Set notification-related preferences for an account. Requires auth.",
|
||||
"input": {
|
||||
"encoding": "application/json",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"chat": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#chatPreference"
|
||||
},
|
||||
"follow": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"like": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"likeViaRepost": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"mention": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"quote": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"reply": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"repost": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"repostViaRepost": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#filterablePreference"
|
||||
},
|
||||
"starterpackJoined": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#preference"
|
||||
},
|
||||
"subscribedPost": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#preference"
|
||||
},
|
||||
"unverified": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#preference"
|
||||
},
|
||||
"verified": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#preference"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"encoding": "application/json",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": ["preferences"],
|
||||
"properties": {
|
||||
"preferences": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.notification.defs#preferences"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
packages/api/src/client/index.ts
generated
28
packages/api/src/client/index.ts
generated
@ -174,9 +174,11 @@ import * as AppBskyLabelerDefs from './types/app/bsky/labeler/defs.js'
|
||||
import * as AppBskyLabelerGetServices from './types/app/bsky/labeler/getServices.js'
|
||||
import * as AppBskyLabelerService from './types/app/bsky/labeler/service.js'
|
||||
import * as AppBskyNotificationDefs from './types/app/bsky/notification/defs.js'
|
||||
import * as AppBskyNotificationGetPreferences from './types/app/bsky/notification/getPreferences.js'
|
||||
import * as AppBskyNotificationGetUnreadCount from './types/app/bsky/notification/getUnreadCount.js'
|
||||
import * as AppBskyNotificationListNotifications from './types/app/bsky/notification/listNotifications.js'
|
||||
import * as AppBskyNotificationPutPreferences from './types/app/bsky/notification/putPreferences.js'
|
||||
import * as AppBskyNotificationPutPreferencesV2 from './types/app/bsky/notification/putPreferencesV2.js'
|
||||
import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/registerPush.js'
|
||||
import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen.js'
|
||||
import * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet.js'
|
||||
@ -437,9 +439,11 @@ export * as AppBskyLabelerDefs from './types/app/bsky/labeler/defs.js'
|
||||
export * as AppBskyLabelerGetServices from './types/app/bsky/labeler/getServices.js'
|
||||
export * as AppBskyLabelerService from './types/app/bsky/labeler/service.js'
|
||||
export * as AppBskyNotificationDefs from './types/app/bsky/notification/defs.js'
|
||||
export * as AppBskyNotificationGetPreferences from './types/app/bsky/notification/getPreferences.js'
|
||||
export * as AppBskyNotificationGetUnreadCount from './types/app/bsky/notification/getUnreadCount.js'
|
||||
export * as AppBskyNotificationListNotifications from './types/app/bsky/notification/listNotifications.js'
|
||||
export * as AppBskyNotificationPutPreferences from './types/app/bsky/notification/putPreferences.js'
|
||||
export * as AppBskyNotificationPutPreferencesV2 from './types/app/bsky/notification/putPreferencesV2.js'
|
||||
export * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/registerPush.js'
|
||||
export * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen.js'
|
||||
export * as AppBskyRichtextFacet from './types/app/bsky/richtext/facet.js'
|
||||
@ -3343,6 +3347,18 @@ export class AppBskyNotificationNS {
|
||||
this._client = client
|
||||
}
|
||||
|
||||
getPreferences(
|
||||
params?: AppBskyNotificationGetPreferences.QueryParams,
|
||||
opts?: AppBskyNotificationGetPreferences.CallOptions,
|
||||
): Promise<AppBskyNotificationGetPreferences.Response> {
|
||||
return this._client.call(
|
||||
'app.bsky.notification.getPreferences',
|
||||
params,
|
||||
undefined,
|
||||
opts,
|
||||
)
|
||||
}
|
||||
|
||||
getUnreadCount(
|
||||
params?: AppBskyNotificationGetUnreadCount.QueryParams,
|
||||
opts?: AppBskyNotificationGetUnreadCount.CallOptions,
|
||||
@ -3379,6 +3395,18 @@ export class AppBskyNotificationNS {
|
||||
)
|
||||
}
|
||||
|
||||
putPreferencesV2(
|
||||
data?: AppBskyNotificationPutPreferencesV2.InputSchema,
|
||||
opts?: AppBskyNotificationPutPreferencesV2.CallOptions,
|
||||
): Promise<AppBskyNotificationPutPreferencesV2.Response> {
|
||||
return this._client.call(
|
||||
'app.bsky.notification.putPreferencesV2',
|
||||
opts?.qp,
|
||||
data,
|
||||
opts,
|
||||
)
|
||||
}
|
||||
|
||||
registerPush(
|
||||
data?: AppBskyNotificationRegisterPush.InputSchema,
|
||||
opts?: AppBskyNotificationRegisterPush.CallOptions,
|
||||
|
227
packages/api/src/client/lexicons.ts
generated
227
packages/api/src/client/lexicons.ts
generated
@ -9732,6 +9732,147 @@ export const schemaDict = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
chatPreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'accepted'],
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
filterablePreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'list', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'follows'],
|
||||
},
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preference: {
|
||||
type: 'object',
|
||||
required: ['list', 'push'],
|
||||
properties: {
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preferences: {
|
||||
type: 'object',
|
||||
required: [
|
||||
'chat',
|
||||
'follow',
|
||||
'like',
|
||||
'likeViaRepost',
|
||||
'mention',
|
||||
'quote',
|
||||
'reply',
|
||||
'repost',
|
||||
'repostViaRepost',
|
||||
'starterpackJoined',
|
||||
'subscribedPost',
|
||||
'unverified',
|
||||
'verified',
|
||||
],
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetPreferences: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.getPreferences',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'query',
|
||||
description:
|
||||
'Get notification-related preferences for an account. Requires auth.',
|
||||
parameters: {
|
||||
type: 'params',
|
||||
properties: {},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetUnreadCount: {
|
||||
@ -9924,6 +10065,90 @@ export const schemaDict = {
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationPutPreferencesV2: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.putPreferencesV2',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'procedure',
|
||||
description:
|
||||
'Set notification-related preferences for an account. Requires auth.',
|
||||
input: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationRegisterPush: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.registerPush',
|
||||
@ -16557,10 +16782,12 @@ export const ids = {
|
||||
AppBskyLabelerGetServices: 'app.bsky.labeler.getServices',
|
||||
AppBskyLabelerService: 'app.bsky.labeler.service',
|
||||
AppBskyNotificationDefs: 'app.bsky.notification.defs',
|
||||
AppBskyNotificationGetPreferences: 'app.bsky.notification.getPreferences',
|
||||
AppBskyNotificationGetUnreadCount: 'app.bsky.notification.getUnreadCount',
|
||||
AppBskyNotificationListNotifications:
|
||||
'app.bsky.notification.listNotifications',
|
||||
AppBskyNotificationPutPreferences: 'app.bsky.notification.putPreferences',
|
||||
AppBskyNotificationPutPreferencesV2: 'app.bsky.notification.putPreferencesV2',
|
||||
AppBskyNotificationRegisterPush: 'app.bsky.notification.registerPush',
|
||||
AppBskyNotificationUpdateSeen: 'app.bsky.notification.updateSeen',
|
||||
AppBskyRichtextFacet: 'app.bsky.richtext.facet',
|
||||
|
@ -27,3 +27,79 @@ export function isRecordDeleted<V>(v: V) {
|
||||
export function validateRecordDeleted<V>(v: V) {
|
||||
return validate<RecordDeleted & V>(v, id, hashRecordDeleted)
|
||||
}
|
||||
|
||||
export interface ChatPreference {
|
||||
$type?: 'app.bsky.notification.defs#chatPreference'
|
||||
filter: 'all' | 'accepted' | (string & {})
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashChatPreference = 'chatPreference'
|
||||
|
||||
export function isChatPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export function validateChatPreference<V>(v: V) {
|
||||
return validate<ChatPreference & V>(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export interface FilterablePreference {
|
||||
$type?: 'app.bsky.notification.defs#filterablePreference'
|
||||
filter: 'all' | 'follows' | (string & {})
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashFilterablePreference = 'filterablePreference'
|
||||
|
||||
export function isFilterablePreference<V>(v: V) {
|
||||
return is$typed(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export function validateFilterablePreference<V>(v: V) {
|
||||
return validate<FilterablePreference & V>(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export interface Preference {
|
||||
$type?: 'app.bsky.notification.defs#preference'
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashPreference = 'preference'
|
||||
|
||||
export function isPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export function validatePreference<V>(v: V) {
|
||||
return validate<Preference & V>(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export interface Preferences {
|
||||
$type?: 'app.bsky.notification.defs#preferences'
|
||||
chat: ChatPreference
|
||||
follow: FilterablePreference
|
||||
like: FilterablePreference
|
||||
likeViaRepost: FilterablePreference
|
||||
mention: FilterablePreference
|
||||
quote: FilterablePreference
|
||||
reply: FilterablePreference
|
||||
repost: FilterablePreference
|
||||
repostViaRepost: FilterablePreference
|
||||
starterpackJoined: Preference
|
||||
subscribedPost: Preference
|
||||
unverified: Preference
|
||||
verified: Preference
|
||||
}
|
||||
|
||||
const hashPreferences = 'preferences'
|
||||
|
||||
export function isPreferences<V>(v: V) {
|
||||
return is$typed(v, id, hashPreferences)
|
||||
}
|
||||
|
||||
export function validatePreferences<V>(v: V) {
|
||||
return validate<Preferences & V>(v, id, hashPreferences)
|
||||
}
|
||||
|
40
packages/api/src/client/types/app/bsky/notification/getPreferences.ts
generated
Normal file
40
packages/api/src/client/types/app/bsky/notification/getPreferences.ts
generated
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import { HeadersMap, XRPCError } from '@atproto/xrpc'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.getPreferences'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export type InputSchema = undefined
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export interface CallOptions {
|
||||
signal?: AbortSignal
|
||||
headers?: HeadersMap
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
success: boolean
|
||||
headers: HeadersMap
|
||||
data: OutputSchema
|
||||
}
|
||||
|
||||
export function toKnownErr(e: any) {
|
||||
return e
|
||||
}
|
56
packages/api/src/client/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
56
packages/api/src/client/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import { HeadersMap, XRPCError } from '@atproto/xrpc'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.putPreferencesV2'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export interface InputSchema {
|
||||
chat?: AppBskyNotificationDefs.ChatPreference
|
||||
follow?: AppBskyNotificationDefs.FilterablePreference
|
||||
like?: AppBskyNotificationDefs.FilterablePreference
|
||||
likeViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
mention?: AppBskyNotificationDefs.FilterablePreference
|
||||
quote?: AppBskyNotificationDefs.FilterablePreference
|
||||
reply?: AppBskyNotificationDefs.FilterablePreference
|
||||
repost?: AppBskyNotificationDefs.FilterablePreference
|
||||
repostViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
starterpackJoined?: AppBskyNotificationDefs.Preference
|
||||
subscribedPost?: AppBskyNotificationDefs.Preference
|
||||
unverified?: AppBskyNotificationDefs.Preference
|
||||
verified?: AppBskyNotificationDefs.Preference
|
||||
}
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export interface CallOptions {
|
||||
signal?: AbortSignal
|
||||
headers?: HeadersMap
|
||||
qp?: QueryParams
|
||||
encoding?: 'application/json'
|
||||
}
|
||||
|
||||
export interface Response {
|
||||
success: boolean
|
||||
headers: HeadersMap
|
||||
data: OutputSchema
|
||||
}
|
||||
|
||||
export function toKnownErr(e: any) {
|
||||
return e
|
||||
}
|
@ -753,6 +753,66 @@ message GetBlocklistSubscriptionsResponse {
|
||||
// Notifications
|
||||
//
|
||||
|
||||
message GetNotificationPreferencesRequest {
|
||||
repeated string dids = 1;
|
||||
}
|
||||
|
||||
message NotificationChannelList {
|
||||
bool enabled = 1;
|
||||
}
|
||||
|
||||
message NotificationChannelPush {
|
||||
bool enabled = 1;
|
||||
}
|
||||
|
||||
enum NotificationFilter {
|
||||
NOTIFICATION_FILTER_UNSPECIFIED = 0;
|
||||
NOTIFICATION_FILTER_ALL = 1;
|
||||
NOTIFICATION_FILTER_FOLLOWS = 2;
|
||||
}
|
||||
|
||||
message FilterableNotificationPreference {
|
||||
NotificationFilter filter = 1;
|
||||
NotificationChannelList list = 2;
|
||||
NotificationChannelPush push = 3;
|
||||
}
|
||||
|
||||
message NotificationPreference {
|
||||
NotificationChannelList list = 1;
|
||||
NotificationChannelPush push = 2;
|
||||
}
|
||||
|
||||
enum ChatNotificationFilter {
|
||||
CHAT_NOTIFICATION_FILTER_UNSPECIFIED = 0;
|
||||
CHAT_NOTIFICATION_FILTER_ALL = 1;
|
||||
CHAT_NOTIFICATION_FILTER_ACCEPTED = 2;
|
||||
}
|
||||
|
||||
message ChatNotificationPreference {
|
||||
ChatNotificationFilter filter = 1;
|
||||
NotificationChannelPush push = 2;
|
||||
}
|
||||
|
||||
message NotificationPreferences {
|
||||
ChatNotificationPreference chat = 1;
|
||||
FilterableNotificationPreference follow = 2;
|
||||
FilterableNotificationPreference like = 3;
|
||||
FilterableNotificationPreference like_via_repost = 4;
|
||||
FilterableNotificationPreference mention = 5;
|
||||
FilterableNotificationPreference quote = 6;
|
||||
FilterableNotificationPreference reply = 7;
|
||||
FilterableNotificationPreference repost = 8;
|
||||
FilterableNotificationPreference repost_via_repost = 9;
|
||||
NotificationPreference starterpack_joined = 10;
|
||||
NotificationPreference subscribed_post = 11;
|
||||
NotificationPreference unverified = 12;
|
||||
NotificationPreference verified = 13;
|
||||
}
|
||||
|
||||
message GetNotificationPreferencesResponse {
|
||||
repeated NotificationPreferences preferences = 1;
|
||||
}
|
||||
|
||||
// - list recent notifications for a user
|
||||
// - notifications should include a uri for the record that caused the notif & a “reason” for the notification (reply, like, quotepost, etc)
|
||||
// - this should include both read & unread notifs
|
||||
@ -1256,6 +1316,7 @@ service Service {
|
||||
rpc GetBlocklistSubscriptions(GetBlocklistSubscriptionsRequest) returns (GetBlocklistSubscriptionsResponse);
|
||||
|
||||
// Notifications
|
||||
rpc GetNotificationPreferences(GetNotificationPreferencesRequest) returns (GetNotificationPreferencesResponse);
|
||||
rpc GetNotifications(GetNotificationsRequest) returns (GetNotificationsResponse);
|
||||
rpc GetNotificationSeen(GetNotificationSeenRequest) returns (GetNotificationSeenResponse);
|
||||
rpc GetUnreadNotificationCount(GetUnreadNotificationCountRequest) returns (GetUnreadNotificationCountResponse);
|
||||
|
@ -0,0 +1,50 @@
|
||||
import assert from 'node:assert'
|
||||
import { Un$Typed } from '@atproto/api'
|
||||
import { UpstreamFailureError } from '@atproto/xrpc-server'
|
||||
import { AppContext } from '../../../../context'
|
||||
import { Server } from '../../../../lexicon'
|
||||
import { Preferences } from '../../../../lexicon/types/app/bsky/notification/defs'
|
||||
import { GetNotificationPreferencesResponse } from '../../../../proto/bsky_pb'
|
||||
import { protobufToLex } from './util'
|
||||
|
||||
export default function (server: Server, ctx: AppContext) {
|
||||
server.app.bsky.notification.getPreferences({
|
||||
auth: ctx.authVerifier.standard,
|
||||
handler: async ({ auth }) => {
|
||||
const actorDid = auth.credentials.iss
|
||||
const preferences = await computePreferences(ctx, actorDid)
|
||||
return {
|
||||
encoding: 'application/json',
|
||||
body: {
|
||||
preferences,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const computePreferences = async (
|
||||
ctx: AppContext,
|
||||
actorDid: string,
|
||||
): Promise<Un$Typed<Preferences>> => {
|
||||
let res: GetNotificationPreferencesResponse
|
||||
try {
|
||||
res = await ctx.dataplane.getNotificationPreferences({
|
||||
dids: [actorDid],
|
||||
})
|
||||
} catch (err) {
|
||||
throw new UpstreamFailureError(
|
||||
'cannot get current notification preferences',
|
||||
'NotificationPreferencesFailed',
|
||||
{ cause: err },
|
||||
)
|
||||
}
|
||||
|
||||
assert(
|
||||
res.preferences.length === 1,
|
||||
`expected exactly one preferences entry, got ${res.preferences.length}`,
|
||||
)
|
||||
|
||||
const currentPreferences = protobufToLex(res.preferences[0])
|
||||
return currentPreferences
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
import assert from 'node:assert'
|
||||
import { Un$Typed } from '@atproto/api'
|
||||
import { UpstreamFailureError } from '@atproto/xrpc-server'
|
||||
import { AppContext } from '../../../../context'
|
||||
import { Server } from '../../../../lexicon'
|
||||
import { Preferences } from '../../../../lexicon/types/app/bsky/notification/defs'
|
||||
import { HandlerInput } from '../../../../lexicon/types/app/bsky/notification/putPreferencesV2'
|
||||
import { GetNotificationPreferencesResponse } from '../../../../proto/bsky_pb'
|
||||
import { protobufToLex } from './util'
|
||||
|
||||
export default function (server: Server, ctx: AppContext) {
|
||||
server.app.bsky.notification.putPreferencesV2({
|
||||
auth: ctx.authVerifier.standard,
|
||||
handler: async ({ auth, input }) => {
|
||||
const actorDid = auth.credentials.iss
|
||||
const preferences = await computePreferences(ctx, actorDid, input)
|
||||
|
||||
// Notification preferences are created automatically on the dataplane on signup, so we just update.
|
||||
await ctx.stashClient.update({
|
||||
actorDid,
|
||||
namespace: 'app.bsky.notification.defs#preferences',
|
||||
key: 'self',
|
||||
payload: preferences,
|
||||
})
|
||||
|
||||
return {
|
||||
encoding: 'application/json',
|
||||
body: {
|
||||
preferences,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const computePreferences = async (
|
||||
ctx: AppContext,
|
||||
actorDid: string,
|
||||
input: HandlerInput,
|
||||
): Promise<Un$Typed<Preferences>> => {
|
||||
let res: GetNotificationPreferencesResponse
|
||||
try {
|
||||
res = await ctx.dataplane.getNotificationPreferences({
|
||||
dids: [actorDid],
|
||||
})
|
||||
} catch (err) {
|
||||
throw new UpstreamFailureError(
|
||||
'cannot get current notification preferences',
|
||||
'NotificationPreferencesFailed',
|
||||
{ cause: err },
|
||||
)
|
||||
}
|
||||
|
||||
assert(
|
||||
res.preferences.length === 1,
|
||||
`expected exactly one preferences entry, got ${res.preferences.length}`,
|
||||
)
|
||||
|
||||
const currentPreferences = protobufToLex(res.preferences[0])
|
||||
const preferences = { ...currentPreferences, ...input.body }
|
||||
return preferences
|
||||
}
|
123
packages/bsky/src/api/app/bsky/notification/util.ts
Normal file
123
packages/bsky/src/api/app/bsky/notification/util.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import { Un$Typed } from '@atproto/api'
|
||||
import {
|
||||
ChatPreference,
|
||||
FilterablePreference,
|
||||
Preference,
|
||||
Preferences,
|
||||
} from '../../../../lexicon/types/app/bsky/notification/defs'
|
||||
import {
|
||||
ChatNotificationFilter,
|
||||
ChatNotificationPreference,
|
||||
FilterableNotificationPreference,
|
||||
NotificationFilter,
|
||||
NotificationPreference,
|
||||
NotificationPreferences,
|
||||
} from '../../../../proto/bsky_pb'
|
||||
|
||||
type DeepPartial<T> = T extends object
|
||||
? {
|
||||
[P in keyof T]?: DeepPartial<T[P]>
|
||||
}
|
||||
: T
|
||||
|
||||
const ensureChatPreference = (
|
||||
p?: DeepPartial<ChatPreference>,
|
||||
): ChatPreference => {
|
||||
const filters = ['all', 'accepted']
|
||||
return {
|
||||
filter:
|
||||
typeof p?.filter === 'string' && filters.includes(p.filter)
|
||||
? p.filter
|
||||
: 'all',
|
||||
push: p?.push ?? true,
|
||||
}
|
||||
}
|
||||
|
||||
const ensureFilterablePreference = (
|
||||
p?: DeepPartial<FilterablePreference>,
|
||||
): FilterablePreference => {
|
||||
const filters = ['all', 'follows']
|
||||
return {
|
||||
filter:
|
||||
typeof p?.filter === 'string' && filters.includes(p.filter)
|
||||
? p.filter
|
||||
: 'all',
|
||||
list: p?.list ?? true,
|
||||
push: p?.push ?? true,
|
||||
}
|
||||
}
|
||||
|
||||
const ensurePreference = (p?: DeepPartial<Preference>): Preference => {
|
||||
return {
|
||||
list: p?.list ?? true,
|
||||
push: p?.push ?? true,
|
||||
}
|
||||
}
|
||||
|
||||
const ensurePreferences = (
|
||||
p: DeepPartial<Preferences>,
|
||||
): Un$Typed<Preferences> => {
|
||||
return {
|
||||
chat: ensureChatPreference(p.chat),
|
||||
follow: ensureFilterablePreference(p.follow),
|
||||
like: ensureFilterablePreference(p.like),
|
||||
likeViaRepost: ensureFilterablePreference(p.likeViaRepost),
|
||||
mention: ensureFilterablePreference(p.mention),
|
||||
quote: ensureFilterablePreference(p.quote),
|
||||
reply: ensureFilterablePreference(p.reply),
|
||||
repost: ensureFilterablePreference(p.repost),
|
||||
repostViaRepost: ensureFilterablePreference(p.repostViaRepost),
|
||||
starterpackJoined: ensurePreference(p.starterpackJoined),
|
||||
subscribedPost: ensurePreference(p.subscribedPost),
|
||||
unverified: ensurePreference(p.unverified),
|
||||
verified: ensurePreference(p.verified),
|
||||
}
|
||||
}
|
||||
|
||||
const protobufChatPreferenceToLex = (
|
||||
p?: DeepPartial<ChatNotificationPreference>,
|
||||
): DeepPartial<ChatPreference> => {
|
||||
return {
|
||||
filter: p?.filter === ChatNotificationFilter.ACCEPTED ? 'accepted' : 'all',
|
||||
push: p?.push?.enabled,
|
||||
}
|
||||
}
|
||||
|
||||
const protobufFilterablePreferenceToLex = (
|
||||
p?: DeepPartial<FilterableNotificationPreference>,
|
||||
): DeepPartial<FilterablePreference> => {
|
||||
return {
|
||||
filter: p?.filter === NotificationFilter.FOLLOWS ? 'follows' : 'all',
|
||||
list: p?.list?.enabled,
|
||||
push: p?.push?.enabled,
|
||||
}
|
||||
}
|
||||
|
||||
const protobufPreferenceToLex = (
|
||||
p?: DeepPartial<NotificationPreference>,
|
||||
): DeepPartial<Preference> => {
|
||||
return {
|
||||
list: p?.list?.enabled,
|
||||
push: p?.push?.enabled,
|
||||
}
|
||||
}
|
||||
|
||||
export const protobufToLex = (
|
||||
res: DeepPartial<NotificationPreferences>,
|
||||
): Un$Typed<Preferences> => {
|
||||
return ensurePreferences({
|
||||
chat: protobufChatPreferenceToLex(res.chat),
|
||||
follow: protobufFilterablePreferenceToLex(res.follow),
|
||||
like: protobufFilterablePreferenceToLex(res.like),
|
||||
likeViaRepost: protobufFilterablePreferenceToLex(res.likeViaRepost),
|
||||
mention: protobufFilterablePreferenceToLex(res.mention),
|
||||
quote: protobufFilterablePreferenceToLex(res.quote),
|
||||
reply: protobufFilterablePreferenceToLex(res.reply),
|
||||
repost: protobufFilterablePreferenceToLex(res.repost),
|
||||
repostViaRepost: protobufFilterablePreferenceToLex(res.repostViaRepost),
|
||||
starterpackJoined: protobufPreferenceToLex(res.starterpackJoined),
|
||||
subscribedPost: protobufPreferenceToLex(res.subscribedPost),
|
||||
unverified: protobufPreferenceToLex(res.unverified),
|
||||
verified: protobufPreferenceToLex(res.verified),
|
||||
})
|
||||
}
|
@ -42,9 +42,11 @@ import unmuteActor from './app/bsky/graph/unmuteActor'
|
||||
import unmuteActorList from './app/bsky/graph/unmuteActorList'
|
||||
import unmuteThread from './app/bsky/graph/unmuteThread'
|
||||
import getLabelerServices from './app/bsky/labeler/getServices'
|
||||
import getPreferences from './app/bsky/notification/getPreferences'
|
||||
import getUnreadCount from './app/bsky/notification/getUnreadCount'
|
||||
import listNotifications from './app/bsky/notification/listNotifications'
|
||||
import putPreferences from './app/bsky/notification/putPreferences'
|
||||
import putPreferencesV2 from './app/bsky/notification/putPreferencesV2'
|
||||
import registerPush from './app/bsky/notification/registerPush'
|
||||
import updateSeen from './app/bsky/notification/updateSeen'
|
||||
import getConfig from './app/bsky/unspecced/getConfig'
|
||||
@ -122,10 +124,12 @@ export default function (server: Server, ctx: AppContext) {
|
||||
searchActors(server, ctx)
|
||||
searchActorsTypeahead(server, ctx)
|
||||
getSuggestions(server, ctx)
|
||||
getPreferences(server, ctx)
|
||||
getUnreadCount(server, ctx)
|
||||
listNotifications(server, ctx)
|
||||
updateSeen(server, ctx)
|
||||
putPreferences(server, ctx)
|
||||
putPreferencesV2(server, ctx)
|
||||
registerPush(server, ctx)
|
||||
getConfig(server, ctx)
|
||||
getPopularFeedGenerators(server, ctx)
|
||||
|
@ -13,6 +13,7 @@ import { DataPlaneClient, HostList } from './data-plane/client'
|
||||
import { FeatureGates } from './feature-gates'
|
||||
import { Hydrator } from './hydration/hydrator'
|
||||
import { httpLogger as log } from './logger'
|
||||
import { StashClient } from './stash'
|
||||
import {
|
||||
ParsedLabelers,
|
||||
defaultLabelerHeader,
|
||||
@ -35,6 +36,7 @@ export class AppContext {
|
||||
signingKey: Keypair
|
||||
idResolver: IdResolver
|
||||
bsyncClient: BsyncClient
|
||||
stashClient: StashClient
|
||||
courierClient: CourierClient | undefined
|
||||
authVerifier: AuthVerifier
|
||||
featureGates: FeatureGates
|
||||
@ -94,6 +96,10 @@ export class AppContext {
|
||||
return this.opts.bsyncClient
|
||||
}
|
||||
|
||||
get stashClient(): StashClient {
|
||||
return this.opts.stashClient
|
||||
}
|
||||
|
||||
get courierClient(): CourierClient | undefined {
|
||||
return this.opts.courierClient
|
||||
}
|
||||
|
@ -4,10 +4,15 @@ import http from 'node:http'
|
||||
import { ConnectRouter } from '@connectrpc/connect'
|
||||
import { expressConnectMiddleware } from '@connectrpc/connect-express'
|
||||
import express from 'express'
|
||||
import { TID } from '@atproto/common'
|
||||
import { AtUri } from '@atproto/syntax'
|
||||
import { ids } from '../../lexicon/lexicons'
|
||||
import { Service } from '../../proto/bsync_connect'
|
||||
import { MuteOperation_Type } from '../../proto/bsync_pb'
|
||||
import {
|
||||
Method,
|
||||
MuteOperation_Type,
|
||||
PutOperationRequest,
|
||||
} from '../../proto/bsync_pb'
|
||||
import { Database } from '../server/db'
|
||||
|
||||
export class MockBsync {
|
||||
@ -138,7 +143,110 @@ const createRoutes = (db: Database) => (router: ConnectRouter) =>
|
||||
throw new Error('not implemented')
|
||||
},
|
||||
|
||||
async putOperation(req) {
|
||||
const { actorDid, namespace, key, method, payload } = req
|
||||
if (
|
||||
method !== Method.CREATE &&
|
||||
method !== Method.UPDATE &&
|
||||
method !== Method.DELETE
|
||||
) {
|
||||
throw new Error(`Unsupported method: ${method}`)
|
||||
}
|
||||
|
||||
const now = new Date().toISOString()
|
||||
if (namespace === 'app.bsky.notification.defs#preferences') {
|
||||
await handleNotificationPreferencesOperation(db, req, now)
|
||||
} else {
|
||||
await handleGenericOperation(db, req, now)
|
||||
}
|
||||
|
||||
return {
|
||||
operation: {
|
||||
id: TID.nextStr(),
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
method,
|
||||
payload,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
async scanOperations() {
|
||||
throw new Error('not implemented')
|
||||
},
|
||||
|
||||
async ping() {
|
||||
return {}
|
||||
},
|
||||
})
|
||||
|
||||
const handleNotificationPreferencesOperation = async (
|
||||
db: Database,
|
||||
req: PutOperationRequest,
|
||||
now: string,
|
||||
) => {
|
||||
const { actorDid, namespace, key, method, payload } = req
|
||||
if (method === Method.CREATE || method === Method.UPDATE) {
|
||||
return db.db
|
||||
.insertInto('private_data')
|
||||
.values({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: Buffer.from(payload).toString('utf8'),
|
||||
indexedAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
.onConflict((oc) =>
|
||||
oc.columns(['actorDid', 'namespace', 'key']).doUpdateSet({
|
||||
payload: Buffer.from(payload).toString('utf8'),
|
||||
updatedAt: now,
|
||||
}),
|
||||
)
|
||||
.execute()
|
||||
}
|
||||
|
||||
return handleGenericOperation(db, req, now)
|
||||
}
|
||||
|
||||
const handleGenericOperation = async (
|
||||
db: Database,
|
||||
req: PutOperationRequest,
|
||||
now: string,
|
||||
) => {
|
||||
const { actorDid, namespace, key, method, payload } = req
|
||||
if (method === Method.CREATE) {
|
||||
return db.db
|
||||
.insertInto('private_data')
|
||||
.values({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: Buffer.from(payload).toString('utf8'),
|
||||
indexedAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
.execute()
|
||||
}
|
||||
|
||||
if (method === Method.UPDATE) {
|
||||
return db.db
|
||||
.updateTable('private_data')
|
||||
.where('actorDid', '=', actorDid)
|
||||
.where('namespace', '=', namespace)
|
||||
.where('key', '=', key)
|
||||
.set({
|
||||
payload: Buffer.from(payload).toString('utf8'),
|
||||
updatedAt: now,
|
||||
})
|
||||
.execute()
|
||||
}
|
||||
|
||||
return db.db
|
||||
.deleteFrom('private_data')
|
||||
.where('actorDid', '=', actorDid)
|
||||
.where('namespace', '=', namespace)
|
||||
.where('key', '=', key)
|
||||
.execute()
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import * as post from './tables/post'
|
||||
import * as postAgg from './tables/post-agg'
|
||||
import * as postEmbed from './tables/post-embed'
|
||||
import * as postgate from './tables/post-gate'
|
||||
import * as privateData from './tables/private-data'
|
||||
import * as profile from './tables/profile'
|
||||
import * as profileAgg from './tables/profile-agg'
|
||||
import * as quote from './tables/quote'
|
||||
@ -77,6 +78,7 @@ export type DatabaseSchemaType = duplicateRecord.PartialDB &
|
||||
starterPack.PartialDB &
|
||||
taggedSuggestion.PartialDB &
|
||||
quote.PartialDB &
|
||||
verification.PartialDB
|
||||
verification.PartialDB &
|
||||
privateData.PartialDB
|
||||
|
||||
export type DatabaseSchema = Kysely<DatabaseSchemaType>
|
||||
|
@ -0,0 +1,22 @@
|
||||
import { Kysely } from 'kysely'
|
||||
|
||||
export async function up(db: Kysely<unknown>): Promise<void> {
|
||||
await db.schema
|
||||
.createTable('private_data')
|
||||
.addColumn('actorDid', 'varchar', (col) => col.notNull())
|
||||
.addColumn('namespace', 'varchar', (col) => col.notNull())
|
||||
.addColumn('key', 'varchar', (col) => col.notNull())
|
||||
.addColumn('payload', 'text', (col) => col.notNull())
|
||||
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
||||
.addColumn('updatedAt', 'varchar', (col) => col.notNull())
|
||||
.addPrimaryKeyConstraint('private_data_pkey', [
|
||||
'actorDid',
|
||||
'namespace',
|
||||
'key',
|
||||
])
|
||||
.execute()
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<unknown>): Promise<void> {
|
||||
await db.schema.dropTable('private_data').execute()
|
||||
}
|
@ -50,3 +50,4 @@ export * as _20250207T174822012Z from './20250207T174822012Z-add-label-exp'
|
||||
export * as _20250404T163421487Z from './20250404T163421487Z-verifications'
|
||||
export * as _20250526T023712742Z from './20250526T023712742Z-like-repost-via'
|
||||
export * as _20250528T221913281Z from './20250528T221913281Z-add-record-tags'
|
||||
export * as _20250602T190357447Z from './20250602T190357447Z-add-private-data'
|
||||
|
@ -0,0 +1,13 @@
|
||||
export interface PrivateData {
|
||||
actorDid: string
|
||||
namespace: string
|
||||
key: string
|
||||
// JSON-encoded
|
||||
payload: string
|
||||
indexedAt: string
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export const tableName = 'private_data'
|
||||
|
||||
export type PartialDB = { [tableName]: PrivateData }
|
@ -14,6 +14,7 @@ import lists from './lists'
|
||||
import moderation from './moderation'
|
||||
import mutes from './mutes'
|
||||
import notifs from './notifs'
|
||||
import privateData from './private-data'
|
||||
import profile from './profile'
|
||||
import quotes from './quotes'
|
||||
import records from './records'
|
||||
@ -40,6 +41,7 @@ export default (db: Database, idResolver: IdResolver) =>
|
||||
...moderation(db),
|
||||
...mutes(db),
|
||||
...notifs(db),
|
||||
...privateData(db),
|
||||
...profile(db),
|
||||
...quotes(db),
|
||||
...records(db),
|
||||
|
90
packages/bsky/src/data-plane/server/routes/private-data.ts
Normal file
90
packages/bsky/src/data-plane/server/routes/private-data.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import { ServiceImpl } from '@connectrpc/connect'
|
||||
import { keyBy } from '@atproto/common'
|
||||
import {
|
||||
ChatPreference,
|
||||
FilterablePreference,
|
||||
Preference,
|
||||
Preferences,
|
||||
} from '../../../lexicon/types/app/bsky/notification/defs'
|
||||
import { Service } from '../../../proto/bsky_connect'
|
||||
import {
|
||||
ChatNotificationFilter,
|
||||
ChatNotificationPreference,
|
||||
FilterableNotificationPreference,
|
||||
NotificationFilter,
|
||||
NotificationPreference,
|
||||
NotificationPreferences,
|
||||
} from '../../../proto/bsky_pb'
|
||||
import { Database } from '../db'
|
||||
|
||||
export default (db: Database): Partial<ServiceImpl<typeof Service>> => ({
|
||||
async getNotificationPreferences(req) {
|
||||
const { dids } = req
|
||||
const res = await db.db
|
||||
.selectFrom('private_data')
|
||||
.selectAll()
|
||||
.where('actorDid', 'in', dids)
|
||||
.where('namespace', '=', 'app.bsky.notification.defs#preferences')
|
||||
.where('key', '=', 'self')
|
||||
.execute()
|
||||
|
||||
const byDid = keyBy(res, 'actorDid')
|
||||
const preferences = dids.map((did) => {
|
||||
const row = byDid.get(did)
|
||||
if (!row) {
|
||||
return {}
|
||||
}
|
||||
const p: Preferences = JSON.parse(row.payload)
|
||||
return lexToProtobuf(p)
|
||||
})
|
||||
|
||||
return { preferences }
|
||||
},
|
||||
})
|
||||
|
||||
export const lexToProtobuf = (p: Preferences): NotificationPreferences => {
|
||||
return new NotificationPreferences({
|
||||
chat: lexChatPreferenceToProtobuf(p.chat),
|
||||
follow: lexFilterablePreferenceToProtobuf(p.follow),
|
||||
like: lexFilterablePreferenceToProtobuf(p.like),
|
||||
likeViaRepost: lexFilterablePreferenceToProtobuf(p.likeViaRepost),
|
||||
mention: lexFilterablePreferenceToProtobuf(p.mention),
|
||||
quote: lexFilterablePreferenceToProtobuf(p.quote),
|
||||
reply: lexFilterablePreferenceToProtobuf(p.reply),
|
||||
repost: lexFilterablePreferenceToProtobuf(p.repost),
|
||||
repostViaRepost: lexFilterablePreferenceToProtobuf(p.repostViaRepost),
|
||||
starterpackJoined: lexPreferenceToProtobuf(p.starterpackJoined),
|
||||
subscribedPost: lexPreferenceToProtobuf(p.subscribedPost),
|
||||
unverified: lexPreferenceToProtobuf(p.unverified),
|
||||
verified: lexPreferenceToProtobuf(p.verified),
|
||||
})
|
||||
}
|
||||
|
||||
const lexChatPreferenceToProtobuf = (
|
||||
p: ChatPreference,
|
||||
): ChatNotificationPreference =>
|
||||
new ChatNotificationPreference({
|
||||
filter:
|
||||
p.filter === 'accepted'
|
||||
? ChatNotificationFilter.ACCEPTED
|
||||
: ChatNotificationFilter.ALL,
|
||||
push: { enabled: p.push ?? true },
|
||||
})
|
||||
|
||||
const lexFilterablePreferenceToProtobuf = (
|
||||
p: FilterablePreference,
|
||||
): FilterableNotificationPreference =>
|
||||
new FilterableNotificationPreference({
|
||||
filter:
|
||||
p.filter === 'follows'
|
||||
? NotificationFilter.FOLLOWS
|
||||
: NotificationFilter.ALL,
|
||||
list: { enabled: p.list ?? true },
|
||||
push: { enabled: p.push ?? true },
|
||||
})
|
||||
|
||||
const lexPreferenceToProtobuf = (p: Preference): NotificationPreference =>
|
||||
new NotificationPreference({
|
||||
list: { enabled: p.list ?? true },
|
||||
push: { enabled: p.push ?? true },
|
||||
})
|
@ -29,6 +29,7 @@ import * as imageServer from './image/server'
|
||||
import { ImageUriBuilder } from './image/uri'
|
||||
import { createServer } from './lexicon'
|
||||
import { loggerMiddleware } from './logger'
|
||||
import { createStashClient } from './stash'
|
||||
import { Views } from './views'
|
||||
import { VideoUriBuilder } from './views/util'
|
||||
|
||||
@ -136,6 +137,8 @@ export class BskyAppView {
|
||||
interceptors: config.bsyncApiKey ? [bsyncAuth(config.bsyncApiKey)] : [],
|
||||
})
|
||||
|
||||
const stashClient = createStashClient(bsyncClient)
|
||||
|
||||
const courierClient = config.courierUrl
|
||||
? createCourierClient({
|
||||
baseUrl: config.courierUrl,
|
||||
@ -178,6 +181,7 @@ export class BskyAppView {
|
||||
signingKey,
|
||||
idResolver,
|
||||
bsyncClient,
|
||||
stashClient,
|
||||
courierClient,
|
||||
authVerifier,
|
||||
featureGates,
|
||||
|
24
packages/bsky/src/lexicon/index.ts
generated
24
packages/bsky/src/lexicon/index.ts
generated
@ -138,9 +138,11 @@ import * as AppBskyGraphUnmuteActor from './types/app/bsky/graph/unmuteActor.js'
|
||||
import * as AppBskyGraphUnmuteActorList from './types/app/bsky/graph/unmuteActorList.js'
|
||||
import * as AppBskyGraphUnmuteThread from './types/app/bsky/graph/unmuteThread.js'
|
||||
import * as AppBskyLabelerGetServices from './types/app/bsky/labeler/getServices.js'
|
||||
import * as AppBskyNotificationGetPreferences from './types/app/bsky/notification/getPreferences.js'
|
||||
import * as AppBskyNotificationGetUnreadCount from './types/app/bsky/notification/getUnreadCount.js'
|
||||
import * as AppBskyNotificationListNotifications from './types/app/bsky/notification/listNotifications.js'
|
||||
import * as AppBskyNotificationPutPreferences from './types/app/bsky/notification/putPreferences.js'
|
||||
import * as AppBskyNotificationPutPreferencesV2 from './types/app/bsky/notification/putPreferencesV2.js'
|
||||
import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/registerPush.js'
|
||||
import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen.js'
|
||||
import * as AppBskyUnspeccedGetConfig from './types/app/bsky/unspecced/getConfig.js'
|
||||
@ -1853,6 +1855,17 @@ export class AppBskyNotificationNS {
|
||||
this._server = server
|
||||
}
|
||||
|
||||
getPreferences<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
AppBskyNotificationGetPreferences.Handler<ExtractAuth<AV>>,
|
||||
AppBskyNotificationGetPreferences.HandlerReqCtx<ExtractAuth<AV>>
|
||||
>,
|
||||
) {
|
||||
const nsid = 'app.bsky.notification.getPreferences' // @ts-ignore
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
getUnreadCount<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
@ -1886,6 +1899,17 @@ export class AppBskyNotificationNS {
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
putPreferencesV2<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
AppBskyNotificationPutPreferencesV2.Handler<ExtractAuth<AV>>,
|
||||
AppBskyNotificationPutPreferencesV2.HandlerReqCtx<ExtractAuth<AV>>
|
||||
>,
|
||||
) {
|
||||
const nsid = 'app.bsky.notification.putPreferencesV2' // @ts-ignore
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
registerPush<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
|
227
packages/bsky/src/lexicon/lexicons.ts
generated
227
packages/bsky/src/lexicon/lexicons.ts
generated
@ -9732,6 +9732,147 @@ export const schemaDict = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
chatPreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'accepted'],
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
filterablePreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'list', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'follows'],
|
||||
},
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preference: {
|
||||
type: 'object',
|
||||
required: ['list', 'push'],
|
||||
properties: {
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preferences: {
|
||||
type: 'object',
|
||||
required: [
|
||||
'chat',
|
||||
'follow',
|
||||
'like',
|
||||
'likeViaRepost',
|
||||
'mention',
|
||||
'quote',
|
||||
'reply',
|
||||
'repost',
|
||||
'repostViaRepost',
|
||||
'starterpackJoined',
|
||||
'subscribedPost',
|
||||
'unverified',
|
||||
'verified',
|
||||
],
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetPreferences: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.getPreferences',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'query',
|
||||
description:
|
||||
'Get notification-related preferences for an account. Requires auth.',
|
||||
parameters: {
|
||||
type: 'params',
|
||||
properties: {},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetUnreadCount: {
|
||||
@ -9924,6 +10065,90 @@ export const schemaDict = {
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationPutPreferencesV2: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.putPreferencesV2',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'procedure',
|
||||
description:
|
||||
'Set notification-related preferences for an account. Requires auth.',
|
||||
input: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationRegisterPush: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.registerPush',
|
||||
@ -12939,10 +13164,12 @@ export const ids = {
|
||||
AppBskyLabelerGetServices: 'app.bsky.labeler.getServices',
|
||||
AppBskyLabelerService: 'app.bsky.labeler.service',
|
||||
AppBskyNotificationDefs: 'app.bsky.notification.defs',
|
||||
AppBskyNotificationGetPreferences: 'app.bsky.notification.getPreferences',
|
||||
AppBskyNotificationGetUnreadCount: 'app.bsky.notification.getUnreadCount',
|
||||
AppBskyNotificationListNotifications:
|
||||
'app.bsky.notification.listNotifications',
|
||||
AppBskyNotificationPutPreferences: 'app.bsky.notification.putPreferences',
|
||||
AppBskyNotificationPutPreferencesV2: 'app.bsky.notification.putPreferencesV2',
|
||||
AppBskyNotificationRegisterPush: 'app.bsky.notification.registerPush',
|
||||
AppBskyNotificationUpdateSeen: 'app.bsky.notification.updateSeen',
|
||||
AppBskyRichtextFacet: 'app.bsky.richtext.facet',
|
||||
|
@ -27,3 +27,79 @@ export function isRecordDeleted<V>(v: V) {
|
||||
export function validateRecordDeleted<V>(v: V) {
|
||||
return validate<RecordDeleted & V>(v, id, hashRecordDeleted)
|
||||
}
|
||||
|
||||
export interface ChatPreference {
|
||||
$type?: 'app.bsky.notification.defs#chatPreference'
|
||||
filter: 'all' | 'accepted' | (string & {})
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashChatPreference = 'chatPreference'
|
||||
|
||||
export function isChatPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export function validateChatPreference<V>(v: V) {
|
||||
return validate<ChatPreference & V>(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export interface FilterablePreference {
|
||||
$type?: 'app.bsky.notification.defs#filterablePreference'
|
||||
filter: 'all' | 'follows' | (string & {})
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashFilterablePreference = 'filterablePreference'
|
||||
|
||||
export function isFilterablePreference<V>(v: V) {
|
||||
return is$typed(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export function validateFilterablePreference<V>(v: V) {
|
||||
return validate<FilterablePreference & V>(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export interface Preference {
|
||||
$type?: 'app.bsky.notification.defs#preference'
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashPreference = 'preference'
|
||||
|
||||
export function isPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export function validatePreference<V>(v: V) {
|
||||
return validate<Preference & V>(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export interface Preferences {
|
||||
$type?: 'app.bsky.notification.defs#preferences'
|
||||
chat: ChatPreference
|
||||
follow: FilterablePreference
|
||||
like: FilterablePreference
|
||||
likeViaRepost: FilterablePreference
|
||||
mention: FilterablePreference
|
||||
quote: FilterablePreference
|
||||
reply: FilterablePreference
|
||||
repost: FilterablePreference
|
||||
repostViaRepost: FilterablePreference
|
||||
starterpackJoined: Preference
|
||||
subscribedPost: Preference
|
||||
unverified: Preference
|
||||
verified: Preference
|
||||
}
|
||||
|
||||
const hashPreferences = 'preferences'
|
||||
|
||||
export function isPreferences<V>(v: V) {
|
||||
return is$typed(v, id, hashPreferences)
|
||||
}
|
||||
|
||||
export function validatePreferences<V>(v: V) {
|
||||
return validate<Preferences & V>(v, id, hashPreferences)
|
||||
}
|
||||
|
52
packages/bsky/src/lexicon/types/app/bsky/notification/getPreferences.ts
generated
Normal file
52
packages/bsky/src/lexicon/types/app/bsky/notification/getPreferences.ts
generated
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import express from 'express'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.getPreferences'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export type InputSchema = undefined
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export type HandlerInput = undefined
|
||||
|
||||
export interface HandlerSuccess {
|
||||
encoding: 'application/json'
|
||||
body: OutputSchema
|
||||
headers?: { [key: string]: string }
|
||||
}
|
||||
|
||||
export interface HandlerError {
|
||||
status: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
|
||||
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
||||
auth: HA
|
||||
params: QueryParams
|
||||
input: HandlerInput
|
||||
req: express.Request
|
||||
res: express.Response
|
||||
resetRouteRateLimits: () => Promise<void>
|
||||
}
|
||||
export type Handler<HA extends HandlerAuth = never> = (
|
||||
ctx: HandlerReqCtx<HA>,
|
||||
) => Promise<HandlerOutput> | HandlerOutput
|
69
packages/bsky/src/lexicon/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
69
packages/bsky/src/lexicon/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import express from 'express'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.putPreferencesV2'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export interface InputSchema {
|
||||
chat?: AppBskyNotificationDefs.ChatPreference
|
||||
follow?: AppBskyNotificationDefs.FilterablePreference
|
||||
like?: AppBskyNotificationDefs.FilterablePreference
|
||||
likeViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
mention?: AppBskyNotificationDefs.FilterablePreference
|
||||
quote?: AppBskyNotificationDefs.FilterablePreference
|
||||
reply?: AppBskyNotificationDefs.FilterablePreference
|
||||
repost?: AppBskyNotificationDefs.FilterablePreference
|
||||
repostViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
starterpackJoined?: AppBskyNotificationDefs.Preference
|
||||
subscribedPost?: AppBskyNotificationDefs.Preference
|
||||
unverified?: AppBskyNotificationDefs.Preference
|
||||
verified?: AppBskyNotificationDefs.Preference
|
||||
}
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export interface HandlerInput {
|
||||
encoding: 'application/json'
|
||||
body: InputSchema
|
||||
}
|
||||
|
||||
export interface HandlerSuccess {
|
||||
encoding: 'application/json'
|
||||
body: OutputSchema
|
||||
headers?: { [key: string]: string }
|
||||
}
|
||||
|
||||
export interface HandlerError {
|
||||
status: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
|
||||
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
||||
auth: HA
|
||||
params: QueryParams
|
||||
input: HandlerInput
|
||||
req: express.Request
|
||||
res: express.Response
|
||||
resetRouteRateLimits: () => Promise<void>
|
||||
}
|
||||
export type Handler<HA extends HandlerAuth = never> = (
|
||||
ctx: HandlerReqCtx<HA>,
|
||||
) => Promise<HandlerOutput> | HandlerOutput
|
11
packages/bsky/src/proto/bsky_connect.ts
generated
11
packages/bsky/src/proto/bsky_connect.ts
generated
@ -126,6 +126,8 @@ import {
|
||||
GetMutesResponse,
|
||||
GetNewUserCountForRangeRequest,
|
||||
GetNewUserCountForRangeResponse,
|
||||
GetNotificationPreferencesRequest,
|
||||
GetNotificationPreferencesResponse,
|
||||
GetNotificationSeenRequest,
|
||||
GetNotificationSeenResponse,
|
||||
GetNotificationsRequest,
|
||||
@ -732,6 +734,15 @@ export const Service = {
|
||||
/**
|
||||
* Notifications
|
||||
*
|
||||
* @generated from rpc bsky.Service.GetNotificationPreferences
|
||||
*/
|
||||
getNotificationPreferences: {
|
||||
name: 'GetNotificationPreferences',
|
||||
I: GetNotificationPreferencesRequest,
|
||||
O: GetNotificationPreferencesResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* @generated from rpc bsky.Service.GetNotifications
|
||||
*/
|
||||
getNotifications: {
|
||||
|
669
packages/bsky/src/proto/bsky_pb.ts
generated
669
packages/bsky/src/proto/bsky_pb.ts
generated
@ -13,6 +13,58 @@ import type {
|
||||
} from '@bufbuild/protobuf'
|
||||
import { Message, proto3, protoInt64, Timestamp } from '@bufbuild/protobuf'
|
||||
|
||||
/**
|
||||
* @generated from enum bsky.NotificationFilter
|
||||
*/
|
||||
export enum NotificationFilter {
|
||||
/**
|
||||
* @generated from enum value: NOTIFICATION_FILTER_UNSPECIFIED = 0;
|
||||
*/
|
||||
UNSPECIFIED = 0,
|
||||
|
||||
/**
|
||||
* @generated from enum value: NOTIFICATION_FILTER_ALL = 1;
|
||||
*/
|
||||
ALL = 1,
|
||||
|
||||
/**
|
||||
* @generated from enum value: NOTIFICATION_FILTER_FOLLOWS = 2;
|
||||
*/
|
||||
FOLLOWS = 2,
|
||||
}
|
||||
// Retrieve enum metadata with: proto3.getEnumType(NotificationFilter)
|
||||
proto3.util.setEnumType(NotificationFilter, 'bsky.NotificationFilter', [
|
||||
{ no: 0, name: 'NOTIFICATION_FILTER_UNSPECIFIED' },
|
||||
{ no: 1, name: 'NOTIFICATION_FILTER_ALL' },
|
||||
{ no: 2, name: 'NOTIFICATION_FILTER_FOLLOWS' },
|
||||
])
|
||||
|
||||
/**
|
||||
* @generated from enum bsky.ChatNotificationFilter
|
||||
*/
|
||||
export enum ChatNotificationFilter {
|
||||
/**
|
||||
* @generated from enum value: CHAT_NOTIFICATION_FILTER_UNSPECIFIED = 0;
|
||||
*/
|
||||
UNSPECIFIED = 0,
|
||||
|
||||
/**
|
||||
* @generated from enum value: CHAT_NOTIFICATION_FILTER_ALL = 1;
|
||||
*/
|
||||
ALL = 1,
|
||||
|
||||
/**
|
||||
* @generated from enum value: CHAT_NOTIFICATION_FILTER_ACCEPTED = 2;
|
||||
*/
|
||||
ACCEPTED = 2,
|
||||
}
|
||||
// Retrieve enum metadata with: proto3.getEnumType(ChatNotificationFilter)
|
||||
proto3.util.setEnumType(ChatNotificationFilter, 'bsky.ChatNotificationFilter', [
|
||||
{ no: 0, name: 'CHAT_NOTIFICATION_FILTER_UNSPECIFIED' },
|
||||
{ no: 1, name: 'CHAT_NOTIFICATION_FILTER_ALL' },
|
||||
{ no: 2, name: 'CHAT_NOTIFICATION_FILTER_ACCEPTED' },
|
||||
])
|
||||
|
||||
/**
|
||||
* @generated from enum bsky.FeedType
|
||||
*/
|
||||
@ -8180,6 +8232,623 @@ export class GetBlocklistSubscriptionsResponse extends Message<GetBlocklistSubsc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.GetNotificationPreferencesRequest
|
||||
*/
|
||||
export class GetNotificationPreferencesRequest extends Message<GetNotificationPreferencesRequest> {
|
||||
/**
|
||||
* @generated from field: repeated string dids = 1;
|
||||
*/
|
||||
dids: string[] = []
|
||||
|
||||
constructor(data?: PartialMessage<GetNotificationPreferencesRequest>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.GetNotificationPreferencesRequest'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{
|
||||
no: 1,
|
||||
name: 'dids',
|
||||
kind: 'scalar',
|
||||
T: 9 /* ScalarType.STRING */,
|
||||
repeated: true,
|
||||
},
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): GetNotificationPreferencesRequest {
|
||||
return new GetNotificationPreferencesRequest().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): GetNotificationPreferencesRequest {
|
||||
return new GetNotificationPreferencesRequest().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): GetNotificationPreferencesRequest {
|
||||
return new GetNotificationPreferencesRequest().fromJsonString(
|
||||
jsonString,
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| GetNotificationPreferencesRequest
|
||||
| PlainMessage<GetNotificationPreferencesRequest>
|
||||
| undefined,
|
||||
b:
|
||||
| GetNotificationPreferencesRequest
|
||||
| PlainMessage<GetNotificationPreferencesRequest>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(GetNotificationPreferencesRequest, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.NotificationChannelList
|
||||
*/
|
||||
export class NotificationChannelList extends Message<NotificationChannelList> {
|
||||
/**
|
||||
* @generated from field: bool enabled = 1;
|
||||
*/
|
||||
enabled = false
|
||||
|
||||
constructor(data?: PartialMessage<NotificationChannelList>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.NotificationChannelList'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: 'enabled', kind: 'scalar', T: 8 /* ScalarType.BOOL */ },
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): NotificationChannelList {
|
||||
return new NotificationChannelList().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationChannelList {
|
||||
return new NotificationChannelList().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationChannelList {
|
||||
return new NotificationChannelList().fromJsonString(jsonString, options)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| NotificationChannelList
|
||||
| PlainMessage<NotificationChannelList>
|
||||
| undefined,
|
||||
b:
|
||||
| NotificationChannelList
|
||||
| PlainMessage<NotificationChannelList>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(NotificationChannelList, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.NotificationChannelPush
|
||||
*/
|
||||
export class NotificationChannelPush extends Message<NotificationChannelPush> {
|
||||
/**
|
||||
* @generated from field: bool enabled = 1;
|
||||
*/
|
||||
enabled = false
|
||||
|
||||
constructor(data?: PartialMessage<NotificationChannelPush>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.NotificationChannelPush'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: 'enabled', kind: 'scalar', T: 8 /* ScalarType.BOOL */ },
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): NotificationChannelPush {
|
||||
return new NotificationChannelPush().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationChannelPush {
|
||||
return new NotificationChannelPush().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationChannelPush {
|
||||
return new NotificationChannelPush().fromJsonString(jsonString, options)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| NotificationChannelPush
|
||||
| PlainMessage<NotificationChannelPush>
|
||||
| undefined,
|
||||
b:
|
||||
| NotificationChannelPush
|
||||
| PlainMessage<NotificationChannelPush>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(NotificationChannelPush, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.FilterableNotificationPreference
|
||||
*/
|
||||
export class FilterableNotificationPreference extends Message<FilterableNotificationPreference> {
|
||||
/**
|
||||
* @generated from field: bsky.NotificationFilter filter = 1;
|
||||
*/
|
||||
filter = NotificationFilter.UNSPECIFIED
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationChannelList list = 2;
|
||||
*/
|
||||
list?: NotificationChannelList
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationChannelPush push = 3;
|
||||
*/
|
||||
push?: NotificationChannelPush
|
||||
|
||||
constructor(data?: PartialMessage<FilterableNotificationPreference>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.FilterableNotificationPreference'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{
|
||||
no: 1,
|
||||
name: 'filter',
|
||||
kind: 'enum',
|
||||
T: proto3.getEnumType(NotificationFilter),
|
||||
},
|
||||
{ no: 2, name: 'list', kind: 'message', T: NotificationChannelList },
|
||||
{ no: 3, name: 'push', kind: 'message', T: NotificationChannelPush },
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): FilterableNotificationPreference {
|
||||
return new FilterableNotificationPreference().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): FilterableNotificationPreference {
|
||||
return new FilterableNotificationPreference().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): FilterableNotificationPreference {
|
||||
return new FilterableNotificationPreference().fromJsonString(
|
||||
jsonString,
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| FilterableNotificationPreference
|
||||
| PlainMessage<FilterableNotificationPreference>
|
||||
| undefined,
|
||||
b:
|
||||
| FilterableNotificationPreference
|
||||
| PlainMessage<FilterableNotificationPreference>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(FilterableNotificationPreference, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.NotificationPreference
|
||||
*/
|
||||
export class NotificationPreference extends Message<NotificationPreference> {
|
||||
/**
|
||||
* @generated from field: bsky.NotificationChannelList list = 1;
|
||||
*/
|
||||
list?: NotificationChannelList
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationChannelPush push = 2;
|
||||
*/
|
||||
push?: NotificationChannelPush
|
||||
|
||||
constructor(data?: PartialMessage<NotificationPreference>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.NotificationPreference'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: 'list', kind: 'message', T: NotificationChannelList },
|
||||
{ no: 2, name: 'push', kind: 'message', T: NotificationChannelPush },
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): NotificationPreference {
|
||||
return new NotificationPreference().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationPreference {
|
||||
return new NotificationPreference().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationPreference {
|
||||
return new NotificationPreference().fromJsonString(jsonString, options)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| NotificationPreference
|
||||
| PlainMessage<NotificationPreference>
|
||||
| undefined,
|
||||
b:
|
||||
| NotificationPreference
|
||||
| PlainMessage<NotificationPreference>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(NotificationPreference, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.ChatNotificationPreference
|
||||
*/
|
||||
export class ChatNotificationPreference extends Message<ChatNotificationPreference> {
|
||||
/**
|
||||
* @generated from field: bsky.ChatNotificationFilter filter = 1;
|
||||
*/
|
||||
filter = ChatNotificationFilter.UNSPECIFIED
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationChannelPush push = 2;
|
||||
*/
|
||||
push?: NotificationChannelPush
|
||||
|
||||
constructor(data?: PartialMessage<ChatNotificationPreference>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.ChatNotificationPreference'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{
|
||||
no: 1,
|
||||
name: 'filter',
|
||||
kind: 'enum',
|
||||
T: proto3.getEnumType(ChatNotificationFilter),
|
||||
},
|
||||
{ no: 2, name: 'push', kind: 'message', T: NotificationChannelPush },
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): ChatNotificationPreference {
|
||||
return new ChatNotificationPreference().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): ChatNotificationPreference {
|
||||
return new ChatNotificationPreference().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): ChatNotificationPreference {
|
||||
return new ChatNotificationPreference().fromJsonString(jsonString, options)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| ChatNotificationPreference
|
||||
| PlainMessage<ChatNotificationPreference>
|
||||
| undefined,
|
||||
b:
|
||||
| ChatNotificationPreference
|
||||
| PlainMessage<ChatNotificationPreference>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(ChatNotificationPreference, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.NotificationPreferences
|
||||
*/
|
||||
export class NotificationPreferences extends Message<NotificationPreferences> {
|
||||
/**
|
||||
* @generated from field: bsky.ChatNotificationPreference chat = 1;
|
||||
*/
|
||||
chat?: ChatNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference follow = 2;
|
||||
*/
|
||||
follow?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference like = 3;
|
||||
*/
|
||||
like?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference like_via_repost = 4;
|
||||
*/
|
||||
likeViaRepost?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference mention = 5;
|
||||
*/
|
||||
mention?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference quote = 6;
|
||||
*/
|
||||
quote?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference reply = 7;
|
||||
*/
|
||||
reply?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference repost = 8;
|
||||
*/
|
||||
repost?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.FilterableNotificationPreference repost_via_repost = 9;
|
||||
*/
|
||||
repostViaRepost?: FilterableNotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationPreference starterpack_joined = 10;
|
||||
*/
|
||||
starterpackJoined?: NotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationPreference subscribed_post = 11;
|
||||
*/
|
||||
subscribedPost?: NotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationPreference unverified = 12;
|
||||
*/
|
||||
unverified?: NotificationPreference
|
||||
|
||||
/**
|
||||
* @generated from field: bsky.NotificationPreference verified = 13;
|
||||
*/
|
||||
verified?: NotificationPreference
|
||||
|
||||
constructor(data?: PartialMessage<NotificationPreferences>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.NotificationPreferences'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: 'chat', kind: 'message', T: ChatNotificationPreference },
|
||||
{
|
||||
no: 2,
|
||||
name: 'follow',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 3,
|
||||
name: 'like',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 4,
|
||||
name: 'like_via_repost',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 5,
|
||||
name: 'mention',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 6,
|
||||
name: 'quote',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 7,
|
||||
name: 'reply',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 8,
|
||||
name: 'repost',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 9,
|
||||
name: 'repost_via_repost',
|
||||
kind: 'message',
|
||||
T: FilterableNotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 10,
|
||||
name: 'starterpack_joined',
|
||||
kind: 'message',
|
||||
T: NotificationPreference,
|
||||
},
|
||||
{
|
||||
no: 11,
|
||||
name: 'subscribed_post',
|
||||
kind: 'message',
|
||||
T: NotificationPreference,
|
||||
},
|
||||
{ no: 12, name: 'unverified', kind: 'message', T: NotificationPreference },
|
||||
{ no: 13, name: 'verified', kind: 'message', T: NotificationPreference },
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): NotificationPreferences {
|
||||
return new NotificationPreferences().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationPreferences {
|
||||
return new NotificationPreferences().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): NotificationPreferences {
|
||||
return new NotificationPreferences().fromJsonString(jsonString, options)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| NotificationPreferences
|
||||
| PlainMessage<NotificationPreferences>
|
||||
| undefined,
|
||||
b:
|
||||
| NotificationPreferences
|
||||
| PlainMessage<NotificationPreferences>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(NotificationPreferences, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message bsky.GetNotificationPreferencesResponse
|
||||
*/
|
||||
export class GetNotificationPreferencesResponse extends Message<GetNotificationPreferencesResponse> {
|
||||
/**
|
||||
* @generated from field: repeated bsky.NotificationPreferences preferences = 1;
|
||||
*/
|
||||
preferences: NotificationPreferences[] = []
|
||||
|
||||
constructor(data?: PartialMessage<GetNotificationPreferencesResponse>) {
|
||||
super()
|
||||
proto3.util.initPartial(data, this)
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsky.GetNotificationPreferencesResponse'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{
|
||||
no: 1,
|
||||
name: 'preferences',
|
||||
kind: 'message',
|
||||
T: NotificationPreferences,
|
||||
repeated: true,
|
||||
},
|
||||
])
|
||||
|
||||
static fromBinary(
|
||||
bytes: Uint8Array,
|
||||
options?: Partial<BinaryReadOptions>,
|
||||
): GetNotificationPreferencesResponse {
|
||||
return new GetNotificationPreferencesResponse().fromBinary(bytes, options)
|
||||
}
|
||||
|
||||
static fromJson(
|
||||
jsonValue: JsonValue,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): GetNotificationPreferencesResponse {
|
||||
return new GetNotificationPreferencesResponse().fromJson(jsonValue, options)
|
||||
}
|
||||
|
||||
static fromJsonString(
|
||||
jsonString: string,
|
||||
options?: Partial<JsonReadOptions>,
|
||||
): GetNotificationPreferencesResponse {
|
||||
return new GetNotificationPreferencesResponse().fromJsonString(
|
||||
jsonString,
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
||||
static equals(
|
||||
a:
|
||||
| GetNotificationPreferencesResponse
|
||||
| PlainMessage<GetNotificationPreferencesResponse>
|
||||
| undefined,
|
||||
b:
|
||||
| GetNotificationPreferencesResponse
|
||||
| PlainMessage<GetNotificationPreferencesResponse>
|
||||
| undefined,
|
||||
): boolean {
|
||||
return proto3.util.equals(GetNotificationPreferencesResponse, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* - list recent notifications for a user
|
||||
* - notifications should include a uri for the record that caused the notif & a “reason” for the notification (reply, like, quotepost, etc)
|
||||
|
34
packages/bsky/src/proto/bsync_pb.ts
generated
34
packages/bsky/src/proto/bsync_pb.ts
generated
@ -736,14 +736,14 @@ export class Operation extends Message<Operation> {
|
||||
actorDid = ''
|
||||
|
||||
/**
|
||||
* @generated from field: string collection = 3;
|
||||
* @generated from field: string namespace = 3;
|
||||
*/
|
||||
collection = ''
|
||||
namespace = ''
|
||||
|
||||
/**
|
||||
* @generated from field: string rkey = 4;
|
||||
* @generated from field: string key = 4;
|
||||
*/
|
||||
rkey = ''
|
||||
key = ''
|
||||
|
||||
/**
|
||||
* @generated from field: bsync.Method method = 5;
|
||||
@ -765,8 +765,8 @@ export class Operation extends Message<Operation> {
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: 'id', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: 'actor_did', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 3, name: 'collection', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 4, name: 'rkey', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 3, name: 'namespace', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 4, name: 'key', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 5, name: 'method', kind: 'enum', T: proto3.getEnumType(Method) },
|
||||
{ no: 6, name: 'payload', kind: 'scalar', T: 12 /* ScalarType.BYTES */ },
|
||||
])
|
||||
@ -805,19 +805,19 @@ export class Operation extends Message<Operation> {
|
||||
*/
|
||||
export class PutOperationRequest extends Message<PutOperationRequest> {
|
||||
/**
|
||||
* @generated from field: string collection = 1;
|
||||
*/
|
||||
collection = ''
|
||||
|
||||
/**
|
||||
* @generated from field: string actor_did = 2;
|
||||
* @generated from field: string actor_did = 1;
|
||||
*/
|
||||
actorDid = ''
|
||||
|
||||
/**
|
||||
* @generated from field: string rkey = 3;
|
||||
* @generated from field: string namespace = 2;
|
||||
*/
|
||||
rkey = ''
|
||||
namespace = ''
|
||||
|
||||
/**
|
||||
* @generated from field: string key = 3;
|
||||
*/
|
||||
key = ''
|
||||
|
||||
/**
|
||||
* @generated from field: bsync.Method method = 4;
|
||||
@ -837,9 +837,9 @@ export class PutOperationRequest extends Message<PutOperationRequest> {
|
||||
static readonly runtime: typeof proto3 = proto3
|
||||
static readonly typeName = 'bsync.PutOperationRequest'
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: 'collection', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: 'actor_did', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 3, name: 'rkey', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 1, name: 'actor_did', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: 'namespace', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 3, name: 'key', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 4, name: 'method', kind: 'enum', T: proto3.getEnumType(Method) },
|
||||
{ no: 5, name: 'payload', kind: 'scalar', T: 12 /* ScalarType.BYTES */ },
|
||||
])
|
||||
|
75
packages/bsky/src/stash.ts
Normal file
75
packages/bsky/src/stash.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { LexValue, stringifyLex } from '@atproto/lexicon'
|
||||
import { BsyncClient } from './bsync'
|
||||
import { lexicons } from './lexicon/lexicons'
|
||||
import { Method } from './proto/bsync_pb'
|
||||
|
||||
export const createStashClient = (bsyncClient: BsyncClient): StashClient => {
|
||||
return new StashClient(bsyncClient)
|
||||
}
|
||||
|
||||
// An abstraction over the BsyncClient, that uses the bsync `PutOperation` RPC
|
||||
// to store private data, which can be indexed by the dataplane and queried by the appview.
|
||||
export class StashClient {
|
||||
constructor(private readonly bsyncClient: BsyncClient) {}
|
||||
|
||||
create(input: CreateInput) {
|
||||
this.validateLexicon(input.namespace, input.payload)
|
||||
return this.putOperation(Method.CREATE, input)
|
||||
}
|
||||
|
||||
update(input: UpdateInput) {
|
||||
this.validateLexicon(input.namespace, input.payload)
|
||||
return this.putOperation(Method.UPDATE, input)
|
||||
}
|
||||
|
||||
delete(input: DeleteInput) {
|
||||
return this.putOperation(Method.DELETE, { ...input, payload: undefined })
|
||||
}
|
||||
|
||||
private validateLexicon(namespace: string, payload: LexValue) {
|
||||
const result = lexicons.validate(namespace, payload)
|
||||
if (!result.success) {
|
||||
throw result.error
|
||||
}
|
||||
}
|
||||
|
||||
private async putOperation(method: Method, input: PutOperationInput) {
|
||||
const { actorDid, namespace, key, payload } = input
|
||||
await this.bsyncClient.putOperation({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
method,
|
||||
payload: payload
|
||||
? Buffer.from(
|
||||
stringifyLex({
|
||||
$type: namespace,
|
||||
...payload,
|
||||
}),
|
||||
)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type PutOperationInput = {
|
||||
actorDid: string
|
||||
namespace: string
|
||||
key: string
|
||||
payload: LexValue | undefined
|
||||
}
|
||||
|
||||
type CreateInput = {
|
||||
actorDid: string
|
||||
namespace: string
|
||||
key: string
|
||||
payload: LexValue
|
||||
}
|
||||
|
||||
type UpdateInput = CreateInput
|
||||
|
||||
type DeleteInput = {
|
||||
actorDid: string
|
||||
namespace: string
|
||||
key: string
|
||||
}
|
156
packages/bsky/tests/stash.test.ts
Normal file
156
packages/bsky/tests/stash.test.ts
Normal file
@ -0,0 +1,156 @@
|
||||
import { TestNetwork } from '@atproto/dev-env'
|
||||
import { ProfileAssociatedChat } from '../dist/lexicon/types/app/bsky/actor/defs'
|
||||
import { StashClient } from '../dist/stash'
|
||||
|
||||
type Database = TestNetwork['bsky']['db']
|
||||
|
||||
describe('private data', () => {
|
||||
let network: TestNetwork
|
||||
let stashClient: StashClient
|
||||
let db: Database
|
||||
|
||||
const actorDid = 'did:plc:example'
|
||||
// This lexicon has nothing special other than being simple, convenient to use in a test.
|
||||
const namespace = 'app.bsky.actor.defs#profileAssociatedChat'
|
||||
const key = 'self'
|
||||
|
||||
const validPayload0: ProfileAssociatedChat = { allowIncoming: 'all' }
|
||||
const validPayload1: ProfileAssociatedChat = { allowIncoming: 'following' }
|
||||
const invalidPayload: ProfileAssociatedChat = {
|
||||
invalid: 'all',
|
||||
} as unknown as ProfileAssociatedChat
|
||||
|
||||
beforeAll(async () => {
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_private_data',
|
||||
})
|
||||
db = network.bsky.db
|
||||
stashClient = network.bsky.ctx.stashClient
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await clearPrivateData(db)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await network.close()
|
||||
})
|
||||
|
||||
describe('create', () => {
|
||||
it('creates entry', async () => {
|
||||
await stashClient.create({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: validPayload0,
|
||||
})
|
||||
await network.processAll()
|
||||
|
||||
const dbResult = await db.db
|
||||
.selectFrom('private_data')
|
||||
.selectAll()
|
||||
.where('actorDid', '=', actorDid)
|
||||
.where('namespace', '=', namespace)
|
||||
.where('key', '=', key)
|
||||
.executeTakeFirstOrThrow()
|
||||
expect(dbResult).toStrictEqual({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: JSON.stringify({ $type: namespace, ...validPayload0 }),
|
||||
indexedAt: expect.any(String),
|
||||
updatedAt: expect.any(String),
|
||||
})
|
||||
})
|
||||
|
||||
it('validates lexicon', async () => {
|
||||
expect(() =>
|
||||
stashClient.create({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: invalidPayload,
|
||||
}),
|
||||
).toThrow('Object must have the property "allowIncoming"')
|
||||
})
|
||||
})
|
||||
|
||||
describe('update', () => {
|
||||
it('updates entry', async () => {
|
||||
await stashClient.create({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: validPayload0,
|
||||
})
|
||||
await network.processAll()
|
||||
|
||||
await stashClient.update({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: validPayload1,
|
||||
})
|
||||
await network.processAll()
|
||||
|
||||
const dbResult = await db.db
|
||||
.selectFrom('private_data')
|
||||
.selectAll()
|
||||
.where('actorDid', '=', actorDid)
|
||||
.where('namespace', '=', namespace)
|
||||
.where('key', '=', key)
|
||||
.executeTakeFirstOrThrow()
|
||||
expect(dbResult).toStrictEqual({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: JSON.stringify({ $type: namespace, ...validPayload1 }),
|
||||
indexedAt: expect.any(String),
|
||||
updatedAt: expect.any(String),
|
||||
})
|
||||
})
|
||||
|
||||
it('validates lexicon', async () => {
|
||||
expect(() =>
|
||||
stashClient.update({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: invalidPayload,
|
||||
}),
|
||||
).toThrow('Object must have the property "allowIncoming"')
|
||||
})
|
||||
})
|
||||
|
||||
describe('delete', () => {
|
||||
it('deletes entry', async () => {
|
||||
await stashClient.create({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
payload: validPayload0,
|
||||
})
|
||||
await network.processAll()
|
||||
|
||||
await stashClient.delete({
|
||||
actorDid,
|
||||
namespace,
|
||||
key,
|
||||
})
|
||||
await network.processAll()
|
||||
|
||||
const dbResult = await db.db
|
||||
.selectFrom('private_data')
|
||||
.selectAll()
|
||||
.where('actorDid', '=', actorDid)
|
||||
.where('namespace', '=', namespace)
|
||||
.where('key', '=', key)
|
||||
.executeTakeFirst()
|
||||
expect(dbResult).toBe(undefined)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const clearPrivateData = async (db: Database) => {
|
||||
await db.db.deleteFrom('private_data').execute()
|
||||
}
|
@ -2,11 +2,22 @@ import { AtpAgent } from '@atproto/api'
|
||||
import { SeedClient, TestNetwork, basicSeed } from '@atproto/dev-env'
|
||||
import { delayCursor } from '../../src/api/app/bsky/notification/listNotifications'
|
||||
import { ids } from '../../src/lexicon/lexicons'
|
||||
import {
|
||||
ChatPreference,
|
||||
FilterablePreference,
|
||||
Preference,
|
||||
Preferences,
|
||||
} from '../../src/lexicon/types/app/bsky/notification/defs'
|
||||
import { Notification } from '../../src/lexicon/types/app/bsky/notification/listNotifications'
|
||||
import { InputSchema } from '../../src/lexicon/types/app/bsky/notification/putPreferencesV2'
|
||||
import { forSnapshot, paginateAll } from '../_util'
|
||||
|
||||
type Database = TestNetwork['bsky']['db']
|
||||
|
||||
describe('notification views', () => {
|
||||
let network: TestNetwork
|
||||
let db: Database
|
||||
|
||||
let agent: AtpAgent
|
||||
let sc: SeedClient
|
||||
|
||||
@ -19,6 +30,7 @@ describe('notification views', () => {
|
||||
network = await TestNetwork.create({
|
||||
dbPostgresSchema: 'bsky_views_notifications',
|
||||
})
|
||||
db = network.bsky.db
|
||||
agent = network.bsky.getClient()
|
||||
sc = network.getSeedClient()
|
||||
await basicSeed(sc)
|
||||
@ -905,4 +917,213 @@ describe('notification views', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('preferences v2', () => {
|
||||
beforeEach(async () => {
|
||||
await clearPrivateData(db)
|
||||
})
|
||||
|
||||
// Defaults
|
||||
const fp: FilterablePreference = {
|
||||
filter: 'all',
|
||||
list: true,
|
||||
push: true,
|
||||
}
|
||||
const p: Preference = {
|
||||
list: true,
|
||||
push: true,
|
||||
}
|
||||
const cp: ChatPreference = {
|
||||
filter: 'all',
|
||||
push: true,
|
||||
}
|
||||
|
||||
it('gets preferences filling up with the defaults', async () => {
|
||||
const actorDid = sc.dids.carol
|
||||
|
||||
const getAndAssert = async (
|
||||
expectedApi: Preferences,
|
||||
expectedDb: Preferences | undefined,
|
||||
) => {
|
||||
const { data } = await agent.app.bsky.notification.getPreferences(
|
||||
{},
|
||||
{
|
||||
headers: await network.serviceHeaders(
|
||||
actorDid,
|
||||
ids.AppBskyNotificationGetPreferences,
|
||||
),
|
||||
},
|
||||
)
|
||||
expect(data.preferences).toStrictEqual(expectedApi)
|
||||
|
||||
const dbResult = await db.db
|
||||
.selectFrom('private_data')
|
||||
.selectAll()
|
||||
.where('actorDid', '=', actorDid)
|
||||
.where('namespace', '=', 'app.bsky.notification.defs#preferences')
|
||||
.where('key', '=', 'self')
|
||||
.executeTakeFirst()
|
||||
if (dbResult === undefined) {
|
||||
expect(dbResult).toBe(expectedDb)
|
||||
} else {
|
||||
expect(dbResult).toStrictEqual({
|
||||
actorDid: actorDid,
|
||||
namespace: 'app.bsky.notification.defs#preferences',
|
||||
key: 'self',
|
||||
indexedAt: expect.any(String),
|
||||
payload: expect.anything(), // Better to compare payload parsed.
|
||||
updatedAt: expect.any(String),
|
||||
})
|
||||
expect(JSON.parse(dbResult.payload)).toStrictEqual({
|
||||
$type: 'app.bsky.notification.defs#preferences',
|
||||
...expectedDb,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const expectedApi0: Preferences = {
|
||||
chat: cp,
|
||||
follow: fp,
|
||||
like: fp,
|
||||
likeViaRepost: fp,
|
||||
mention: fp,
|
||||
quote: fp,
|
||||
reply: fp,
|
||||
repost: fp,
|
||||
repostViaRepost: fp,
|
||||
starterpackJoined: p,
|
||||
subscribedPost: p,
|
||||
unverified: p,
|
||||
verified: p,
|
||||
}
|
||||
// The user has no preferences set yet, so nothing stored.
|
||||
const expectedDb0 = undefined
|
||||
await getAndAssert(expectedApi0, expectedDb0)
|
||||
|
||||
await agent.app.bsky.notification.putPreferencesV2(
|
||||
{ verified: { list: false, push: false } },
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: await network.serviceHeaders(
|
||||
actorDid,
|
||||
ids.AppBskyNotificationPutPreferencesV2,
|
||||
),
|
||||
},
|
||||
)
|
||||
await network.processAll()
|
||||
|
||||
const expectedApi1: Preferences = {
|
||||
chat: cp,
|
||||
follow: fp,
|
||||
like: fp,
|
||||
likeViaRepost: fp,
|
||||
mention: fp,
|
||||
quote: fp,
|
||||
reply: fp,
|
||||
repost: fp,
|
||||
repostViaRepost: fp,
|
||||
starterpackJoined: p,
|
||||
subscribedPost: p,
|
||||
unverified: p,
|
||||
verified: { list: false, push: false },
|
||||
}
|
||||
// Stored all the defaults.
|
||||
const expectedDb1 = expectedApi1
|
||||
await getAndAssert(expectedApi1, expectedDb1)
|
||||
})
|
||||
|
||||
it('stores the preferences setting the defaults', async () => {
|
||||
const actorDid = sc.dids.carol
|
||||
|
||||
const putAndAssert = async (
|
||||
input: InputSchema,
|
||||
expected: Preferences,
|
||||
) => {
|
||||
const { data } = await agent.app.bsky.notification.putPreferencesV2(
|
||||
input,
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: await network.serviceHeaders(
|
||||
actorDid,
|
||||
ids.AppBskyNotificationPutPreferencesV2,
|
||||
),
|
||||
},
|
||||
)
|
||||
await network.processAll()
|
||||
expect(data.preferences).toStrictEqual(expected)
|
||||
|
||||
const dbResult = await db.db
|
||||
.selectFrom('private_data')
|
||||
.selectAll()
|
||||
.where('actorDid', '=', actorDid)
|
||||
.where('namespace', '=', 'app.bsky.notification.defs#preferences')
|
||||
.where('key', '=', 'self')
|
||||
.executeTakeFirstOrThrow()
|
||||
expect(dbResult).toStrictEqual({
|
||||
actorDid: actorDid,
|
||||
namespace: 'app.bsky.notification.defs#preferences',
|
||||
key: 'self',
|
||||
indexedAt: expect.any(String),
|
||||
payload: expect.anything(), // Better to compare payload parsed.
|
||||
updatedAt: expect.any(String),
|
||||
})
|
||||
expect(JSON.parse(dbResult.payload)).toStrictEqual({
|
||||
$type: 'app.bsky.notification.defs#preferences',
|
||||
...expected,
|
||||
})
|
||||
}
|
||||
|
||||
const input0 = {
|
||||
chat: {
|
||||
push: false,
|
||||
filter: 'accepted',
|
||||
},
|
||||
}
|
||||
const expected0: Preferences = {
|
||||
chat: input0.chat,
|
||||
follow: fp,
|
||||
like: fp,
|
||||
likeViaRepost: fp,
|
||||
mention: fp,
|
||||
quote: fp,
|
||||
reply: fp,
|
||||
repost: fp,
|
||||
repostViaRepost: fp,
|
||||
starterpackJoined: p,
|
||||
subscribedPost: p,
|
||||
unverified: p,
|
||||
verified: p,
|
||||
}
|
||||
await putAndAssert(input0, expected0)
|
||||
|
||||
const input1 = {
|
||||
mention: {
|
||||
list: false,
|
||||
push: false,
|
||||
filter: 'follows',
|
||||
},
|
||||
}
|
||||
const expected1: Preferences = {
|
||||
// Kept from the previous call.
|
||||
chat: input0.chat,
|
||||
follow: fp,
|
||||
like: fp,
|
||||
likeViaRepost: fp,
|
||||
mention: input1.mention,
|
||||
quote: fp,
|
||||
reply: fp,
|
||||
repost: fp,
|
||||
repostViaRepost: fp,
|
||||
starterpackJoined: p,
|
||||
subscribedPost: p,
|
||||
unverified: p,
|
||||
verified: p,
|
||||
}
|
||||
await putAndAssert(input1, expected1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const clearPrivateData = async (db: Database) => {
|
||||
await db.db.deleteFrom('private_data').execute()
|
||||
}
|
||||
|
@ -82,6 +82,17 @@ const validateOp = (req: PutOperationRequest): Operation => {
|
||||
throw new ConnectError('operation method is invalid', Code.InvalidArgument)
|
||||
}
|
||||
|
||||
if (req.method === Method.CREATE || req.method === Method.UPDATE) {
|
||||
try {
|
||||
JSON.parse(new TextDecoder().decode(req.payload))
|
||||
} catch (error) {
|
||||
throw new ConnectError(
|
||||
'payload must be a valid JSON when method is CREATE or UPDATE',
|
||||
Code.InvalidArgument,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (req.method === Method.DELETE && req.payload.length > 0) {
|
||||
throw new ConnectError(
|
||||
'cannot specify a payload when method is DELETE',
|
||||
|
@ -16,6 +16,10 @@ describe('operations', () => {
|
||||
let bsync: BsyncService
|
||||
let client: BsyncClient
|
||||
|
||||
const validPayload0 = Buffer.from(JSON.stringify({ value: 0 }))
|
||||
const validPayload1 = Buffer.from(JSON.stringify({ value: 1 }))
|
||||
const invalidPayload = Buffer.from('{invalid json}')
|
||||
|
||||
beforeAll(async () => {
|
||||
bsync = await BsyncService.create(
|
||||
envToCfg({
|
||||
@ -55,7 +59,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
})
|
||||
await expect(tryPutOperation1).rejects.toEqual(
|
||||
new ConnectError('missing auth', Code.Unauthenticated),
|
||||
@ -71,7 +75,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
})
|
||||
await expect(tryPutOperation2).rejects.toEqual(
|
||||
new ConnectError('invalid api key', Code.Unauthenticated),
|
||||
@ -85,7 +89,7 @@ describe('operations', () => {
|
||||
namespace: 'bad-namespace',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([]),
|
||||
payload: validPayload0,
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new ConnectError(
|
||||
@ -99,7 +103,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([]),
|
||||
payload: validPayload0,
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new ConnectError(
|
||||
@ -113,7 +117,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: '',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([]),
|
||||
payload: validPayload0,
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new ConnectError('operation key is required', Code.InvalidArgument),
|
||||
@ -124,18 +128,46 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.UNSPECIFIED,
|
||||
payload: Buffer.from([]),
|
||||
payload: validPayload0,
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new ConnectError('operation method is invalid', Code.InvalidArgument),
|
||||
)
|
||||
await expect(
|
||||
client.putOperation({
|
||||
actorDid: 'did:example:a',
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: invalidPayload,
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new ConnectError(
|
||||
'payload must be a valid JSON when method is CREATE or UPDATE',
|
||||
Code.InvalidArgument,
|
||||
),
|
||||
)
|
||||
await expect(
|
||||
client.putOperation({
|
||||
actorDid: 'did:example:a',
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.UPDATE,
|
||||
payload: invalidPayload,
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new ConnectError(
|
||||
'payload must be a valid JSON when method is CREATE or UPDATE',
|
||||
Code.InvalidArgument,
|
||||
),
|
||||
)
|
||||
await expect(
|
||||
client.putOperation({
|
||||
actorDid: 'did:example:a',
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.DELETE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
}),
|
||||
).rejects.toEqual(
|
||||
new ConnectError(
|
||||
@ -151,14 +183,14 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
})
|
||||
const res2 = await client.putOperation({
|
||||
actorDid: 'did:example:a',
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.UPDATE,
|
||||
payload: Buffer.from([4, 5, 6]),
|
||||
payload: validPayload1,
|
||||
})
|
||||
|
||||
expect(res1.operation?.id).toBe('1')
|
||||
@ -170,7 +202,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
createdAt: expect.any(Date),
|
||||
},
|
||||
{
|
||||
@ -179,7 +211,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.UPDATE,
|
||||
payload: Buffer.from([4, 5, 6]),
|
||||
payload: validPayload1,
|
||||
createdAt: expect.any(Date),
|
||||
},
|
||||
])
|
||||
@ -191,7 +223,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
})
|
||||
|
||||
const op = res.operation
|
||||
@ -202,7 +234,7 @@ describe('operations', () => {
|
||||
expect(op.namespace).toBe('app.bsky.some.col')
|
||||
expect(op.key).toBe('key1')
|
||||
expect(op.method).toBe(Method.CREATE)
|
||||
expect(op.payload).toEqual(Uint8Array.from([1, 2, 3]))
|
||||
expect(op.payload).toEqual(new Uint8Array(validPayload0))
|
||||
})
|
||||
})
|
||||
|
||||
@ -237,7 +269,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
})
|
||||
}
|
||||
|
||||
@ -266,7 +298,7 @@ describe('operations', () => {
|
||||
namespace: 'app.bsky.some.col',
|
||||
key: 'key1',
|
||||
method: Method.CREATE,
|
||||
payload: Buffer.from([1, 2, 3]),
|
||||
payload: validPayload0,
|
||||
})
|
||||
const res = await scanPromise
|
||||
expect(res.operations.length).toEqual(1)
|
||||
|
24
packages/ozone/src/lexicon/index.ts
generated
24
packages/ozone/src/lexicon/index.ts
generated
@ -138,9 +138,11 @@ import * as AppBskyGraphUnmuteActor from './types/app/bsky/graph/unmuteActor.js'
|
||||
import * as AppBskyGraphUnmuteActorList from './types/app/bsky/graph/unmuteActorList.js'
|
||||
import * as AppBskyGraphUnmuteThread from './types/app/bsky/graph/unmuteThread.js'
|
||||
import * as AppBskyLabelerGetServices from './types/app/bsky/labeler/getServices.js'
|
||||
import * as AppBskyNotificationGetPreferences from './types/app/bsky/notification/getPreferences.js'
|
||||
import * as AppBskyNotificationGetUnreadCount from './types/app/bsky/notification/getUnreadCount.js'
|
||||
import * as AppBskyNotificationListNotifications from './types/app/bsky/notification/listNotifications.js'
|
||||
import * as AppBskyNotificationPutPreferences from './types/app/bsky/notification/putPreferences.js'
|
||||
import * as AppBskyNotificationPutPreferencesV2 from './types/app/bsky/notification/putPreferencesV2.js'
|
||||
import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/registerPush.js'
|
||||
import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen.js'
|
||||
import * as AppBskyUnspeccedGetConfig from './types/app/bsky/unspecced/getConfig.js'
|
||||
@ -1903,6 +1905,17 @@ export class AppBskyNotificationNS {
|
||||
this._server = server
|
||||
}
|
||||
|
||||
getPreferences<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
AppBskyNotificationGetPreferences.Handler<ExtractAuth<AV>>,
|
||||
AppBskyNotificationGetPreferences.HandlerReqCtx<ExtractAuth<AV>>
|
||||
>,
|
||||
) {
|
||||
const nsid = 'app.bsky.notification.getPreferences' // @ts-ignore
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
getUnreadCount<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
@ -1936,6 +1949,17 @@ export class AppBskyNotificationNS {
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
putPreferencesV2<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
AppBskyNotificationPutPreferencesV2.Handler<ExtractAuth<AV>>,
|
||||
AppBskyNotificationPutPreferencesV2.HandlerReqCtx<ExtractAuth<AV>>
|
||||
>,
|
||||
) {
|
||||
const nsid = 'app.bsky.notification.putPreferencesV2' // @ts-ignore
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
registerPush<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
|
227
packages/ozone/src/lexicon/lexicons.ts
generated
227
packages/ozone/src/lexicon/lexicons.ts
generated
@ -9732,6 +9732,147 @@ export const schemaDict = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
chatPreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'accepted'],
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
filterablePreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'list', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'follows'],
|
||||
},
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preference: {
|
||||
type: 'object',
|
||||
required: ['list', 'push'],
|
||||
properties: {
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preferences: {
|
||||
type: 'object',
|
||||
required: [
|
||||
'chat',
|
||||
'follow',
|
||||
'like',
|
||||
'likeViaRepost',
|
||||
'mention',
|
||||
'quote',
|
||||
'reply',
|
||||
'repost',
|
||||
'repostViaRepost',
|
||||
'starterpackJoined',
|
||||
'subscribedPost',
|
||||
'unverified',
|
||||
'verified',
|
||||
],
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetPreferences: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.getPreferences',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'query',
|
||||
description:
|
||||
'Get notification-related preferences for an account. Requires auth.',
|
||||
parameters: {
|
||||
type: 'params',
|
||||
properties: {},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetUnreadCount: {
|
||||
@ -9924,6 +10065,90 @@ export const schemaDict = {
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationPutPreferencesV2: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.putPreferencesV2',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'procedure',
|
||||
description:
|
||||
'Set notification-related preferences for an account. Requires auth.',
|
||||
input: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationRegisterPush: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.registerPush',
|
||||
@ -16557,10 +16782,12 @@ export const ids = {
|
||||
AppBskyLabelerGetServices: 'app.bsky.labeler.getServices',
|
||||
AppBskyLabelerService: 'app.bsky.labeler.service',
|
||||
AppBskyNotificationDefs: 'app.bsky.notification.defs',
|
||||
AppBskyNotificationGetPreferences: 'app.bsky.notification.getPreferences',
|
||||
AppBskyNotificationGetUnreadCount: 'app.bsky.notification.getUnreadCount',
|
||||
AppBskyNotificationListNotifications:
|
||||
'app.bsky.notification.listNotifications',
|
||||
AppBskyNotificationPutPreferences: 'app.bsky.notification.putPreferences',
|
||||
AppBskyNotificationPutPreferencesV2: 'app.bsky.notification.putPreferencesV2',
|
||||
AppBskyNotificationRegisterPush: 'app.bsky.notification.registerPush',
|
||||
AppBskyNotificationUpdateSeen: 'app.bsky.notification.updateSeen',
|
||||
AppBskyRichtextFacet: 'app.bsky.richtext.facet',
|
||||
|
@ -27,3 +27,79 @@ export function isRecordDeleted<V>(v: V) {
|
||||
export function validateRecordDeleted<V>(v: V) {
|
||||
return validate<RecordDeleted & V>(v, id, hashRecordDeleted)
|
||||
}
|
||||
|
||||
export interface ChatPreference {
|
||||
$type?: 'app.bsky.notification.defs#chatPreference'
|
||||
filter: 'all' | 'accepted' | (string & {})
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashChatPreference = 'chatPreference'
|
||||
|
||||
export function isChatPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export function validateChatPreference<V>(v: V) {
|
||||
return validate<ChatPreference & V>(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export interface FilterablePreference {
|
||||
$type?: 'app.bsky.notification.defs#filterablePreference'
|
||||
filter: 'all' | 'follows' | (string & {})
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashFilterablePreference = 'filterablePreference'
|
||||
|
||||
export function isFilterablePreference<V>(v: V) {
|
||||
return is$typed(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export function validateFilterablePreference<V>(v: V) {
|
||||
return validate<FilterablePreference & V>(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export interface Preference {
|
||||
$type?: 'app.bsky.notification.defs#preference'
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashPreference = 'preference'
|
||||
|
||||
export function isPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export function validatePreference<V>(v: V) {
|
||||
return validate<Preference & V>(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export interface Preferences {
|
||||
$type?: 'app.bsky.notification.defs#preferences'
|
||||
chat: ChatPreference
|
||||
follow: FilterablePreference
|
||||
like: FilterablePreference
|
||||
likeViaRepost: FilterablePreference
|
||||
mention: FilterablePreference
|
||||
quote: FilterablePreference
|
||||
reply: FilterablePreference
|
||||
repost: FilterablePreference
|
||||
repostViaRepost: FilterablePreference
|
||||
starterpackJoined: Preference
|
||||
subscribedPost: Preference
|
||||
unverified: Preference
|
||||
verified: Preference
|
||||
}
|
||||
|
||||
const hashPreferences = 'preferences'
|
||||
|
||||
export function isPreferences<V>(v: V) {
|
||||
return is$typed(v, id, hashPreferences)
|
||||
}
|
||||
|
||||
export function validatePreferences<V>(v: V) {
|
||||
return validate<Preferences & V>(v, id, hashPreferences)
|
||||
}
|
||||
|
52
packages/ozone/src/lexicon/types/app/bsky/notification/getPreferences.ts
generated
Normal file
52
packages/ozone/src/lexicon/types/app/bsky/notification/getPreferences.ts
generated
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import express from 'express'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.getPreferences'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export type InputSchema = undefined
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export type HandlerInput = undefined
|
||||
|
||||
export interface HandlerSuccess {
|
||||
encoding: 'application/json'
|
||||
body: OutputSchema
|
||||
headers?: { [key: string]: string }
|
||||
}
|
||||
|
||||
export interface HandlerError {
|
||||
status: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
|
||||
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
||||
auth: HA
|
||||
params: QueryParams
|
||||
input: HandlerInput
|
||||
req: express.Request
|
||||
res: express.Response
|
||||
resetRouteRateLimits: () => Promise<void>
|
||||
}
|
||||
export type Handler<HA extends HandlerAuth = never> = (
|
||||
ctx: HandlerReqCtx<HA>,
|
||||
) => Promise<HandlerOutput> | HandlerOutput
|
69
packages/ozone/src/lexicon/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
69
packages/ozone/src/lexicon/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import express from 'express'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.putPreferencesV2'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export interface InputSchema {
|
||||
chat?: AppBskyNotificationDefs.ChatPreference
|
||||
follow?: AppBskyNotificationDefs.FilterablePreference
|
||||
like?: AppBskyNotificationDefs.FilterablePreference
|
||||
likeViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
mention?: AppBskyNotificationDefs.FilterablePreference
|
||||
quote?: AppBskyNotificationDefs.FilterablePreference
|
||||
reply?: AppBskyNotificationDefs.FilterablePreference
|
||||
repost?: AppBskyNotificationDefs.FilterablePreference
|
||||
repostViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
starterpackJoined?: AppBskyNotificationDefs.Preference
|
||||
subscribedPost?: AppBskyNotificationDefs.Preference
|
||||
unverified?: AppBskyNotificationDefs.Preference
|
||||
verified?: AppBskyNotificationDefs.Preference
|
||||
}
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export interface HandlerInput {
|
||||
encoding: 'application/json'
|
||||
body: InputSchema
|
||||
}
|
||||
|
||||
export interface HandlerSuccess {
|
||||
encoding: 'application/json'
|
||||
body: OutputSchema
|
||||
headers?: { [key: string]: string }
|
||||
}
|
||||
|
||||
export interface HandlerError {
|
||||
status: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
|
||||
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
||||
auth: HA
|
||||
params: QueryParams
|
||||
input: HandlerInput
|
||||
req: express.Request
|
||||
res: express.Response
|
||||
resetRouteRateLimits: () => Promise<void>
|
||||
}
|
||||
export type Handler<HA extends HandlerAuth = never> = (
|
||||
ctx: HandlerReqCtx<HA>,
|
||||
) => Promise<HandlerOutput> | HandlerOutput
|
24
packages/pds/src/lexicon/index.ts
generated
24
packages/pds/src/lexicon/index.ts
generated
@ -138,9 +138,11 @@ import * as AppBskyGraphUnmuteActor from './types/app/bsky/graph/unmuteActor.js'
|
||||
import * as AppBskyGraphUnmuteActorList from './types/app/bsky/graph/unmuteActorList.js'
|
||||
import * as AppBskyGraphUnmuteThread from './types/app/bsky/graph/unmuteThread.js'
|
||||
import * as AppBskyLabelerGetServices from './types/app/bsky/labeler/getServices.js'
|
||||
import * as AppBskyNotificationGetPreferences from './types/app/bsky/notification/getPreferences.js'
|
||||
import * as AppBskyNotificationGetUnreadCount from './types/app/bsky/notification/getUnreadCount.js'
|
||||
import * as AppBskyNotificationListNotifications from './types/app/bsky/notification/listNotifications.js'
|
||||
import * as AppBskyNotificationPutPreferences from './types/app/bsky/notification/putPreferences.js'
|
||||
import * as AppBskyNotificationPutPreferencesV2 from './types/app/bsky/notification/putPreferencesV2.js'
|
||||
import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/registerPush.js'
|
||||
import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen.js'
|
||||
import * as AppBskyUnspeccedGetConfig from './types/app/bsky/unspecced/getConfig.js'
|
||||
@ -1903,6 +1905,17 @@ export class AppBskyNotificationNS {
|
||||
this._server = server
|
||||
}
|
||||
|
||||
getPreferences<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
AppBskyNotificationGetPreferences.Handler<ExtractAuth<AV>>,
|
||||
AppBskyNotificationGetPreferences.HandlerReqCtx<ExtractAuth<AV>>
|
||||
>,
|
||||
) {
|
||||
const nsid = 'app.bsky.notification.getPreferences' // @ts-ignore
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
getUnreadCount<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
@ -1936,6 +1949,17 @@ export class AppBskyNotificationNS {
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
putPreferencesV2<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
AppBskyNotificationPutPreferencesV2.Handler<ExtractAuth<AV>>,
|
||||
AppBskyNotificationPutPreferencesV2.HandlerReqCtx<ExtractAuth<AV>>
|
||||
>,
|
||||
) {
|
||||
const nsid = 'app.bsky.notification.putPreferencesV2' // @ts-ignore
|
||||
return this._server.xrpc.method(nsid, cfg)
|
||||
}
|
||||
|
||||
registerPush<AV extends AuthVerifier>(
|
||||
cfg: ConfigOf<
|
||||
AV,
|
||||
|
227
packages/pds/src/lexicon/lexicons.ts
generated
227
packages/pds/src/lexicon/lexicons.ts
generated
@ -9732,6 +9732,147 @@ export const schemaDict = {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
chatPreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'accepted'],
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
filterablePreference: {
|
||||
type: 'object',
|
||||
required: ['filter', 'list', 'push'],
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'string',
|
||||
knownValues: ['all', 'follows'],
|
||||
},
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preference: {
|
||||
type: 'object',
|
||||
required: ['list', 'push'],
|
||||
properties: {
|
||||
list: {
|
||||
type: 'boolean',
|
||||
},
|
||||
push: {
|
||||
type: 'boolean',
|
||||
},
|
||||
},
|
||||
},
|
||||
preferences: {
|
||||
type: 'object',
|
||||
required: [
|
||||
'chat',
|
||||
'follow',
|
||||
'like',
|
||||
'likeViaRepost',
|
||||
'mention',
|
||||
'quote',
|
||||
'reply',
|
||||
'repost',
|
||||
'repostViaRepost',
|
||||
'starterpackJoined',
|
||||
'subscribedPost',
|
||||
'unverified',
|
||||
'verified',
|
||||
],
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetPreferences: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.getPreferences',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'query',
|
||||
description:
|
||||
'Get notification-related preferences for an account. Requires auth.',
|
||||
parameters: {
|
||||
type: 'params',
|
||||
properties: {},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationGetUnreadCount: {
|
||||
@ -9924,6 +10065,90 @@ export const schemaDict = {
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationPutPreferencesV2: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.putPreferencesV2',
|
||||
defs: {
|
||||
main: {
|
||||
type: 'procedure',
|
||||
description:
|
||||
'Set notification-related preferences for an account. Requires auth.',
|
||||
input: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
chat: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#chatPreference',
|
||||
},
|
||||
follow: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
like: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
likeViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
mention: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
quote: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
reply: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
repostViaRepost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#filterablePreference',
|
||||
},
|
||||
starterpackJoined: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
subscribedPost: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
unverified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
verified: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preference',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
output: {
|
||||
encoding: 'application/json',
|
||||
schema: {
|
||||
type: 'object',
|
||||
required: ['preferences'],
|
||||
properties: {
|
||||
preferences: {
|
||||
type: 'ref',
|
||||
ref: 'lex:app.bsky.notification.defs#preferences',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AppBskyNotificationRegisterPush: {
|
||||
lexicon: 1,
|
||||
id: 'app.bsky.notification.registerPush',
|
||||
@ -16557,10 +16782,12 @@ export const ids = {
|
||||
AppBskyLabelerGetServices: 'app.bsky.labeler.getServices',
|
||||
AppBskyLabelerService: 'app.bsky.labeler.service',
|
||||
AppBskyNotificationDefs: 'app.bsky.notification.defs',
|
||||
AppBskyNotificationGetPreferences: 'app.bsky.notification.getPreferences',
|
||||
AppBskyNotificationGetUnreadCount: 'app.bsky.notification.getUnreadCount',
|
||||
AppBskyNotificationListNotifications:
|
||||
'app.bsky.notification.listNotifications',
|
||||
AppBskyNotificationPutPreferences: 'app.bsky.notification.putPreferences',
|
||||
AppBskyNotificationPutPreferencesV2: 'app.bsky.notification.putPreferencesV2',
|
||||
AppBskyNotificationRegisterPush: 'app.bsky.notification.registerPush',
|
||||
AppBskyNotificationUpdateSeen: 'app.bsky.notification.updateSeen',
|
||||
AppBskyRichtextFacet: 'app.bsky.richtext.facet',
|
||||
|
@ -27,3 +27,79 @@ export function isRecordDeleted<V>(v: V) {
|
||||
export function validateRecordDeleted<V>(v: V) {
|
||||
return validate<RecordDeleted & V>(v, id, hashRecordDeleted)
|
||||
}
|
||||
|
||||
export interface ChatPreference {
|
||||
$type?: 'app.bsky.notification.defs#chatPreference'
|
||||
filter: 'all' | 'accepted' | (string & {})
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashChatPreference = 'chatPreference'
|
||||
|
||||
export function isChatPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export function validateChatPreference<V>(v: V) {
|
||||
return validate<ChatPreference & V>(v, id, hashChatPreference)
|
||||
}
|
||||
|
||||
export interface FilterablePreference {
|
||||
$type?: 'app.bsky.notification.defs#filterablePreference'
|
||||
filter: 'all' | 'follows' | (string & {})
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashFilterablePreference = 'filterablePreference'
|
||||
|
||||
export function isFilterablePreference<V>(v: V) {
|
||||
return is$typed(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export function validateFilterablePreference<V>(v: V) {
|
||||
return validate<FilterablePreference & V>(v, id, hashFilterablePreference)
|
||||
}
|
||||
|
||||
export interface Preference {
|
||||
$type?: 'app.bsky.notification.defs#preference'
|
||||
list: boolean
|
||||
push: boolean
|
||||
}
|
||||
|
||||
const hashPreference = 'preference'
|
||||
|
||||
export function isPreference<V>(v: V) {
|
||||
return is$typed(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export function validatePreference<V>(v: V) {
|
||||
return validate<Preference & V>(v, id, hashPreference)
|
||||
}
|
||||
|
||||
export interface Preferences {
|
||||
$type?: 'app.bsky.notification.defs#preferences'
|
||||
chat: ChatPreference
|
||||
follow: FilterablePreference
|
||||
like: FilterablePreference
|
||||
likeViaRepost: FilterablePreference
|
||||
mention: FilterablePreference
|
||||
quote: FilterablePreference
|
||||
reply: FilterablePreference
|
||||
repost: FilterablePreference
|
||||
repostViaRepost: FilterablePreference
|
||||
starterpackJoined: Preference
|
||||
subscribedPost: Preference
|
||||
unverified: Preference
|
||||
verified: Preference
|
||||
}
|
||||
|
||||
const hashPreferences = 'preferences'
|
||||
|
||||
export function isPreferences<V>(v: V) {
|
||||
return is$typed(v, id, hashPreferences)
|
||||
}
|
||||
|
||||
export function validatePreferences<V>(v: V) {
|
||||
return validate<Preferences & V>(v, id, hashPreferences)
|
||||
}
|
||||
|
52
packages/pds/src/lexicon/types/app/bsky/notification/getPreferences.ts
generated
Normal file
52
packages/pds/src/lexicon/types/app/bsky/notification/getPreferences.ts
generated
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import express from 'express'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.getPreferences'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export type InputSchema = undefined
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export type HandlerInput = undefined
|
||||
|
||||
export interface HandlerSuccess {
|
||||
encoding: 'application/json'
|
||||
body: OutputSchema
|
||||
headers?: { [key: string]: string }
|
||||
}
|
||||
|
||||
export interface HandlerError {
|
||||
status: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
|
||||
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
||||
auth: HA
|
||||
params: QueryParams
|
||||
input: HandlerInput
|
||||
req: express.Request
|
||||
res: express.Response
|
||||
resetRouteRateLimits: () => Promise<void>
|
||||
}
|
||||
export type Handler<HA extends HandlerAuth = never> = (
|
||||
ctx: HandlerReqCtx<HA>,
|
||||
) => Promise<HandlerOutput> | HandlerOutput
|
69
packages/pds/src/lexicon/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
69
packages/pds/src/lexicon/types/app/bsky/notification/putPreferencesV2.ts
generated
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* GENERATED CODE - DO NOT MODIFY
|
||||
*/
|
||||
import express from 'express'
|
||||
import { type ValidationResult, BlobRef } from '@atproto/lexicon'
|
||||
import { CID } from 'multiformats/cid'
|
||||
import { validate as _validate } from '../../../../lexicons'
|
||||
import {
|
||||
type $Typed,
|
||||
is$typed as _is$typed,
|
||||
type OmitKey,
|
||||
} from '../../../../util'
|
||||
import { HandlerAuth, HandlerPipeThrough } from '@atproto/xrpc-server'
|
||||
import type * as AppBskyNotificationDefs from './defs.js'
|
||||
|
||||
const is$typed = _is$typed,
|
||||
validate = _validate
|
||||
const id = 'app.bsky.notification.putPreferencesV2'
|
||||
|
||||
export interface QueryParams {}
|
||||
|
||||
export interface InputSchema {
|
||||
chat?: AppBskyNotificationDefs.ChatPreference
|
||||
follow?: AppBskyNotificationDefs.FilterablePreference
|
||||
like?: AppBskyNotificationDefs.FilterablePreference
|
||||
likeViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
mention?: AppBskyNotificationDefs.FilterablePreference
|
||||
quote?: AppBskyNotificationDefs.FilterablePreference
|
||||
reply?: AppBskyNotificationDefs.FilterablePreference
|
||||
repost?: AppBskyNotificationDefs.FilterablePreference
|
||||
repostViaRepost?: AppBskyNotificationDefs.FilterablePreference
|
||||
starterpackJoined?: AppBskyNotificationDefs.Preference
|
||||
subscribedPost?: AppBskyNotificationDefs.Preference
|
||||
unverified?: AppBskyNotificationDefs.Preference
|
||||
verified?: AppBskyNotificationDefs.Preference
|
||||
}
|
||||
|
||||
export interface OutputSchema {
|
||||
preferences: AppBskyNotificationDefs.Preferences
|
||||
}
|
||||
|
||||
export interface HandlerInput {
|
||||
encoding: 'application/json'
|
||||
body: InputSchema
|
||||
}
|
||||
|
||||
export interface HandlerSuccess {
|
||||
encoding: 'application/json'
|
||||
body: OutputSchema
|
||||
headers?: { [key: string]: string }
|
||||
}
|
||||
|
||||
export interface HandlerError {
|
||||
status: number
|
||||
message?: string
|
||||
}
|
||||
|
||||
export type HandlerOutput = HandlerError | HandlerSuccess | HandlerPipeThrough
|
||||
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
||||
auth: HA
|
||||
params: QueryParams
|
||||
input: HandlerInput
|
||||
req: express.Request
|
||||
res: express.Response
|
||||
resetRouteRateLimits: () => Promise<void>
|
||||
}
|
||||
export type Handler<HA extends HandlerAuth = never> = (
|
||||
ctx: HandlerReqCtx<HA>,
|
||||
) => Promise<HandlerOutput> | HandlerOutput
|
Loading…
x
Reference in New Issue
Block a user