@atproto/bsky 0.0.150 → 0.0.152

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/api/app/bsky/unspecced/getPostThreadHiddenV2.d.ts +4 -0
  3. package/dist/api/app/bsky/unspecced/getPostThreadHiddenV2.d.ts.map +1 -0
  4. package/dist/api/app/bsky/unspecced/getPostThreadHiddenV2.js +76 -0
  5. package/dist/api/app/bsky/unspecced/getPostThreadHiddenV2.js.map +1 -0
  6. package/dist/api/app/bsky/unspecced/getPostThreadV2.d.ts +4 -0
  7. package/dist/api/app/bsky/unspecced/getPostThreadV2.d.ts.map +1 -0
  8. package/dist/api/app/bsky/unspecced/getPostThreadV2.js +86 -0
  9. package/dist/api/app/bsky/unspecced/getPostThreadV2.js.map +1 -0
  10. package/dist/api/index.d.ts.map +1 -1
  11. package/dist/api/index.js +4 -0
  12. package/dist/api/index.js.map +1 -1
  13. package/dist/config.d.ts +2 -0
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/config.js +7 -0
  16. package/dist/config.js.map +1 -1
  17. package/dist/data-plane/server/db/migrations/20250526T023712742Z-like-repost-via.d.ts +4 -0
  18. package/dist/data-plane/server/db/migrations/20250526T023712742Z-like-repost-via.d.ts.map +1 -0
  19. package/dist/data-plane/server/db/migrations/20250526T023712742Z-like-repost-via.js +17 -0
  20. package/dist/data-plane/server/db/migrations/20250526T023712742Z-like-repost-via.js.map +1 -0
  21. package/dist/data-plane/server/db/migrations/index.d.ts +1 -0
  22. package/dist/data-plane/server/db/migrations/index.d.ts.map +1 -1
  23. package/dist/data-plane/server/db/migrations/index.js +2 -1
  24. package/dist/data-plane/server/db/migrations/index.js.map +1 -1
  25. package/dist/data-plane/server/db/tables/like.d.ts +2 -0
  26. package/dist/data-plane/server/db/tables/like.d.ts.map +1 -1
  27. package/dist/data-plane/server/db/tables/repost.d.ts +2 -0
  28. package/dist/data-plane/server/db/tables/repost.d.ts.map +1 -1
  29. package/dist/data-plane/server/indexing/plugins/like.d.ts.map +1 -1
  30. package/dist/data-plane/server/indexing/plugins/like.js +32 -9
  31. package/dist/data-plane/server/indexing/plugins/like.js.map +1 -1
  32. package/dist/data-plane/server/indexing/plugins/repost.d.ts.map +1 -1
  33. package/dist/data-plane/server/indexing/plugins/repost.js +32 -9
  34. package/dist/data-plane/server/indexing/plugins/repost.js.map +1 -1
  35. package/dist/hydration/feed.d.ts.map +1 -1
  36. package/dist/hydration/feed.js.map +1 -1
  37. package/dist/lexicon/index.d.ts +6 -2
  38. package/dist/lexicon/index.d.ts.map +1 -1
  39. package/dist/lexicon/index.js +12 -4
  40. package/dist/lexicon/index.js.map +1 -1
  41. package/dist/lexicon/lexicons.d.ts +536 -88
  42. package/dist/lexicon/lexicons.d.ts.map +1 -1
  43. package/dist/lexicon/lexicons.js +279 -44
  44. package/dist/lexicon/lexicons.js.map +1 -1
  45. package/dist/lexicon/types/app/bsky/feed/defs.d.ts +2 -0
  46. package/dist/lexicon/types/app/bsky/feed/defs.d.ts.map +1 -1
  47. package/dist/lexicon/types/app/bsky/feed/defs.js.map +1 -1
  48. package/dist/lexicon/types/app/bsky/feed/like.d.ts +1 -0
  49. package/dist/lexicon/types/app/bsky/feed/like.d.ts.map +1 -1
  50. package/dist/lexicon/types/app/bsky/feed/like.js.map +1 -1
  51. package/dist/lexicon/types/app/bsky/feed/repost.d.ts +1 -0
  52. package/dist/lexicon/types/app/bsky/feed/repost.d.ts.map +1 -1
  53. package/dist/lexicon/types/app/bsky/feed/repost.js.map +1 -1
  54. package/dist/lexicon/types/app/bsky/notification/listNotifications.d.ts +2 -2
  55. package/dist/lexicon/types/app/bsky/notification/listNotifications.d.ts.map +1 -1
  56. package/dist/lexicon/types/app/bsky/notification/listNotifications.js.map +1 -1
  57. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.d.ts +61 -0
  58. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.d.ts.map +1 -0
  59. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.js +25 -0
  60. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.js.map +1 -0
  61. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.d.ts +92 -0
  62. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.d.ts.map +1 -0
  63. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.js +52 -0
  64. package/dist/lexicon/types/app/bsky/unspecced/getPostThreadV2.js.map +1 -0
  65. package/dist/views/index.d.ts +36 -1
  66. package/dist/views/index.d.ts.map +1 -1
  67. package/dist/views/index.js +468 -2
  68. package/dist/views/index.js.map +1 -1
  69. package/dist/views/threads-v2.d.ts +62 -0
  70. package/dist/views/threads-v2.d.ts.map +1 -0
  71. package/dist/views/threads-v2.js +180 -0
  72. package/dist/views/threads-v2.js.map +1 -0
  73. package/package.json +4 -4
  74. package/src/api/app/bsky/unspecced/getPostThreadHiddenV2.ts +116 -0
  75. package/src/api/app/bsky/unspecced/getPostThreadV2.ts +130 -0
  76. package/src/api/index.ts +4 -0
  77. package/src/config.ts +9 -0
  78. package/src/data-plane/server/db/migrations/20250526T023712742Z-like-repost-via.ts +17 -0
  79. package/src/data-plane/server/db/migrations/index.ts +1 -0
  80. package/src/data-plane/server/db/tables/like.ts +2 -0
  81. package/src/data-plane/server/db/tables/repost.ts +2 -0
  82. package/src/data-plane/server/indexing/plugins/like.ts +39 -9
  83. package/src/data-plane/server/indexing/plugins/repost.ts +38 -9
  84. package/src/hydration/feed.ts +1 -0
  85. package/src/lexicon/index.ts +33 -9
  86. package/src/lexicon/lexicons.ts +298 -45
  87. package/src/lexicon/types/app/bsky/feed/defs.ts +2 -0
  88. package/src/lexicon/types/app/bsky/feed/like.ts +1 -0
  89. package/src/lexicon/types/app/bsky/feed/repost.ts +1 -0
  90. package/src/lexicon/types/app/bsky/notification/listNotifications.ts +3 -1
  91. package/src/lexicon/types/app/bsky/unspecced/getPostThreadHiddenV2.ts +93 -0
  92. package/src/lexicon/types/app/bsky/unspecced/getPostThreadV2.ts +160 -0
  93. package/src/views/index.ts +747 -2
  94. package/src/views/threads-v2.ts +351 -0
  95. package/tests/__snapshots__/feed-generation.test.ts.snap +2 -0
  96. package/tests/seed/thread-v2.ts +775 -0
  97. package/tests/seed/util.ts +52 -0
  98. package/tests/views/__snapshots__/author-feed.test.ts.snap +30 -24
  99. package/tests/views/__snapshots__/notifications.test.ts.snap +1164 -229
  100. package/tests/views/__snapshots__/thread-v2.test.ts.snap +1091 -0
  101. package/tests/views/__snapshots__/timeline.test.ts.snap +398 -376
  102. package/tests/views/notifications.test.ts +177 -0
  103. package/tests/views/thread-v2.test.ts +2009 -0
  104. package/tsconfig.build.tsbuildinfo +1 -1
  105. package/tsconfig.tests.tsbuildinfo +1 -1
