@recursiv/sdk 0.7.50 → 0.7.52
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.
- package/README.md +69 -12
- package/dist/client.js +3 -1
- package/dist/index.d.ts +13 -6
- package/dist/index.js +5 -1
- package/dist/realtime.d.ts +79 -9
- package/dist/realtime.js +339 -76
- package/dist/resources/admin.d.ts +13 -0
- package/dist/resources/agents.d.ts +41 -4
- package/dist/resources/agents.js +45 -24
- package/dist/resources/app-subscriptions.d.ts +102 -4
- package/dist/resources/app-subscriptions.js +43 -3
- package/dist/resources/auth.d.ts +198 -2
- package/dist/resources/auth.js +397 -3
- package/dist/resources/boosts.d.ts +170 -0
- package/dist/resources/boosts.js +75 -0
- package/dist/resources/chat.d.ts +33 -3
- package/dist/resources/chat.js +38 -2
- package/dist/resources/communities.d.ts +23 -11
- package/dist/resources/communities.js +20 -6
- package/dist/resources/curator.d.ts +24 -6
- package/dist/resources/curator.js +2 -1
- package/dist/resources/deployments.d.ts +8 -3
- package/dist/resources/discovery.d.ts +15 -1
- package/dist/resources/discovery.js +29 -1
- package/dist/resources/invite-codes-admin.d.ts +13 -0
- package/dist/resources/invite-codes.d.ts +10 -0
- package/dist/resources/invite-codes.js +6 -6
- package/dist/resources/notifications.d.ts +74 -5
- package/dist/resources/notifications.js +38 -8
- package/dist/resources/posts.d.ts +28 -5
- package/dist/resources/posts.js +13 -4
- package/dist/resources/profiles.d.ts +45 -9
- package/dist/resources/profiles.js +54 -3
- package/dist/resources/protocols.d.ts +195 -14
- package/dist/resources/protocols.js +77 -12
- package/dist/resources/settings.d.ts +25 -3
- package/dist/resources/settings.js +28 -2
- package/dist/resources/video.d.ts +19 -0
- package/dist/resources/video.js +8 -0
- package/dist/resources/wallet.d.ts +41 -1
- package/dist/resources/wallet.js +8 -0
- package/dist/types.d.ts +217 -6
- package/llm.md +68 -20
- package/package.json +2 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boost: pay to promote your own post into the For You feed. CPM campaigns
|
|
3
|
+
* funded from a prepaid balance with an append-only ledger. Top-ups run on the
|
|
4
|
+
* app's own Stripe account and need a project-scoped key.
|
|
5
|
+
*/
|
|
6
|
+
export class BoostsResource {
|
|
7
|
+
client;
|
|
8
|
+
constructor(client) {
|
|
9
|
+
this.client = client;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a campaign for one of your own posts. Debits `budget_micros` from your balance
|
|
13
|
+
* (402 `insufficient_balance` when it cannot). Starts `pending` review.
|
|
14
|
+
* Not retried automatically, so a slow response cannot fund two campaigns.
|
|
15
|
+
*/
|
|
16
|
+
create(input) {
|
|
17
|
+
return this.client.post('/boosts', input, { retry: false });
|
|
18
|
+
}
|
|
19
|
+
/** Your campaigns, newest first, with spend and impressions. */
|
|
20
|
+
mine(params) {
|
|
21
|
+
return this.client.get('/boosts/mine', params);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Your balance, recent ledger, the CPM floor, the top-up limits, and the boost credit your
|
|
25
|
+
* plan on this app adds each paid period (`meta.plan_credit`, a `grant` ledger row per period).
|
|
26
|
+
*/
|
|
27
|
+
balance() {
|
|
28
|
+
return this.client.get('/boosts/balance');
|
|
29
|
+
}
|
|
30
|
+
/** Pause one of your active campaigns. */
|
|
31
|
+
pause(campaignId) {
|
|
32
|
+
return this.client.post(`/boosts/${encodeURIComponent(campaignId)}/pause`, {});
|
|
33
|
+
}
|
|
34
|
+
/** Resume one of your paused campaigns. */
|
|
35
|
+
resume(campaignId) {
|
|
36
|
+
return this.client.post(`/boosts/${encodeURIComponent(campaignId)}/resume`, {});
|
|
37
|
+
}
|
|
38
|
+
/** Cancel a campaign and refund its unspent budget to your balance (`meta.refunded_micros`). */
|
|
39
|
+
cancel(campaignId) {
|
|
40
|
+
return this.client.post(`/boosts/${encodeURIComponent(campaignId)}/cancel`, {});
|
|
41
|
+
}
|
|
42
|
+
/** Report an impression or click on a boosted feed entry. Idempotent per viewer per UTC day. */
|
|
43
|
+
recordEvent(campaignId, kind) {
|
|
44
|
+
return this.client.post(`/boosts/${encodeURIComponent(campaignId)}/events`, { kind });
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Buy boost credit: opens a one-time Stripe Checkout for `amount_cents` (USD) on the app's
|
|
48
|
+
* own Stripe account. The balance is credited once the payment succeeds. Limits are in
|
|
49
|
+
* `balance().meta.topup`. Requires a project-scoped key with `billing:write`.
|
|
50
|
+
* `return_url` keeps its own query and fragment; `topup=success&session_id=<id>` or
|
|
51
|
+
* `topup=cancelled` is added to its query (to the fragment's query for a hash route).
|
|
52
|
+
*/
|
|
53
|
+
topup(input) {
|
|
54
|
+
return this.client.post('/boosts/topup', input, { retry: false });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Credit a paid top-up when the member returns from Checkout. Safe to call repeatedly
|
|
58
|
+
* and alongside the webhook: a session credits the balance once.
|
|
59
|
+
*/
|
|
60
|
+
confirmTopup(sessionId) {
|
|
61
|
+
return this.client.post('/boosts/topup/confirm', { session_id: sessionId });
|
|
62
|
+
}
|
|
63
|
+
/** Campaigns waiting for review, oldest first (admin). */
|
|
64
|
+
listPendingReview(params) {
|
|
65
|
+
return this.client.get('/boosts/review', params);
|
|
66
|
+
}
|
|
67
|
+
/** Approve or reject a campaign (admin). Rejecting refunds the unspent budget. */
|
|
68
|
+
review(campaignId, input) {
|
|
69
|
+
return this.client.post(`/boosts/review/${encodeURIComponent(campaignId)}`, input);
|
|
70
|
+
}
|
|
71
|
+
/** Grant balance to a user (admin). */
|
|
72
|
+
grant(input) {
|
|
73
|
+
return this.client.post('/boosts/grant', input, { retry: false });
|
|
74
|
+
}
|
|
75
|
+
}
|
package/dist/resources/chat.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
-
/**
|
|
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;
|
package/dist/resources/chat.js
CHANGED
|
@@ -15,7 +15,14 @@ export class ChatResource {
|
|
|
15
15
|
conversation(id) {
|
|
16
16
|
return this.client.get(`/chat/conversations/${id}`);
|
|
17
17
|
}
|
|
18
|
-
/**
|
|
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
|
-
/**
|
|
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,19 +1,31 @@
|
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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<
|
|
15
|
-
members
|
|
16
|
-
|
|
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>>;
|
|
28
|
+
/** Create a new community. Omit slug for a server-generated collision-resistant slug. */
|
|
17
29
|
create(input: CreateCommunityInput): Promise<SingleResponse<CreatedCommunity>>;
|
|
18
30
|
/** Join a community */
|
|
19
31
|
join(id: string): Promise<SingleResponse<JoinResult>>;
|
|
@@ -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?:
|
|
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,23 +3,37 @@ export class CommunitiesResource {
|
|
|
3
3
|
constructor(client) {
|
|
4
4
|
this.client = client;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
}
|
|
22
|
-
/** Create a new community */
|
|
36
|
+
/** Create a new community. Omit slug for a server-generated collision-resistant slug. */
|
|
23
37
|
create(input) {
|
|
24
38
|
return this.client.post('/communities', input);
|
|
25
39
|
}
|
|
@@ -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
|
}
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import type { HttpClient } from '../client.js';
|
|
2
|
-
import type { PaginatedResponse, Post, SingleResponse } from '../types.js';
|
|
2
|
+
import type { DiscoveryLayout, PaginatedResponse, PaginationMeta, Post, SingleResponse } from '../types.js';
|
|
3
|
+
/** Which surface is asking: Home's For You (default) or Discover's For you. */
|
|
4
|
+
export type ForYouSurface = 'home' | 'discover';
|
|
5
|
+
export type ForYouParams = {
|
|
6
|
+
limit?: number;
|
|
7
|
+
offset?: number;
|
|
8
|
+
/** The previous page's `meta.next_cursor`: pages a stored ranking, so posts read meanwhile never shift the next page. */
|
|
9
|
+
cursor?: string;
|
|
10
|
+
/** Adds `meta.discovery` (layouts) and the public safety floor; limit <= 25. */
|
|
11
|
+
discovery?: boolean;
|
|
12
|
+
/** `discover` ranks for Discover: fresher, beyond the member's follows, with their category order. */
|
|
13
|
+
surface?: ForYouSurface;
|
|
14
|
+
};
|
|
15
|
+
export interface ForYouMeta extends PaginationMeta {
|
|
16
|
+
discovery?: DiscoveryLayout;
|
|
17
|
+
next_cursor?: string;
|
|
18
|
+
/** Whether the ranker can personalize for this member yet (3 follows or 3 upvoted authors). */
|
|
19
|
+
personalized?: boolean;
|
|
20
|
+
}
|
|
3
21
|
/** RSS / Atom source. Default — `type` may be omitted for back-compat. */
|
|
4
22
|
export interface CuratorRssSource {
|
|
5
23
|
type?: 'rss';
|
|
@@ -250,10 +268,10 @@ export declare class CuratorResource {
|
|
|
250
268
|
* existing posts for the signed-in user (engagement + recency + social +
|
|
251
269
|
* affinity, no model calls). Returns posts in the same shape as
|
|
252
270
|
* `sdk.posts.list()`, so any feed UI renders it unchanged. Requires a
|
|
253
|
-
* project-scoped key (the feed is per-app).
|
|
271
|
+
* project-scoped key (the feed is per-app). Servers that predate `cursor`,
|
|
272
|
+
* `discovery` and `surface` ignore them.
|
|
254
273
|
*/
|
|
255
|
-
forYou(params?: {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}): Promise<PaginatedResponse<Post>>;
|
|
274
|
+
forYou(params?: ForYouParams): Promise<PaginatedResponse<Post> & {
|
|
275
|
+
meta: ForYouMeta;
|
|
276
|
+
}>;
|
|
259
277
|
}
|
|
@@ -47,7 +47,8 @@ export class CuratorResource {
|
|
|
47
47
|
* existing posts for the signed-in user (engagement + recency + social +
|
|
48
48
|
* affinity, no model calls). Returns posts in the same shape as
|
|
49
49
|
* `sdk.posts.list()`, so any feed UI renders it unchanged. Requires a
|
|
50
|
-
* project-scoped key (the feed is per-app).
|
|
50
|
+
* project-scoped key (the feed is per-app). Servers that predate `cursor`,
|
|
51
|
+
* `discovery` and `surface` ignore them.
|
|
51
52
|
*/
|
|
52
53
|
forYou(params = {}) {
|
|
53
54
|
return this.client.get('/curator/foryou', params);
|
|
@@ -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
|
|
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
|
|
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,4 +1,5 @@
|
|
|
1
1
|
import type { DiscoveryLayout, Post } from '../types.js';
|
|
2
|
+
import type { CuratorResource } from './curator.js';
|
|
2
3
|
import type { DiscoveryLearning } from './discovery-learning.js';
|
|
3
4
|
import type { PostsResource } from './posts.js';
|
|
4
5
|
import type { ProtocolsResource, SocialNetwork, SocialPost, SocialRadar, SocialRadarPosts } from './protocols.js';
|
|
@@ -201,7 +202,20 @@ export declare class DiscoveryFeedSession {
|
|
|
201
202
|
export declare class DiscoveryResource {
|
|
202
203
|
private posts;
|
|
203
204
|
private protocols;
|
|
204
|
-
|
|
205
|
+
private curator?;
|
|
206
|
+
constructor(posts: PostsResource, protocols: ProtocolsResource, curator?: Pick<CuratorResource, "forYou"> | undefined);
|
|
207
|
+
/**
|
|
208
|
+
* A For you Discover feed: the member's For You ranking (asked for Discover's surface, with layouts and a
|
|
209
|
+
* snapshot cursor) in a session's Minds slot. With a category, the session also reads open-network posts
|
|
210
|
+
* from that category (the member's top one); without, it is Minds only. Never the radar. The page-0
|
|
211
|
+
* arrangement and when to use which are the app's choice.
|
|
212
|
+
*/
|
|
213
|
+
createPersonalFeed(options: {
|
|
214
|
+
networks: SocialNetwork[];
|
|
215
|
+
learning?: DiscoveryLearning;
|
|
216
|
+
recommend?: DiscoveryRecommendationSources;
|
|
217
|
+
category?: string;
|
|
218
|
+
}): DiscoveryFeedSession;
|
|
205
219
|
createFeed(options: {
|
|
206
220
|
networks: SocialNetwork[];
|
|
207
221
|
category?: string;
|
|
@@ -160,6 +160,9 @@ export class DiscoveryFeedSession {
|
|
|
160
160
|
return this.pending;
|
|
161
161
|
}
|
|
162
162
|
async read(stream) {
|
|
163
|
+
// `discovery` asks only for the layout judgment (and, for Minds posts, the public-only floor). The
|
|
164
|
+
// server's safety floor does not depend on it, so a reader that drops it to skip layout work (a clip
|
|
165
|
+
// pool) is screened exactly like this session.
|
|
163
166
|
const params = { limit: 25, ...(this.category ? { category: this.category } : {}), discovery: true };
|
|
164
167
|
if (stream.protocol === 'minds') {
|
|
165
168
|
// Discover leads with what is moving now: the REST hot order (engagement
|
|
@@ -462,9 +465,34 @@ export class DiscoveryFeedSession {
|
|
|
462
465
|
export class DiscoveryResource {
|
|
463
466
|
posts;
|
|
464
467
|
protocols;
|
|
465
|
-
|
|
468
|
+
curator;
|
|
469
|
+
constructor(posts, protocols, curator) {
|
|
466
470
|
this.posts = posts;
|
|
467
471
|
this.protocols = protocols;
|
|
472
|
+
this.curator = curator;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* A For you Discover feed: the member's For You ranking (asked for Discover's surface, with layouts and a
|
|
476
|
+
* snapshot cursor) in a session's Minds slot. With a category, the session also reads open-network posts
|
|
477
|
+
* from that category (the member's top one); without, it is Minds only. Never the radar. The page-0
|
|
478
|
+
* arrangement and when to use which are the app's choice.
|
|
479
|
+
*/
|
|
480
|
+
createPersonalFeed(options) {
|
|
481
|
+
const curator = this.curator;
|
|
482
|
+
if (!curator)
|
|
483
|
+
throw new Error('createPersonalFeed needs the curator resource');
|
|
484
|
+
const list = {
|
|
485
|
+
// The session's `sort` and `category` are Discover's hot-order knobs; the ranker ignores them.
|
|
486
|
+
list: async (params) => {
|
|
487
|
+
const response = await curator.forYou({ limit: params?.limit, offset: params?.offset, cursor: params?.cursor, discovery: true, surface: 'discover' });
|
|
488
|
+
// A server that predates the cursor says has_more: false on a partial ranked page although its
|
|
489
|
+
// continuation serves the next offset. A cursor-aware server always says `personalized`, and its
|
|
490
|
+
// has_more is the end of the feed.
|
|
491
|
+
const legacy = typeof response.meta.personalized !== 'boolean';
|
|
492
|
+
return { ...response, meta: { ...response.meta, has_more: response.meta.has_more || (legacy && response.data.length > 0) } };
|
|
493
|
+
},
|
|
494
|
+
};
|
|
495
|
+
return new DiscoveryFeedSession(list, this.protocols, options.category ? options.networks : [], options.category, options.category ? 'all' : 'minds', options.learning, options.recommend);
|
|
468
496
|
}
|
|
469
497
|
createFeed(options) {
|
|
470
498
|
// The radar rides along by default; an older server answers 404 and the session simply shows no story module.
|
|
@@ -18,12 +18,25 @@ export interface InviteCodeStats {
|
|
|
18
18
|
used: number;
|
|
19
19
|
expired: number;
|
|
20
20
|
revoked: number;
|
|
21
|
+
/** @deprecated Use `total`. */
|
|
22
|
+
total_codes: number;
|
|
23
|
+
/** @deprecated Use `active`. */
|
|
24
|
+
active_codes: number;
|
|
25
|
+
/** @deprecated Use `used`. */
|
|
26
|
+
used_codes: number;
|
|
27
|
+
/** @deprecated Use `expired`. */
|
|
28
|
+
expired_codes: number;
|
|
29
|
+
/** @deprecated Use `revoked`. */
|
|
30
|
+
revoked_codes: number;
|
|
21
31
|
};
|
|
22
32
|
waitlist: Record<string, number>;
|
|
23
33
|
current_wave: {
|
|
24
34
|
id: string;
|
|
25
35
|
wave: number;
|
|
26
36
|
name: string;
|
|
37
|
+
max_codes: number;
|
|
38
|
+
invites_per_user: number;
|
|
39
|
+
reward_tokens: number;
|
|
27
40
|
is_active: boolean;
|
|
28
41
|
} | null;
|
|
29
42
|
}
|
|
@@ -90,10 +90,20 @@ export interface BulkGenerateResult {
|
|
|
90
90
|
}
|
|
91
91
|
export interface InviteStats {
|
|
92
92
|
codes: {
|
|
93
|
+
total: number;
|
|
94
|
+
active: number;
|
|
95
|
+
used: number;
|
|
96
|
+
expired: number;
|
|
97
|
+
revoked: number;
|
|
98
|
+
/** @deprecated Use `total`. Retained for legacy admin clients. */
|
|
93
99
|
total_codes: number;
|
|
100
|
+
/** @deprecated Use `active`. Retained for legacy admin clients. */
|
|
94
101
|
active_codes: number;
|
|
102
|
+
/** @deprecated Use `used`. Retained for legacy admin clients. */
|
|
95
103
|
used_codes: number;
|
|
104
|
+
/** @deprecated Use `expired`. Retained for legacy admin clients. */
|
|
96
105
|
expired_codes: number;
|
|
106
|
+
/** @deprecated Use `revoked`. Retained for legacy admin clients. */
|
|
97
107
|
revoked_codes: number;
|
|
98
108
|
};
|
|
99
109
|
waitlist: Record<string, number>;
|
|
@@ -43,26 +43,26 @@ export class InviteCodesResource {
|
|
|
43
43
|
// ── Admin Methods ──
|
|
44
44
|
/** Admin: Initialize wave configs for the network */
|
|
45
45
|
initializeWaves() {
|
|
46
|
-
return this.client.post('/invite-codes
|
|
46
|
+
return this.client.post('/invite-codes-admin/waves/initialize');
|
|
47
47
|
}
|
|
48
48
|
/** Admin: Get all wave configs */
|
|
49
49
|
getWaves() {
|
|
50
|
-
return this.client.get('/invite-codes
|
|
50
|
+
return this.client.get('/invite-codes-admin/waves');
|
|
51
51
|
}
|
|
52
52
|
/** Admin: Activate a specific wave */
|
|
53
53
|
activateWave(wave) {
|
|
54
|
-
return this.client.post('/invite-codes
|
|
54
|
+
return this.client.post('/invite-codes-admin/waves/activate', { wave });
|
|
55
55
|
}
|
|
56
56
|
/** Admin: Bulk generate invite codes */
|
|
57
57
|
bulkGenerate(input) {
|
|
58
|
-
return this.client.post('/invite-codes
|
|
58
|
+
return this.client.post('/invite-codes-admin/bulk-generate', input);
|
|
59
59
|
}
|
|
60
60
|
/** Admin: Get invite system stats */
|
|
61
61
|
getStats() {
|
|
62
|
-
return this.client.get('/invite-codes
|
|
62
|
+
return this.client.get('/invite-codes-admin/stats');
|
|
63
63
|
}
|
|
64
64
|
/** Admin: Get waitlist entries */
|
|
65
65
|
getWaitlist(params) {
|
|
66
|
-
return this.client.get('/invite-codes
|
|
66
|
+
return this.client.get('/invite-codes-admin/waitlist', params);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -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,
|
|
26
|
-
* operational (agent, task, deploy,
|
|
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
|
-
/**
|
|
49
|
-
|
|
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) */
|