@recursiv/sdk 0.7.49 → 0.7.51

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.
@@ -1,5 +1,5 @@
1
1
  import type { HttpClient } from '../client.js';
2
- import type { PaginatedResponse, SingleResponse, SuccessResponse, Conversation, ConversationDetail, Message, SendMessageInput, SentMessage, DmInput, DmResult, PaginationParams } from '../types.js';
2
+ import type { PaginatedResponse, SingleResponse, SuccessResponse, Conversation, ConversationDetail, Message, SendMessageInput, SentMessage, DmInput, DmResult, PaginationParams, ConversationRequestResult, LeaveConversationResult } from '../types.js';
3
3
  export declare class ChatResource {
4
4
  private client;
5
5
  constructor(client: HttpClient);
@@ -11,7 +11,14 @@ export declare class ChatResource {
11
11
  communityConversation(communityId: string): Promise<SingleResponse<Conversation>>;
12
12
  /** Get a conversation by ID */
13
13
  conversation(id: string): Promise<SingleResponse<ConversationDetail>>;
14
- /** List messages in a conversation (newest first) */
14
+ /**
15
+ * List messages in a conversation (newest first).
16
+ *
17
+ * For scrolling back, pass the previous page's `meta.next_cursor` as
18
+ * `cursor` rather than growing `offset`: an offset counts from the newest
19
+ * message and shifts every time one arrives, a cursor does not. The cursor
20
+ * is bound to this conversation.
21
+ */
15
22
  messages(conversationId: string, params?: PaginationParams): Promise<PaginatedResponse<Message>>;
16
23
  /** Send a message to a conversation */
17
24
  send(input: SendMessageInput): Promise<SingleResponse<SentMessage>>;
@@ -35,8 +42,31 @@ export declare class ChatResource {
35
42
  name: string;
36
43
  member_ids: string[];
37
44
  }): Promise<SingleResponse<ConversationDetail>>;
38
- /** Delete a conversation (only the creator can delete) */
45
+ /**
46
+ * Delete a conversation for every member. Allowed when the conversation's
47
+ * `can_delete` is true: the caller started it, or every other member is an
48
+ * agent. Otherwise the API answers 403 `not_creator`; use `leave()` where
49
+ * `can_leave` is true.
50
+ */
39
51
  deleteConversation(id: string): Promise<SuccessResponse>;
52
+ /**
53
+ * Remove the caller from a conversation (a group, or a room whose other
54
+ * members are all agents). The last person to leave removes the room. A
55
+ * one-on-one with another person cannot be left (409 `dm_leave_unsupported`);
56
+ * check `can_leave` on the conversation first.
57
+ *
58
+ * This changes membership. It is not `realtime.leaveConversation()`, which
59
+ * only stops listening for live events.
60
+ */
61
+ leave(conversationId: string): Promise<SingleResponse<LeaveConversationResult>>;
62
+ /** Accept a message request (`request_status: 'pending'`). Idempotent; also reverses a decline. */
63
+ acceptRequest(conversationId: string): Promise<SingleResponse<ConversationRequestResult>>;
64
+ /**
65
+ * Decline a message request. The conversation leaves the caller's lists and
66
+ * stops notifying them; the sender is not told. Only a pending request can
67
+ * be declined (409 `not_a_request` otherwise). Idempotent.
68
+ */
69
+ declineRequest(conversationId: string): Promise<SingleResponse<ConversationRequestResult>>;
40
70
  /** React to a message (toggles: adds if not present, removes if already reacted) */
41
71
  reactToMessage(messageId: string, input: {
42
72
  type: string;
@@ -15,7 +15,14 @@ export class ChatResource {
15
15
  conversation(id) {
16
16
  return this.client.get(`/chat/conversations/${id}`);
17
17
  }
18
- /** List messages in a conversation (newest first) */
18
+ /**
19
+ * List messages in a conversation (newest first).
20
+ *
21
+ * For scrolling back, pass the previous page's `meta.next_cursor` as
22
+ * `cursor` rather than growing `offset`: an offset counts from the newest
23
+ * message and shifts every time one arrives, a cursor does not. The cursor
24
+ * is bound to this conversation.
25
+ */
19
26
  messages(conversationId, params) {
20
27
  return this.client.get(`/chat/conversations/${conversationId}/messages`, params);
21
28
  }
@@ -41,10 +48,39 @@ export class ChatResource {
41
48
  createGroup(input) {
42
49
  return this.client.post('/chat/conversations/group', input);
43
50
  }
44
- /** Delete a conversation (only the creator can delete) */
51
+ /**
52
+ * Delete a conversation for every member. Allowed when the conversation's
53
+ * `can_delete` is true: the caller started it, or every other member is an
54
+ * agent. Otherwise the API answers 403 `not_creator`; use `leave()` where
55
+ * `can_leave` is true.
56
+ */
45
57
  deleteConversation(id) {
46
58
  return this.client.delete(`/chat/conversations/${id}`);
47
59
  }
60
+ /**
61
+ * Remove the caller from a conversation (a group, or a room whose other
62
+ * members are all agents). The last person to leave removes the room. A
63
+ * one-on-one with another person cannot be left (409 `dm_leave_unsupported`);
64
+ * check `can_leave` on the conversation first.
65
+ *
66
+ * This changes membership. It is not `realtime.leaveConversation()`, which
67
+ * only stops listening for live events.
68
+ */
69
+ leave(conversationId) {
70
+ return this.client.post(`/chat/conversations/${conversationId}/leave`);
71
+ }
72
+ /** Accept a message request (`request_status: 'pending'`). Idempotent; also reverses a decline. */
73
+ acceptRequest(conversationId) {
74
+ return this.client.post(`/chat/conversations/${conversationId}/accept`);
75
+ }
76
+ /**
77
+ * Decline a message request. The conversation leaves the caller's lists and
78
+ * stops notifying them; the sender is not told. Only a pending request can
79
+ * be declined (409 `not_a_request` otherwise). Idempotent.
80
+ */
81
+ declineRequest(conversationId) {
82
+ return this.client.post(`/chat/conversations/${conversationId}/decline`);
83
+ }
48
84
  /** React to a message (toggles: adds if not present, removes if already reacted) */
49
85
  reactToMessage(messageId, input) {
50
86
  return this.client.post(`/chat/messages/${messageId}/react`, input);
@@ -1,18 +1,30 @@
1
1
  import type { HttpClient } from '../client.js';
2
- import type { Community, CommunityBannedMember, CommunityDetail, CommunityMember, CreateCommunityInput, CreatedCommunity, JoinResult, LeaveResult, ListCommunitiesParams, PaginatedResponse, PaginationParams, SingleResponse } from '../types.js';
2
+ import type { Community, CommunityBannedMember, CommunityCard, CommunityDetail, CommunityMember, CommunityPeopleParams, CreateCommunityInput, CreatedCommunity, JoinResult, LeaveResult, ListCommunitiesParams, PaginatedResponse, PaginationParams, RelatedCommunity, SingleResponse } from '../types.js';
3
3
  export declare class CommunitiesResource {
4
4
  private client;
5
5
  constructor(client: HttpClient);
6
- /** List public communities, or only the authenticated caller's memberships. */
6
+ /**
7
+ * List public communities, or only the authenticated caller's memberships
8
+ * (`member: true`). `q` filters either list by name or description.
9
+ */
7
10
  list(params?: ListCommunitiesParams): Promise<PaginatedResponse<Community>>;
8
- /** Get a community by ID */
9
- get(id: string): Promise<SingleResponse<CommunityDetail>>;
10
- /** List members of a community */
11
- /** Groups related to this one, ranked by shared members; the caller's own groups are left out. */
11
+ /**
12
+ * Search communities by name or description, server-side. Name matches rank
13
+ * first. Pass `{ member: true }` to search only the caller's own groups.
14
+ */
15
+ search(query: string, params?: ListCommunitiesParams): Promise<PaginatedResponse<Community>>;
16
+ /**
17
+ * Get a community by ID or slug. A private group the caller is not in comes
18
+ * back as a `CommunityCard` (`limited: true`) instead of a 404; a hidden one
19
+ * still 404s.
20
+ */
21
+ get(id: string): Promise<SingleResponse<CommunityDetail | CommunityCard>>;
22
+ /** Public groups related to this one, ranked by shared members; each row carries the caller's `is_member`. */
12
23
  related(id: string, params?: {
13
24
  limit?: number;
14
- }): Promise<PaginatedResponse<Community>>;
15
- members(id: string, params?: PaginationParams): Promise<PaginatedResponse<CommunityMember>>;
25
+ }): Promise<PaginatedResponse<RelatedCommunity>>;
26
+ /** List members of a community. `q` searches by name or username. */
27
+ members(id: string, params?: CommunityPeopleParams): Promise<PaginatedResponse<CommunityMember>>;
16
28
  /** Create a new community */
17
29
  create(input: CreateCommunityInput): Promise<SingleResponse<CreatedCommunity>>;
18
30
  /** Join a community */
@@ -28,8 +40,8 @@ export declare class CommunitiesResource {
28
40
  delete(id: string): Promise<SingleResponse<{
29
41
  deleted: boolean;
30
42
  }>>;
31
- /** People waiting to join a private group. Moderator or higher. */
32
- requests(id: string, params?: PaginationParams): Promise<PaginatedResponse<CommunityMember>>;
43
+ /** People waiting to join a private group. Moderator or higher. `q` searches by name or username. */
44
+ requests(id: string, params?: CommunityPeopleParams): Promise<PaginatedResponse<CommunityMember>>;
33
45
  /** Active bans an admin can review and lift. Admin or higher. */
34
46
  bans(id: string, params?: PaginationParams): Promise<PaginatedResponse<CommunityBannedMember>>;
35
47
  /** Let a pending member in. Admin or higher. */
@@ -3,19 +3,33 @@ export class CommunitiesResource {
3
3
  constructor(client) {
4
4
  this.client = client;
5
5
  }
6
- /** List public communities, or only the authenticated caller's memberships. */
6
+ /**
7
+ * List public communities, or only the authenticated caller's memberships
8
+ * (`member: true`). `q` filters either list by name or description.
9
+ */
7
10
  list(params) {
8
11
  return this.client.get('/communities', params);
9
12
  }
10
- /** Get a community by ID */
13
+ /**
14
+ * Search communities by name or description, server-side. Name matches rank
15
+ * first. Pass `{ member: true }` to search only the caller's own groups.
16
+ */
17
+ search(query, params) {
18
+ return this.client.get('/communities', { ...params, q: query });
19
+ }
20
+ /**
21
+ * Get a community by ID or slug. A private group the caller is not in comes
22
+ * back as a `CommunityCard` (`limited: true`) instead of a 404; a hidden one
23
+ * still 404s.
24
+ */
11
25
  get(id) {
12
26
  return this.client.get(`/communities/${id}`);
13
27
  }
14
- /** List members of a community */
15
- /** Groups related to this one, ranked by shared members; the caller's own groups are left out. */
28
+ /** Public groups related to this one, ranked by shared members; each row carries the caller's `is_member`. */
16
29
  related(id, params) {
17
30
  return this.client.get(`/communities/${encodeURIComponent(id)}/related`, params);
18
31
  }
32
+ /** List members of a community. `q` searches by name or username. */
19
33
  members(id, params) {
20
34
  return this.client.get(`/communities/${id}/members`, params);
21
35
  }
@@ -40,7 +54,7 @@ export class CommunitiesResource {
40
54
  return this.client.delete(`/communities/${id}`);
41
55
  }
42
56
  // ── Running the group: the tools an owner, admin or moderator has ────────
43
- /** People waiting to join a private group. Moderator or higher. */
57
+ /** People waiting to join a private group. Moderator or higher. `q` searches by name or username. */
44
58
  requests(id, params) {
45
59
  return this.client.get(`/communities/${id}/requests`, params);
46
60
  }
@@ -116,6 +116,40 @@ export interface CuratorTodaySource {
116
116
  url: string;
117
117
  published_at: string | null;
118
118
  }
119
+ /** One outlet's own words about a world story, quoted with the outlet. */
120
+ export interface CuratorTodayExcerpt {
121
+ outlet: string;
122
+ lane: CuratorOutletLane;
123
+ title: string;
124
+ url: string;
125
+ text: string;
126
+ }
127
+ /** An image a Minds member posted about the story. */
128
+ export interface CuratorTodayLeadImage {
129
+ url: string;
130
+ post_id: string;
131
+ author_name: string | null;
132
+ author_username: string | null;
133
+ }
134
+ /** A post the topic radar counted under the story. Remote posts carry no link to their own network. */
135
+ export interface CuratorTodayReaction {
136
+ cluster_id: string;
137
+ network: 'bluesky' | 'activitypub' | 'nostr' | 'minds';
138
+ text: string;
139
+ published_at: string;
140
+ likes: number;
141
+ reposts: number;
142
+ replies: number;
143
+ /** Minds reactions only: the post to open. */
144
+ post_id?: string;
145
+ }
146
+ /** The topic radar cluster a world story seeded. */
147
+ export interface CuratorTodayRadar {
148
+ cluster_id: string;
149
+ kind: 'breaking' | 'viral' | 'story';
150
+ sources: Partial<Record<'outlet' | 'hackernews' | 'bluesky' | 'activitypub' | 'nostr' | 'minds', number>>;
151
+ reactions: CuratorTodayReaction[];
152
+ }
119
153
  /** Distinct outlets per lane behind a world story. */
120
154
  export interface CuratorTodayLaneMix {
121
155
  mainstream: number;
@@ -152,6 +186,14 @@ export interface CuratorTodayStory {
152
186
  reply_count: number;
153
187
  /** Minds posts in the same shape as `sdk.posts.list()`. May be empty for a world story. */
154
188
  posts: Post[];
189
+ /** World stories only: up to three outlet teasers, one per outlet. */
190
+ excerpts?: CuratorTodayExcerpt[];
191
+ /** World stories only: 'outlet' when the dek is an outlet's sentence, 'editor' when the world editor model wrote it. */
192
+ dek_origin?: 'outlet' | 'editor' | null;
193
+ /** World stories only: the first image among the story's Minds posts. */
194
+ lead_image?: CuratorTodayLeadImage | null;
195
+ /** World stories only: the radar cluster the story seeded, or null. */
196
+ radar?: CuratorTodayRadar | null;
155
197
  }
156
198
  export interface CuratorTodayEdition {
157
199
  id: string;
@@ -47,15 +47,20 @@ export interface PrepareProtocolServersInput {
47
47
  * hostnames must be allow-listed. Default `staging`.
48
48
  */
49
49
  target?: 'staging' | 'production';
50
+ /**
51
+ * `activitypub` is the staging GoToSocial and is required for staging. A
52
+ * production stack is the Bluesky PDS and the Nostr relay only (ActivityPub is
53
+ * Fedify inside the API), and a production request that names it is refused.
54
+ */
50
55
  hosts: {
51
56
  pds: string;
52
- activitypub: string;
57
+ activitypub?: string;
53
58
  nostr: string;
54
59
  };
55
- /** Immutable upstream image references including @sha256 digest. */
60
+ /** Immutable upstream image references including @sha256 digest; `activitypub` as for `hosts`. */
56
61
  images: {
57
62
  pds: string;
58
- activitypub: string;
63
+ activitypub?: string;
59
64
  nostr: string;
60
65
  };
61
66
  /** A staging PLC, or https://plc.directory for a production PDS whose operator set HOSTED_PDS_PRODUCTION_PLC=true. */
@@ -1,5 +1,35 @@
1
1
  import type { HttpClient } from '../client.js';
2
- import type { RegisterTokenInput, SuccessResponse, PaginationParams } from '../types.js';
2
+ import type { RegisterTokenInput, SuccessResponse, SingleResponse, PaginationParams } from '../types.js';
3
+ /** Who did the thing a notification is about. */
4
+ export interface NotificationActor {
5
+ id: string;
6
+ name: string | null;
7
+ username: string | null;
8
+ image: string | null;
9
+ is_ai: boolean | null;
10
+ }
11
+ /**
12
+ * The post a notification references, as it reads NOW, with the viewer's own
13
+ * state so inline Upvote and Repost can start in the right position. `null`
14
+ * when the post is gone or no longer visible to the viewer.
15
+ */
16
+ export interface NotificationPostPreview {
17
+ id: string;
18
+ excerpt: string | null;
19
+ media_url: string | null;
20
+ media_type: string | null;
21
+ reactions_count?: number;
22
+ score?: number;
23
+ upvote_count?: number;
24
+ downvote_count?: number;
25
+ /** The viewer's own reaction on this post ('upvote', 'downvote', ...), if any. */
26
+ user_reaction?: string | null;
27
+ reply_count?: number;
28
+ unique_commenters?: number;
29
+ reposts_count?: number;
30
+ /** Id of the viewer's own repost of this post; delete it to undo the repost. */
31
+ reposted_by_viewer_id?: string | null;
32
+ }
3
33
  export interface Notification {
4
34
  id: string;
5
35
  target_type: string;
@@ -11,8 +41,22 @@ export interface Notification {
11
41
  status: 'unread' | 'read' | 'archived';
12
42
  created_at: string;
13
43
  read_at: string | null;
44
+ /** For `post_reaction` rows: which reaction ('upvote', 'downvote', ...). Null otherwise or on older rows. */
45
+ reaction_type?: string | null;
46
+ actor?: NotificationActor | null;
47
+ post_preview?: NotificationPostPreview | null;
14
48
  }
15
49
  export type NotificationCategory = 'all' | 'social' | 'system';
50
+ export type NotificationScopeParams = {
51
+ /** Which kind of notification to count. Defaults to `all`. Same meaning as in `list`. */
52
+ category?: NotificationCategory;
53
+ /** Scope to a specific organization, as `list` does. */
54
+ organization_id?: string;
55
+ };
56
+ export interface NotificationUnreadCount {
57
+ count: number;
58
+ category: NotificationCategory;
59
+ }
16
60
  export interface ListNotificationsParams extends PaginationParams {
17
61
  status?: 'unread' | 'read' | 'all';
18
62
  cursor?: string;
@@ -22,8 +66,10 @@ export interface ListNotificationsParams extends PaginationParams {
22
66
  * Which kind of notification to return. Defaults to `all`.
23
67
  *
24
68
  * `social` is what a person did to you (follows, replies, reactions,
25
- * reposts, mentions, chat, community invites/joins). `system` is everything
26
- * operational (agent, task, deploy, billing, security).
69
+ * reposts, mentions, community invites, joins and join requests, moderation
70
+ * decisions). `system` is everything operational (agent, task, deploy,
71
+ * billing, security). Direct messages are in neither: they live in the chat
72
+ * inbox. `all` (the default) lists every row that has not been archived.
27
73
  *
28
74
  * Ask for it here rather than filtering the page you get back: the server
29
75
  * applies the limit AFTER the category, so a client that filters afterwards
@@ -43,10 +89,33 @@ export declare class NotificationsResource {
43
89
  constructor(client: HttpClient);
44
90
  /** List notifications for the authenticated user */
45
91
  list(params?: ListNotificationsParams): Promise<NotificationListResponse>;
92
+ /**
93
+ * Count unread notifications in a category, straight from the database.
94
+ * Use this for badges: `list` returns at most 50 rows, so a badge built from
95
+ * a page can only ever say "50+".
96
+ *
97
+ * @example
98
+ * const { data } = await r.notifications.unreadCount({ category: 'social' });
99
+ * setBadge(data.count);
100
+ */
101
+ unreadCount(params?: NotificationScopeParams): Promise<SingleResponse<NotificationUnreadCount>>;
46
102
  /** Mark a single notification as read */
47
103
  markAsRead(notificationId: string): Promise<SuccessResponse>;
48
- /** Mark all notifications as read */
49
- markAllAsRead(category?: NotificationCategory): Promise<SuccessResponse>;
104
+ /**
105
+ * Dismiss a notification (swipe to remove). It stops appearing in `list`
106
+ * and stops counting as unread; the row is kept, not deleted. Dismissing an
107
+ * id that is already dismissed, or not yours, succeeds and changes nothing.
108
+ */
109
+ archive(notificationId: string): Promise<SuccessResponse>;
110
+ /**
111
+ * Mark every unread notification in a scope as read. Pass the same scope the
112
+ * list was read with, so a client only clears what it could show.
113
+ *
114
+ * @example
115
+ * await r.notifications.markAllAsRead('social');
116
+ * await r.notifications.markAllAsRead({ category: 'social', organization_id: orgId });
117
+ */
118
+ markAllAsRead(scope?: NotificationCategory | NotificationScopeParams): Promise<SuccessResponse>;
50
119
  /** Register a push notification token for the current user */
51
120
  registerToken(input: RegisterTokenInput): Promise<SuccessResponse>;
52
121
  /** Unregister a push notification token (e.g., on logout) */
@@ -7,16 +7,46 @@ export class NotificationsResource {
7
7
  list(params) {
8
8
  return this.client.get('/notifications', params);
9
9
  }
10
+ /**
11
+ * Count unread notifications in a category, straight from the database.
12
+ * Use this for badges: `list` returns at most 50 rows, so a badge built from
13
+ * a page can only ever say "50+".
14
+ *
15
+ * @example
16
+ * const { data } = await r.notifications.unreadCount({ category: 'social' });
17
+ * setBadge(data.count);
18
+ */
19
+ unreadCount(params) {
20
+ return this.client.get('/notifications/unread-count', params);
21
+ }
10
22
  /** Mark a single notification as read */
11
23
  markAsRead(notificationId) {
12
- return this.client.post(`/notifications/${notificationId}/read`);
13
- }
14
- /** Mark all notifications as read */
15
- markAllAsRead(category) {
16
- const path = category && category !== 'all'
17
- ? `/notifications/read-all?category=${encodeURIComponent(category)}`
18
- : '/notifications/read-all';
19
- return this.client.post(path);
24
+ return this.client.post(`/notifications/${encodeURIComponent(notificationId)}/read`);
25
+ }
26
+ /**
27
+ * Dismiss a notification (swipe to remove). It stops appearing in `list`
28
+ * and stops counting as unread; the row is kept, not deleted. Dismissing an
29
+ * id that is already dismissed, or not yours, succeeds and changes nothing.
30
+ */
31
+ archive(notificationId) {
32
+ return this.client.post(`/notifications/${encodeURIComponent(notificationId)}/archive`);
33
+ }
34
+ /**
35
+ * Mark every unread notification in a scope as read. Pass the same scope the
36
+ * list was read with, so a client only clears what it could show.
37
+ *
38
+ * @example
39
+ * await r.notifications.markAllAsRead('social');
40
+ * await r.notifications.markAllAsRead({ category: 'social', organization_id: orgId });
41
+ */
42
+ markAllAsRead(scope) {
43
+ const params = typeof scope === 'string' ? { category: scope } : scope ?? {};
44
+ const query = [];
45
+ if (params.category && params.category !== 'all')
46
+ query.push(`category=${encodeURIComponent(params.category)}`);
47
+ if (params.organization_id)
48
+ query.push(`organization_id=${encodeURIComponent(params.organization_id)}`);
49
+ return this.client.post(query.length ? `/notifications/read-all?${query.join('&')}` : '/notifications/read-all');
20
50
  }
21
51
  /** Register a push notification token for the current user */
22
52
  registerToken(input) {
@@ -1,5 +1,5 @@
1
1
  import type { HttpClient } from '../client.js';
2
- import type { PaginatedResponse, SingleResponse, DeleteResponse, Post, PostDetail, CreatePostInput, CreatedPost, UpdatePostInput, ListPostsParams, SearchPostsParams, ReactionType } from '../types.js';
2
+ import type { PaginatedResponse, SingleResponse, DeleteResponse, Post, PostDetail, CreatePostInput, CreatedPost, UpdatePostInput, ListPostsParams, ListPostRepliesParams, PostRepliesPage, SearchPostsParams, ReactionType } from '../types.js';
3
3
  export declare class PostsResource {
4
4
  private client;
5
5
  constructor(client: HttpClient);
@@ -17,8 +17,10 @@ export declare class PostsResource {
17
17
  limit?: number;
18
18
  organization_id?: string;
19
19
  }): Promise<PaginatedResponse<Post>>;
20
- /** Get a single post with replies */
20
+ /** Get a single post with its newest replies; `replies_next_cursor` is set when the thread continues. */
21
21
  get(id: string): Promise<SingleResponse<PostDetail>>;
22
+ /** One page of a post's replies, newest first. Start from `replies_next_cursor` on `get`, then follow `meta.next_cursor`. */
23
+ replies(id: string, params?: ListPostRepliesParams): Promise<PostRepliesPage>;
22
24
  /** Create a new post */
23
25
  create(input: CreatePostInput): Promise<SingleResponse<CreatedPost>>;
24
26
  /** Update a post's content or tags */
@@ -19,10 +19,14 @@ export class PostsResource {
19
19
  similar(id, params) {
20
20
  return this.client.get(`/posts/${encodeURIComponent(id)}/similar`, params);
21
21
  }
22
- /** Get a single post with replies */
22
+ /** Get a single post with its newest replies; `replies_next_cursor` is set when the thread continues. */
23
23
  get(id) {
24
24
  return this.client.get(`/posts/${id}`);
25
25
  }
26
+ /** One page of a post's replies, newest first. Start from `replies_next_cursor` on `get`, then follow `meta.next_cursor`. */
27
+ replies(id, params) {
28
+ return this.client.get(`/posts/${encodeURIComponent(id)}/replies`, params ? { limit: params.limit, cursor: params.cursor } : undefined);
29
+ }
26
30
  /** Create a new post */
27
31
  create(input) {
28
32
  return this.client.post('/posts', input);
@@ -1,5 +1,5 @@
1
1
  import type { HttpClient } from '../client.js';
2
- import type { PaginatedResponse, SingleResponse, SuccessResponse, Profile, ProfileDetail, ProfileMe, LeaderboardEntry, UpdateProfileInput, SearchProfilesParams } from '../types.js';
2
+ import type { PaginatedResponse, SingleResponse, SuccessResponse, Profile, ProfileDetail, ProfileMe, LeaderboardEntry, UpdateProfileInput, SearchProfilesParams, SearchMentionsParams, MentionCandidate, FollowListProfile, BlockedProfile, MutedProfile, ModerationListParams, ViewerRelationship } from '../types.js';
3
3
  export declare class ProfilesResource {
4
4
  private client;
5
5
  constructor(client: HttpClient);
@@ -16,26 +16,62 @@ export declare class ProfilesResource {
16
16
  getByUsername(username: string): Promise<SingleResponse<ProfileDetail>>;
17
17
  /** Search users by name or username */
18
18
  search(params: SearchProfilesParams): Promise<PaginatedResponse<Profile>>;
19
+ /**
20
+ * Accounts to @mention: people and agents on the caller's network, the
21
+ * caller's follows first. Unlike `search`, this includes agents the app may
22
+ * discover (an agent answers when mentioned); another member's personal AI
23
+ * is never offered.
24
+ */
25
+ mentions(params: SearchMentionsParams): Promise<PaginatedResponse<MentionCandidate>>;
19
26
  /** Update own profile */
20
27
  update(input: UpdateProfileInput): Promise<SingleResponse<Profile>>;
21
28
  /** Follow a user */
22
29
  follow(userId: string): Promise<SuccessResponse>;
23
30
  /** Unfollow a user */
24
31
  unfollow(userId: string): Promise<SuccessResponse>;
25
- /** List a user's followers */
32
+ /**
33
+ * List a user's followers. Each row carries the caller's relationship with
34
+ * it (`is_following`, `follows_you`), so a Follow button needs no second read.
35
+ */
26
36
  followers(userId: string, params?: {
27
37
  limit?: number;
28
38
  offset?: number;
29
- }): Promise<PaginatedResponse<Profile>>;
30
- /** List who a user follows */
39
+ }): Promise<PaginatedResponse<FollowListProfile>>;
40
+ /** List who a user follows, each row with the caller's relationship with it. */
31
41
  following(userId: string, params?: {
32
42
  limit?: number;
33
43
  offset?: number;
34
- }): Promise<PaginatedResponse<Profile>>;
35
- /** Check if current user follows another user */
36
- isFollowing(userId: string): Promise<SingleResponse<{
37
- is_following: boolean;
38
- }>>;
44
+ }): Promise<PaginatedResponse<FollowListProfile>>;
45
+ /**
46
+ * The caller's whole follow set as ids, up to 5000 per page (default 1000).
47
+ * Answers what `isFollowing` answers, for every account at once. Pass
48
+ * `meta.next_cursor` as `cursor` until it is null.
49
+ */
50
+ followingIds(params?: {
51
+ cursor?: string;
52
+ limit?: number;
53
+ }): Promise<PaginatedResponse<string>>;
54
+ /** The follow relationship with another user in both directions (mutual when both are true). */
55
+ isFollowing(userId: string): Promise<SingleResponse<ViewerRelationship>>;
56
+ /**
57
+ * Block a user. A block is a two-way wall: it severs follows in both
58
+ * directions and hides each side's posts from the other.
59
+ */
60
+ block(userId: string): Promise<SuccessResponse>;
61
+ /** Remove a block. Follows severed by the block are not restored. */
62
+ unblock(userId: string): Promise<SuccessResponse>;
63
+ /** The users the caller has blocked, newest first. `search` matches name or username. */
64
+ blocked(params?: ModerationListParams): Promise<PaginatedResponse<BlockedProfile>>;
65
+ /**
66
+ * Mute a user. One-directional: the server stops showing their posts (and
67
+ * reposts of them) in the caller's feeds and stops notifying the caller about
68
+ * them. Their profile and direct links stay reachable, and they are not told.
69
+ */
70
+ mute(userId: string): Promise<SuccessResponse>;
71
+ /** Remove a mute. */
72
+ unmute(userId: string): Promise<SuccessResponse>;
73
+ /** The users the caller has muted, newest first. `search` matches name or username. */
74
+ muted(params?: ModerationListParams): Promise<PaginatedResponse<MutedProfile>>;
39
75
  /**
40
76
  * Channels related to a profile, ranked by co-follow: accounts that the
41
77
  * profile's followees also follow. Suggestion list, so the caller's own
@@ -23,6 +23,15 @@ export class ProfilesResource {
23
23
  search(params) {
24
24
  return this.client.get('/profiles/search', params);
25
25
  }
26
+ /**
27
+ * Accounts to @mention: people and agents on the caller's network, the
28
+ * caller's follows first. Unlike `search`, this includes agents the app may
29
+ * discover (an agent answers when mentioned); another member's personal AI
30
+ * is never offered.
31
+ */
32
+ mentions(params) {
33
+ return this.client.get('/profiles/mentions', params);
34
+ }
26
35
  /** Update own profile */
27
36
  update(input) {
28
37
  return this.client.put('/profiles/me', input);
@@ -35,18 +44,60 @@ export class ProfilesResource {
35
44
  unfollow(userId) {
36
45
  return this.client.delete(`/profiles/${userId}/follow`);
37
46
  }
38
- /** List a user's followers */
47
+ /**
48
+ * List a user's followers. Each row carries the caller's relationship with
49
+ * it (`is_following`, `follows_you`), so a Follow button needs no second read.
50
+ */
39
51
  followers(userId, params) {
40
52
  return this.client.get(`/profiles/${userId}/followers`, params);
41
53
  }
42
- /** List who a user follows */
54
+ /** List who a user follows, each row with the caller's relationship with it. */
43
55
  following(userId, params) {
44
56
  return this.client.get(`/profiles/${userId}/following`, params);
45
57
  }
46
- /** Check if current user follows another user */
58
+ /**
59
+ * The caller's whole follow set as ids, up to 5000 per page (default 1000).
60
+ * Answers what `isFollowing` answers, for every account at once. Pass
61
+ * `meta.next_cursor` as `cursor` until it is null.
62
+ */
63
+ followingIds(params) {
64
+ return this.client.get('/profiles/me/following/ids', params);
65
+ }
66
+ /** The follow relationship with another user in both directions (mutual when both are true). */
47
67
  isFollowing(userId) {
48
68
  return this.client.get(`/profiles/${userId}/is-following`);
49
69
  }
70
+ /**
71
+ * Block a user. A block is a two-way wall: it severs follows in both
72
+ * directions and hides each side's posts from the other.
73
+ */
74
+ block(userId) {
75
+ return this.client.post(`/profiles/${encodeURIComponent(userId)}/block`);
76
+ }
77
+ /** Remove a block. Follows severed by the block are not restored. */
78
+ unblock(userId) {
79
+ return this.client.delete(`/profiles/${encodeURIComponent(userId)}/block`);
80
+ }
81
+ /** The users the caller has blocked, newest first. `search` matches name or username. */
82
+ blocked(params) {
83
+ return this.client.get('/profiles/blocked', params);
84
+ }
85
+ /**
86
+ * Mute a user. One-directional: the server stops showing their posts (and
87
+ * reposts of them) in the caller's feeds and stops notifying the caller about
88
+ * them. Their profile and direct links stay reachable, and they are not told.
89
+ */
90
+ mute(userId) {
91
+ return this.client.post(`/profiles/${encodeURIComponent(userId)}/mute`);
92
+ }
93
+ /** Remove a mute. */
94
+ unmute(userId) {
95
+ return this.client.delete(`/profiles/${encodeURIComponent(userId)}/mute`);
96
+ }
97
+ /** The users the caller has muted, newest first. `search` matches name or username. */
98
+ muted(params) {
99
+ return this.client.get('/profiles/muted', params);
100
+ }
50
101
  /**
51
102
  * Channels related to a profile, ranked by co-follow: accounts that the
52
103
  * profile's followees also follow. Suggestion list, so the caller's own