@@ -0,0 +1,130 @@
1
+ import { ServerConfig } from '../../../../config'
2
+ import { AppContext } from '../../../../context'
3
+ import { Code, DataPlaneClient, isDataplaneError } from '../../../../data-plane'
4
+ import { HydrateCtx, Hydrator } from '../../../../hydration/hydrator'
5
+ import { Server } from '../../../../lexicon'
6
+ import { QueryParams } from '../../../../lexicon/types/app/bsky/unspecced/getPostThreadV2'
7
+ import {
8
+ HydrationFnInput,
9
+ PresentationFnInput,
10
+ SkeletonFnInput,
11
+ createPipeline,
12
+ noRules,
13
+ } from '../../../../pipeline'
14
+ import { postUriToThreadgateUri } from '../../../../util/uris'
15
+ import { Views } from '../../../../views'
16
+ import { resHeaders } from '../../../util'
17
+
18
+ export default function (server: Server, ctx: AppContext) {
19
+ const getPostThread = createPipeline(
20
+ skeleton,
21
+ hydration,
22
+ noRules, // handled in presentation: 3p block-violating replies are turned to #blockedPost, viewer blocks turned to #notFoundPost.
23
+ presentation,
24
+ )
25
+ server.app.bsky.unspecced.getPostThreadV2({
26
+ auth: ctx.authVerifier.optionalStandardOrRole,
27
+ handler: async ({ params, auth, req }) => {
28
+ const { viewer, includeTakedowns, include3pBlocks } =
29
+ ctx.authVerifier.parseCreds(auth)
30
+ const labelers = ctx.reqLabelers(req)
31
+ const hydrateCtx = await ctx.hydrator.createContext({
32
+ labelers,
33
+ viewer,
34
+ includeTakedowns,
35
+ include3pBlocks,
36
+ })
37
+
38
+ return {
39
+ encoding: 'application/json',
40
+ body: await getPostThread({ ...params, hydrateCtx }, ctx),
41
+ headers: resHeaders({
42
+ labelers: hydrateCtx.labelers,
43
+ }),
44
+ }
45
+ },
46
+ })
47
+ }
48
+
49
+ const skeleton = async (inputs: SkeletonFnInput<Context, Params>) => {
50
+ const { ctx, params } = inputs
51
+ const anchor = await ctx.hydrator.resolveUri(params.anchor)
52
+ try {
53
+ const res = await ctx.dataplane.getThread({
54
+ postUri: anchor,
55
+ above: calculateAbove(ctx, params),
56
+ below: calculateBelow(ctx, anchor, params),
57
+ })
58
+ return {
59
+ anchor,
60
+ uris: res.uris,
61
+ }
62
+ } catch (err) {
63
+ if (isDataplaneError(err, Code.NotFound)) {
64
+ return {
65
+ anchor,
66
+ uris: [],
67
+ }
68
+ } else {
69
+ throw err
70
+ }
71
+ }
72
+ }
73
+
74
+ const hydration = async (
75
+ inputs: HydrationFnInput<Context, Params, Skeleton>,
76
+ ) => {
77
+ const { ctx, params, skeleton } = inputs
78
+ return ctx.hydrator.hydrateThreadPosts(
79
+ skeleton.uris.map((uri) => ({ uri })),
80
+ params.hydrateCtx,
81
+ )
82
+ }
83
+
84
+ const presentation = (
85
+ inputs: PresentationFnInput<Context, Params, Skeleton>,
86
+ ) => {
87
+ const { ctx, params, skeleton, hydration } = inputs
88
+ const { hasHiddenReplies, thread } = ctx.views.threadV2(skeleton, hydration, {
89
+ above: calculateAbove(ctx, params),
90
+ below: calculateBelow(ctx, skeleton.anchor, params),
91
+ branchingFactor: params.branchingFactor,
92
+ prioritizeFollowedUsers: params.prioritizeFollowedUsers,
93
+ sort: params.sort,
94
+ })
95
+
96
+ const rootUri =
97
+ hydration.posts?.get(skeleton.anchor)?.record.reply?.root.uri ??
98
+ skeleton.anchor
99
+ const threadgate = ctx.views.threadgate(
100
+ postUriToThreadgateUri(rootUri),
101
+ hydration,
102
+ )
103
+ return { hasHiddenReplies, thread, threadgate }
104
+ }
105
+
106
+ type Context = {
107
+ dataplane: DataPlaneClient
108
+ hydrator: Hydrator
109
+ views: Views
110
+ cfg: ServerConfig
111
+ }
112
+
113
+ type Params = QueryParams & { hydrateCtx: HydrateCtx }
114
+
115
+ type Skeleton = {
116
+ anchor: string
117
+ uris: string[]
118
+ }
119
+
120
+ const calculateAbove = (ctx: Context, params: Params) => {
121
+ return params.above ? ctx.cfg.maxThreadParents : 0
122
+ }
123
+
124
+ const calculateBelow = (ctx: Context, anchor: string, params: Params) => {
125
+ let maxDepth = ctx.cfg.maxThreadDepth
126
+ if (ctx.cfg.bigThreadUris.has(anchor) && ctx.cfg.bigThreadDepth) {
127
+ maxDepth = ctx.cfg.bigThreadDepth
128
+ }
129
+ return maxDepth ? Math.min(maxDepth, params.below) : params.below
130
+ }
package/src/api/index.ts CHANGED
@@ -49,6 +49,8 @@ import registerPush from './app/bsky/notification/registerPush'
49
49
  import updateSeen from './app/bsky/notification/updateSeen'
50
50
  import getConfig from './app/bsky/unspecced/getConfig'
51
51
  import getPopularFeedGenerators from './app/bsky/unspecced/getPopularFeedGenerators'
52
+ import getPostThreadHiddenV2 from './app/bsky/unspecced/getPostThreadHiddenV2'
53
+ import getPostThreadV2 from './app/bsky/unspecced/getPostThreadV2'
52
54
  import getUnspeccedSuggestedFeeds from './app/bsky/unspecced/getSuggestedFeeds'
53
55
  import getSuggestedStarterPacks from './app/bsky/unspecced/getSuggestedStarterPacks'
54
56
  import getSuggestedUsers from './app/bsky/unspecced/getSuggestedUsers'
@@ -82,6 +84,8 @@ export default function (server: Server, ctx: AppContext) {
82
84
  getListFeed(server, ctx)
83
85
  getQuotes(server, ctx)
84
86
  getPostThread(server, ctx)
87
+ getPostThreadHiddenV2(server, ctx)
88
+ getPostThreadV2(server, ctx)
85
89
  getPosts(server, ctx)
86
90
  searchPosts(server, ctx)
87
91
  getActorLikes(server, ctx)
package/src/config.ts CHANGED
@@ -56,6 +56,7 @@ export interface ServerConfigValues {
56
56
  bigThreadUris: Set<string>
57
57
  bigThreadDepth?: number
58
58
  maxThreadDepth?: number
59
+ maxThreadParents: number
59
60
  // notifications
60
61
  notificationsDelayMs?: number
61
62
  // client config
@@ -191,6 +192,9 @@ export class ServerConfig {
191
192
  const maxThreadDepth = process.env.BSKY_MAX_THREAD_DEPTH
192
193
  ? parseInt(process.env.BSKY_MAX_THREAD_DEPTH || '', 10)
193
194
  : undefined
195
+ const maxThreadParents = process.env.BSKY_MAX_THREAD_PARENTS
196
+ ? parseInt(process.env.BSKY_MAX_THREAD_PARENTS || '', 10)
197
+ : 50
194
198
 
195
199
  const notificationsDelayMs = process.env.BSKY_NOTIFICATIONS_DELAY_MS
196
200
  ? parseInt(process.env.BSKY_NOTIFICATIONS_DELAY_MS || '', 10)
@@ -258,6 +262,7 @@ export class ServerConfig {
258
262
  bigThreadUris,
259
263
  bigThreadDepth,
260
264
  maxThreadDepth,
265
+ maxThreadParents,
261
266
  notificationsDelayMs,
262
267
  disableSsrfProtection,
263
268
  proxyAllowHTTP2,
@@ -458,6 +463,10 @@ export class ServerConfig {
458
463
  return this.cfg.maxThreadDepth
459
464
  }
460
465
 
466
+ get maxThreadParents() {
467
+ return this.cfg.maxThreadParents
468
+ }
469
+
461
470
  get notificationsDelayMs() {
462
471
  return this.cfg.notificationsDelayMs ?? 0
463
472
  }
@@ -0,0 +1,17 @@
1
+ import { Kysely } from 'kysely'
2
+
3
+ export async function up(db: Kysely<unknown>): Promise<void> {
4
+ await db.schema.alterTable('like').addColumn('via', 'varchar').execute()
5
+ await db.schema.alterTable('like').addColumn('viaCid', 'varchar').execute()
6
+
7
+ await db.schema.alterTable('repost').addColumn('via', 'varchar').execute()
8
+ await db.schema.alterTable('repost').addColumn('viaCid', 'varchar').execute()
9
+ }
10
+
11
+ export async function down(db: Kysely<unknown>): Promise<void> {
12
+ await db.schema.alterTable('like').dropColumn('via').execute()
13
+ await db.schema.alterTable('like').dropColumn('viaCid').execute()
14
+
15
+ await db.schema.alterTable('repost').dropColumn('via').execute()
16
+ await db.schema.alterTable('repost').dropColumn('viaCid').execute()
17
+ }
@@ -48,3 +48,4 @@ export * as _20241114T153108102Z from './20241114T153108102Z-add-starter-packs-n
48
48
  export * as _20250116T222618297Z from './20250116T222618297Z-post-embed-video'
49
49
  export * as _20250207T174822012Z from './20250207T174822012Z-add-label-exp'
50
50
  export * as _20250404T163421487Z from './20250404T163421487Z-verifications'
51
+ export * as _20250526T023712742Z from './20250526T023712742Z-like-repost-via'
@@ -8,6 +8,8 @@ export interface Like {
8
8
  creator: string
9
9
  subject: string
10
10
  subjectCid: string
11
+ via: string | null
12
+ viaCid: string | null
11
13
  createdAt: string
12
14
  indexedAt: string
13
15
  sortAt: GeneratedAlways<string>
@@ -8,6 +8,8 @@ export interface Repost {
8
8
  creator: string
9
9
  subject: string
10
10
  subjectCid: string
11
+ via: string | null
12
+ viaCid: string | null
11
13
  createdAt: string
12
14
  indexedAt: string
13
15
  sortAt: GeneratedAlways<string>
@@ -1,4 +1,4 @@
1
- import { Selectable } from 'kysely'
1
+ import { Insertable, Selectable } from 'kysely'
2
2
  import { CID } from 'multiformats/cid'
3
3
  import { AtUri, normalizeDatetimeAlways } from '@atproto/syntax'
4
4
  import * as lex from '../../../../lexicon/lexicons'
@@ -6,10 +6,13 @@ import * as Like from '../../../../lexicon/types/app/bsky/feed/like'
6
6
  import { BackgroundQueue } from '../../background'
7
7
  import { Database } from '../../db'
8
8
  import { DatabaseSchema, DatabaseSchemaType } from '../../db/database-schema'
9
+ import { Notification } from '../../db/tables/notification'
9
10
  import { countAll, excluded } from '../../db/util'
10
11
  import { RecordProcessor } from '../processor'
11
12
 
12
13
  const lexId = lex.ids.AppBskyFeedLike
14
+
15
+ type Notif = Insertable<Notification>
13
16
  type IndexedLike = Selectable<DatabaseSchemaType['like']>
14
17
 
15
18
  const insertFn = async (
@@ -27,6 +30,8 @@ const insertFn = async (
27
30
  creator: uri.host,
28
31
  subject: obj.subject.uri,
29
32
  subjectCid: obj.subject.cid,
33
+ via: obj.via?.uri,
34
+ viaCid: obj.via?.cid,
30
35
  createdAt: normalizeDatetimeAlways(obj.createdAt),
31
36
  indexedAt: timestamp,
32
37
  })
@@ -53,20 +58,45 @@ const findDuplicate = async (
53
58
  const notifsForInsert = (obj: IndexedLike) => {
54
59
  const subjectUri = new AtUri(obj.subject)
55
60
  // prevent self-notifications
56
- const isSelf = subjectUri.host === obj.creator
57
- return isSelf
58
- ? []
59
- : [
61
+ const isLikeFromSubjectUser = subjectUri.host === obj.creator
62
+ if (isLikeFromSubjectUser) {
63
+ return []
64
+ }
65
+
66
+ const notifs: Notif[] = [
67
+ // Notification to the author of the liked record.
68
+ {
69
+ did: subjectUri.host,
70
+ author: obj.creator,
71
+ recordUri: obj.uri,
72
+ recordCid: obj.cid,
73
+ reason: 'like' as const,
74
+ reasonSubject: subjectUri.toString(),
75
+ sortAt: obj.sortAt,
76
+ },
77
+ ]
78
+
79
+ if (obj.via) {
80
+ const viaUri = new AtUri(obj.via)
81
+ const isLikeFromViaSubjectUser = viaUri.host === obj.creator
82
+ // prevent self-notifications
83
+ if (!isLikeFromViaSubjectUser) {
84
+ notifs.push(
85
+ // Notification to the reposter via whose repost the like was made.
60
86
  {
61
- did: subjectUri.host,
87
+ did: viaUri.host,
62
88
  author: obj.creator,
63
89
  recordUri: obj.uri,
64
90
  recordCid: obj.cid,
65
- reason: 'like' as const,
66
- reasonSubject: subjectUri.toString(),
91
+ reason: 'like-via-repost' as const,
92
+ reasonSubject: viaUri.toString(),
67
93
  sortAt: obj.sortAt,
68
94
  },
69
- ]
95
+ )
96
+ }
97
+ }
98
+
99
+ return notifs
70
100
  }
71
101
 
72
102
  const deleteFn = async (
@@ -1,4 +1,4 @@
1
- import { Selectable } from 'kysely'
1
+ import { Insertable, Selectable } from 'kysely'
2
2
  import { CID } from 'multiformats/cid'
3
3
  import { AtUri, normalizeDatetimeAlways } from '@atproto/syntax'
4
4
  import * as lex from '../../../../lexicon/lexicons'
@@ -6,10 +6,12 @@ import * as Repost from '../../../../lexicon/types/app/bsky/feed/repost'
6
6
  import { BackgroundQueue } from '../../background'
7
7
  import { Database } from '../../db'
8
8
  import { DatabaseSchema, DatabaseSchemaType } from '../../db/database-schema'
9
+ import { Notification } from '../../db/tables/notification'
9
10
  import { countAll, excluded } from '../../db/util'
10
11
  import { RecordProcessor } from '../processor'
11
12
 
12
13
  const lexId = lex.ids.AppBskyFeedRepost
14
+ type Notif = Insertable<Notification>
13
15
  type IndexedRepost = Selectable<DatabaseSchemaType['repost']>
14
16
 
15
17
  const insertFn = async (
@@ -25,6 +27,8 @@ const insertFn = async (
25
27
  creator: uri.host,
26
28
  subject: obj.subject.uri,
27
29
  subjectCid: obj.subject.cid,
30
+ via: obj.via?.uri,
31
+ viaCid: obj.via?.cid,
28
32
  createdAt: normalizeDatetimeAlways(obj.createdAt),
29
33
  indexedAt: timestamp,
30
34
  }
@@ -72,20 +76,45 @@ const findDuplicate = async (
72
76
  const notifsForInsert = (obj: IndexedRepost) => {
73
77
  const subjectUri = new AtUri(obj.subject)
74
78
  // prevent self-notifications
75
- const isSelf = subjectUri.host === obj.creator
76
- return isSelf
77
- ? []
78
- : [
79
+ const isRepostFromSubjectUser = subjectUri.host === obj.creator
80
+ if (isRepostFromSubjectUser) {
81
+ return []
82
+ }
83
+
84
+ const notifs: Notif[] = [
85
+ // Notification to the author of the reposted record.
86
+ {
87
+ did: subjectUri.host,
88
+ author: obj.creator,
89
+ recordUri: obj.uri,
90
+ recordCid: obj.cid,
91
+ reason: 'repost' as const,
92
+ reasonSubject: subjectUri.toString(),
93
+ sortAt: obj.sortAt,
94
+ },
95
+ ]
96
+
97
+ if (obj.via) {
98
+ const viaUri = new AtUri(obj.via)
99
+ const isRepostFromViaSubjectUser = viaUri.host === obj.creator
100
+ // prevent self-notifications
101
+ if (!isRepostFromViaSubjectUser) {
102
+ notifs.push(
103
+ // Notification to the reposter via whose repost the repost was made.
79
104
  {
80
- did: subjectUri.host,
105
+ did: viaUri.host,
81
106
  author: obj.creator,
82
107
  recordUri: obj.uri,
83
108
  recordCid: obj.cid,
84
- reason: 'repost' as const,
85
- reasonSubject: subjectUri.toString(),
109
+ reason: 'repost-via-repost' as const,
110
+ reasonSubject: viaUri.toString(),
86
111
  sortAt: obj.sortAt,
87
112
  },
88
- ]
113
+ )
114
+ }
115
+ }
116
+
117
+ return notifs
89
118
  }
90
119
 
91
120
  const deleteFn = async (
@@ -37,6 +37,7 @@ export type PostViewerState = {
37
37
  export type PostViewerStates = HydrationMap<PostViewerState>
38
38
 
39
39
  export type ThreadContext = {
40
+ // Whether the root author has liked the post.
40
41
  like?: string
41
42
  }
42
43
 
@@ -108,8 +108,8 @@ import * as AppBskyFeedGetFeedGenerators from './types/app/bsky/feed/getFeedGene
108
108
  import * as AppBskyFeedGetFeedSkeleton from './types/app/bsky/feed/getFeedSkeleton.js'
109
109
  import * as AppBskyFeedGetLikes from './types/app/bsky/feed/getLikes.js'
110
110
  import * as AppBskyFeedGetListFeed from './types/app/bsky/feed/getListFeed.js'
111
- import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts.js'
112
111
  import * as AppBskyFeedGetPostThread from './types/app/bsky/feed/getPostThread.js'
112
+ import * as AppBskyFeedGetPosts from './types/app/bsky/feed/getPosts.js'
113
113
  import * as AppBskyFeedGetQuotes from './types/app/bsky/feed/getQuotes.js'
114
114
  import * as AppBskyFeedGetRepostedBy from './types/app/bsky/feed/getRepostedBy.js'
115
115
  import * as AppBskyFeedGetSuggestedFeeds from './types/app/bsky/feed/getSuggestedFeeds.js'
@@ -145,6 +145,8 @@ import * as AppBskyNotificationRegisterPush from './types/app/bsky/notification/
145
145
  import * as AppBskyNotificationUpdateSeen from './types/app/bsky/notification/updateSeen.js'
146
146
  import * as AppBskyUnspeccedGetConfig from './types/app/bsky/unspecced/getConfig.js'
147
147
  import * as AppBskyUnspeccedGetPopularFeedGenerators from './types/app/bsky/unspecced/getPopularFeedGenerators.js'
148
+ import * as AppBskyUnspeccedGetPostThreadHiddenV2 from './types/app/bsky/unspecced/getPostThreadHiddenV2.js'
149
+ import * as AppBskyUnspeccedGetPostThreadV2 from './types/app/bsky/unspecced/getPostThreadV2.js'
148
150
  import * as AppBskyUnspeccedGetSuggestedFeeds from './types/app/bsky/unspecced/getSuggestedFeeds.js'
149
151
  import * as AppBskyUnspeccedGetSuggestedFeedsSkeleton from './types/app/bsky/unspecced/getSuggestedFeedsSkeleton.js'
150
152
  import * as AppBskyUnspeccedGetSuggestedStarterPacks from './types/app/bsky/unspecced/getSuggestedStarterPacks.js'
@@ -1497,25 +1499,25 @@ export class AppBskyFeedNS {
1497
1499
  return this._server.xrpc.method(nsid, cfg)
1498
1500
  }
1499
1501
 
1500
- getPosts<AV extends AuthVerifier>(
1502
+ getPostThread<AV extends AuthVerifier>(
1501
1503
  cfg: ConfigOf<
1502
1504
  AV,
1503
- AppBskyFeedGetPosts.Handler<ExtractAuth<AV>>,
1504
- AppBskyFeedGetPosts.HandlerReqCtx<ExtractAuth<AV>>
1505
+ AppBskyFeedGetPostThread.Handler<ExtractAuth<AV>>,
1506
+ AppBskyFeedGetPostThread.HandlerReqCtx<ExtractAuth<AV>>
1505
1507
  >,
1506
1508
  ) {
1507
- const nsid = 'app.bsky.feed.getPosts' // @ts-ignore
1509
+ const nsid = 'app.bsky.feed.getPostThread' // @ts-ignore
1508
1510
  return this._server.xrpc.method(nsid, cfg)
1509
1511
  }
1510
1512
 
1511
- getPostThread<AV extends AuthVerifier>(
1513
+ getPosts<AV extends AuthVerifier>(
1512
1514
  cfg: ConfigOf<
1513
1515
  AV,
1514
- AppBskyFeedGetPostThread.Handler<ExtractAuth<AV>>,
1515
- AppBskyFeedGetPostThread.HandlerReqCtx<ExtractAuth<AV>>
1516
+ AppBskyFeedGetPosts.Handler<ExtractAuth<AV>>,
1517
+ AppBskyFeedGetPosts.HandlerReqCtx<ExtractAuth<AV>>
1516
1518
  >,
1517
1519
  ) {
1518
- const nsid = 'app.bsky.feed.getPostThread' // @ts-ignore
1520
+ const nsid = 'app.bsky.feed.getPosts' // @ts-ignore
1519
1521
  return this._server.xrpc.method(nsid, cfg)
1520
1522
  }
1521
1523
 
@@ -1944,6 +1946,28 @@ export class AppBskyUnspeccedNS {
1944
1946
  return this._server.xrpc.method(nsid, cfg)
1945
1947
  }
1946
1948
 
1949
+ getPostThreadHiddenV2<AV extends AuthVerifier>(
1950
+ cfg: ConfigOf<
1951
+ AV,
1952
+ AppBskyUnspeccedGetPostThreadHiddenV2.Handler<ExtractAuth<AV>>,
1953
+ AppBskyUnspeccedGetPostThreadHiddenV2.HandlerReqCtx<ExtractAuth<AV>>
1954
+ >,
1955
+ ) {
1956
+ const nsid = 'app.bsky.unspecced.getPostThreadHiddenV2' // @ts-ignore
1957
+ return this._server.xrpc.method(nsid, cfg)
1958
+ }
1959
+
1960
+ getPostThreadV2<AV extends AuthVerifier>(
1961
+ cfg: ConfigOf<
1962
+ AV,
1963
+ AppBskyUnspeccedGetPostThreadV2.Handler<ExtractAuth<AV>>,
1964
+ AppBskyUnspeccedGetPostThreadV2.HandlerReqCtx<ExtractAuth<AV>>
1965
+ >,
1966
+ ) {
1967
+ const nsid = 'app.bsky.unspecced.getPostThreadV2' // @ts-ignore
1968
+ return this._server.xrpc.method(nsid, cfg)
1969
+ }
1970
+
1947
1971
  getSuggestedFeeds<AV extends AuthVerifier>(
1948
1972
  cfg: ConfigOf<
1949
1973
  AV,