@recursiv/sdk 0.7.65 → 0.7.66
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 +19 -0
- package/dist/index.d.ts +1 -1
- package/dist/resources/curator.d.ts +163 -1
- package/dist/resources/curator.js +9 -0
- package/dist/resources/profiles.d.ts +4 -1
- package/dist/resources/profiles.js +4 -1
- package/dist/resources/protocols.d.ts +4 -5
- package/llm.md +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -670,6 +670,25 @@ and says whether the member is personalized yet (`meta.personalized`). With a
|
|
|
670
670
|
`category` (the member's first), the session also reads open-network posts from it;
|
|
671
671
|
without, it is Minds only. It never carries the radar.
|
|
672
672
|
|
|
673
|
+
### For You: the world by the member's interests
|
|
674
|
+
|
|
675
|
+
`sdk.curator.forYouWorld({ part?, session?, snapshot?, compass? })` reads the For You overview
|
|
676
|
+
for the signed-in member, with their own key of the app. `stories` are world stories (Today,
|
|
677
|
+
the radar and the viral read) matched to the member's interests with breadth: at least four
|
|
678
|
+
themes and two breaking or general stories in the first eight, at most two per theme, and a
|
|
679
|
+
story shown three times without an open rests for a week. `items` are the member's For You
|
|
680
|
+
picks interleaved with the most engaging posts of their top interests (half or more on their
|
|
681
|
+
interests, no interest over 40%, videos weighted up), and `blocks` lay the page out like All:
|
|
682
|
+
`stories`, `lead_video`, `clips`, `posts`, `people`, `groups`, `topics`, `viral` and
|
|
683
|
+
`categories`, never the same type twice in a row, each naming the refs its views should send.
|
|
684
|
+
Every story and item carries `reasons` (`interest:<category>`, `followed:@<handle>`, `breaking`,
|
|
685
|
+
`general`, `for_you`, `engaging`, `breadth`). `part: 'stories'` and `part: 'items'` read the
|
|
686
|
+
two halves on their own, so an app can draw each as it lands; a part=items answer keeps the
|
|
687
|
+
stories rail as a `deferred` block. `meta.interests` are category ids for chips (never put them
|
|
688
|
+
in a URL), `meta.partial` names a source that missed its deadline, and `meta.foryou_cursor`
|
|
689
|
+
continues the same ranking with `curator.forYou({ cursor })`. 404 while the app's operator has
|
|
690
|
+
it off; a 503 `for_you_world_unavailable` carries Retry-After.
|
|
691
|
+
|
|
673
692
|
### The top of a feed
|
|
674
693
|
|
|
675
694
|
`sdk.feeds.top({ ref, limit?, session?, compass? })` answers the top of a feed for the
|
package/dist/index.d.ts
CHANGED
|
@@ -195,7 +195,7 @@ export { VideoResource } from './resources/video.js';
|
|
|
195
195
|
export type { VideoUploadCreds, CreateVideoUploadResult, VideoStatusInfo, VideoPlaybackToken, VideoEntitlement, } from './resources/video.js';
|
|
196
196
|
export { AppSubscriptionsResource } from './resources/app-subscriptions.js';
|
|
197
197
|
export type { AppSubscriptionBoostCredit, AppSubscriptionCheckoutResult, AppSubscriptionPortalResult, AppSubscriptionStatusResult, AppSubscriptionTierChangePreview, AppSubscriptionTierChangeResult, } from './resources/app-subscriptions.js';
|
|
198
|
-
export type { CuratorSource, CuratorPrompt, CuratorRunInput, CuratorRunResult, CuratorTodayEdition, CuratorTodayExcerpt, CuratorTodayLeadImage, CuratorTodayRadar, CuratorTodayReaction, CuratorTodayResponse, CuratorTodaySource, CuratorTodayStory, ForYouMeta, ForYouParams, ForYouSurface, } from './resources/curator.js';
|
|
198
|
+
export type { CuratorSource, CuratorPrompt, CuratorRunInput, CuratorRunResult, CuratorTodayEdition, CuratorTodayExcerpt, CuratorTodayLeadImage, CuratorTodayRadar, CuratorTodayReaction, CuratorTodayResponse, CuratorTodaySource, CuratorTodayStory, ForYouMeta, ForYouParams, ForYouSurface, ForYouWorldBlock, ForYouWorldBlockType, ForYouWorldCategoryShortcut, ForYouWorldItem, ForYouWorldMeta, ForYouWorldParams, ForYouWorldPart, ForYouWorldResponse, ForYouWorldStory, ForYouWorldStoryTarget, ForYouWorldViral, } from './resources/curator.js';
|
|
199
199
|
export { ReportsResource } from './resources/reports.js';
|
|
200
200
|
export type { ReportTargetType, ReportStatus, CreateReportInput, ReportRecord, ResolveReportInput, } from './resources/reports.js';
|
|
201
201
|
export { ModerationResource } from './resources/moderation.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HttpClient } from '../client.js';
|
|
2
|
-
import type { DiscoveryLayout, PaginatedResponse, PaginationMeta, Post, SingleResponse } from '../types.js';
|
|
2
|
+
import type { CompassFilterMeta, DiscoveryLayout, PaginatedResponse, PaginationMeta, Post, SingleResponse } from '../types.js';
|
|
3
|
+
import type { FeedTopNetworkCard, FeedTopTarget } from './feeds.js';
|
|
3
4
|
/** Which surface is asking: Home's For You (default) or Discover's For you. */
|
|
4
5
|
export type ForYouSurface = 'home' | 'discover';
|
|
5
6
|
export type ForYouParams = {
|
|
@@ -22,6 +23,158 @@ export interface ForYouMeta extends PaginationMeta {
|
|
|
22
23
|
/** Whether the ranker can personalize for this member yet (3 follows or 3 upvoted authors). */
|
|
23
24
|
personalized?: boolean;
|
|
24
25
|
}
|
|
26
|
+
/** Which half to read: the stories rail, the items, or both (the default). The app can read the two at once and draw each as it lands. */
|
|
27
|
+
export type ForYouWorldPart = 'stories' | 'items' | 'all';
|
|
28
|
+
export interface ForYouWorldParams {
|
|
29
|
+
part?: ForYouWorldPart;
|
|
30
|
+
/** Opaque per app session ([A-Za-z0-9_-], up to 64): the same token keeps one session's order stable across reads. */
|
|
31
|
+
session?: string;
|
|
32
|
+
/** A For You snapshot nonce the app holds (`meta.snapshot` of a previous answer): reused while the server holds it. */
|
|
33
|
+
snapshot?: string;
|
|
34
|
+
/** A Politics choice, as `posts.list` takes it. */
|
|
35
|
+
compass?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Where a story opens in the app: a radar story by its cluster id, or a World Today story the radar has none for by its Today id. */
|
|
38
|
+
export type ForYouWorldStoryTarget = {
|
|
39
|
+
kind: 'story';
|
|
40
|
+
id: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'today_story';
|
|
43
|
+
id: string;
|
|
44
|
+
};
|
|
45
|
+
/** One world story: a radar story (with Today's headline when Today seeded it), a Today story, or a viral post. */
|
|
46
|
+
export interface ForYouWorldStory {
|
|
47
|
+
/** What an impression of it names: 'cluster:<id>', 'today:<id>' or the post's ref. Send it with `block: 'top'` on a visible view. */
|
|
48
|
+
ref: string;
|
|
49
|
+
id: string;
|
|
50
|
+
source: 'today' | 'radar' | 'viral';
|
|
51
|
+
target: FeedTopTarget | ForYouWorldStoryTarget;
|
|
52
|
+
label: string;
|
|
53
|
+
kind: 'breaking' | 'viral' | 'story';
|
|
54
|
+
breaking: boolean;
|
|
55
|
+
/** A front-page or general-news story: one of those shown whatever the member's interests. */
|
|
56
|
+
general: boolean;
|
|
57
|
+
theme: string | null;
|
|
58
|
+
categories: string[];
|
|
59
|
+
/** How widely it is told: posts per source kind, and the outlets that ran it (Today), when known. */
|
|
60
|
+
counts: {
|
|
61
|
+
sources: Record<string, number>;
|
|
62
|
+
outlets: number | null;
|
|
63
|
+
};
|
|
64
|
+
media: {
|
|
65
|
+
images: number;
|
|
66
|
+
videos: number;
|
|
67
|
+
};
|
|
68
|
+
freshness: {
|
|
69
|
+
newestAt: string | null;
|
|
70
|
+
};
|
|
71
|
+
position: number;
|
|
72
|
+
/** Why it is here: `interest:<category>`, `breaking`, `general`, `viral`, `breadth` or `trending`. */
|
|
73
|
+
reasons: string[];
|
|
74
|
+
explain: {
|
|
75
|
+
score: number;
|
|
76
|
+
interest: number;
|
|
77
|
+
rank: number;
|
|
78
|
+
impression: 'fresh' | 'demoted';
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** One item: a Minds post (`ref` is its id) or an open-network post (`ref` is '<protocol>/<nativeId>'). */
|
|
82
|
+
export interface ForYouWorldItem {
|
|
83
|
+
ref: string;
|
|
84
|
+
kind: 'post' | 'network_post';
|
|
85
|
+
authorId: string;
|
|
86
|
+
target: FeedTopTarget;
|
|
87
|
+
/** Reading order through the blocks. */
|
|
88
|
+
position: number;
|
|
89
|
+
/** 'top' for the first 10: send `block: 'top'` and the position with a visible view of one. */
|
|
90
|
+
block: 'top' | 'below';
|
|
91
|
+
media: 'video' | 'image' | 'none';
|
|
92
|
+
topic: string | null;
|
|
93
|
+
/** Why it is here: `interest:<category>`, `followed:@<handle>`, `for_you`, `engaging` or `breadth`. */
|
|
94
|
+
reasons: string[];
|
|
95
|
+
explain: {
|
|
96
|
+
score: number;
|
|
97
|
+
source: 'foryou' | 'category' | 'all';
|
|
98
|
+
label: 'safe' | 'open';
|
|
99
|
+
impression: 'fresh' | 'demoted';
|
|
100
|
+
engagement: {
|
|
101
|
+
source: string;
|
|
102
|
+
rate: number;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** A viral post in the viral block. `card` is an open-network post's card (no URL on its network); null for a Minds post, read by id. */
|
|
107
|
+
export interface ForYouWorldViral {
|
|
108
|
+
ref: string;
|
|
109
|
+
kind: 'post' | 'network_post';
|
|
110
|
+
protocol: string;
|
|
111
|
+
target: FeedTopTarget;
|
|
112
|
+
label: string;
|
|
113
|
+
category: string | null;
|
|
114
|
+
media: 'video' | 'image' | null;
|
|
115
|
+
rank: number;
|
|
116
|
+
velocity: {
|
|
117
|
+
perHour1h: number;
|
|
118
|
+
z: number;
|
|
119
|
+
};
|
|
120
|
+
card: FeedTopNetworkCard | null;
|
|
121
|
+
}
|
|
122
|
+
export interface ForYouWorldCategoryShortcut {
|
|
123
|
+
id: string;
|
|
124
|
+
name: string;
|
|
125
|
+
reason: 'interest' | 'breadth';
|
|
126
|
+
target: {
|
|
127
|
+
kind: 'category';
|
|
128
|
+
id: string;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/** The page's components, laid out like All: no type follows itself. */
|
|
132
|
+
export type ForYouWorldBlockType = 'stories' | 'lead_video' | 'clips' | 'posts' | 'people' | 'groups' | 'topics' | 'categories' | 'viral';
|
|
133
|
+
export interface ForYouWorldBlock {
|
|
134
|
+
id: string;
|
|
135
|
+
type: ForYouWorldBlockType;
|
|
136
|
+
/** What it shows, in order: item refs (lead_video, clips, posts), story refs, entity keys, category ids or viral refs. */
|
|
137
|
+
refs: string[];
|
|
138
|
+
/** The stories rail of a part=items answer: fill it from your own part=stories read. */
|
|
139
|
+
deferred?: true;
|
|
140
|
+
/** people, groups and topics: the recommender's suggestions (three showings without a tap rest one). */
|
|
141
|
+
entities?: Array<Record<string, unknown> & {
|
|
142
|
+
kind: string;
|
|
143
|
+
key: string;
|
|
144
|
+
}>;
|
|
145
|
+
categories?: ForYouWorldCategoryShortcut[];
|
|
146
|
+
viral?: ForYouWorldViral[];
|
|
147
|
+
}
|
|
148
|
+
export interface ForYouWorldMeta {
|
|
149
|
+
part: ForYouWorldPart;
|
|
150
|
+
flag: {
|
|
151
|
+
world: 'on';
|
|
152
|
+
impressions: 'on' | 'off' | 'unavailable';
|
|
153
|
+
};
|
|
154
|
+
/** Fewer than 3 follows and no signals yet: a breadth-only overview. */
|
|
155
|
+
cold_start: boolean;
|
|
156
|
+
personalized: boolean | null;
|
|
157
|
+
/** The member's top interests as browse category ids, for chips. Never put them in a URL. */
|
|
158
|
+
interests: string[];
|
|
159
|
+
/**
|
|
160
|
+
* Sources left out because they missed their deadline or failed. `consent` is the Bluesky consent read: when it is
|
|
161
|
+
* named, Bluesky posts from the category pools and the viral read were left out of this answer.
|
|
162
|
+
*/
|
|
163
|
+
partial: string[];
|
|
164
|
+
safety: 'safe' | 'open' | null;
|
|
165
|
+
/** The For You snapshot the items came from; `foryou_cursor` continues it on `curator.forYou({ cursor })`. */
|
|
166
|
+
snapshot: string | null;
|
|
167
|
+
foryou_cursor: string | null;
|
|
168
|
+
short: boolean;
|
|
169
|
+
compass_filter?: CompassFilterMeta;
|
|
170
|
+
}
|
|
171
|
+
/** GET /curator/foryou/world: `stories` unless part=items, `items` and `blocks` unless part=stories. */
|
|
172
|
+
export interface ForYouWorldResponse {
|
|
173
|
+
stories?: ForYouWorldStory[];
|
|
174
|
+
items?: ForYouWorldItem[];
|
|
175
|
+
blocks?: ForYouWorldBlock[];
|
|
176
|
+
meta: ForYouWorldMeta;
|
|
177
|
+
}
|
|
25
178
|
/** RSS / Atom source. Default — `type` may be omitted for back-compat. */
|
|
26
179
|
export interface CuratorRssSource {
|
|
27
180
|
type?: 'rss';
|
|
@@ -278,4 +431,13 @@ export declare class CuratorResource {
|
|
|
278
431
|
forYou(params?: ForYouParams): Promise<PaginatedResponse<Post> & {
|
|
279
432
|
meta: ForYouMeta;
|
|
280
433
|
}>;
|
|
434
|
+
/**
|
|
435
|
+
* For You as an overview of the world by the member's interests, read with their own key of the app: world stories
|
|
436
|
+
* (interest-matched, with breadth), then a page of typed blocks laid out like All (a lead video, clip strips, posts,
|
|
437
|
+
* people and groups to follow, trending topics, viral posts, category shortcuts). `part` reads one half on its own.
|
|
438
|
+
* 404 until the app's operator turns it on; a 503 `for_you_world_unavailable` carries Retry-After. Always private.
|
|
439
|
+
*/
|
|
440
|
+
forYouWorld(params?: ForYouWorldParams, options?: {
|
|
441
|
+
retry?: boolean;
|
|
442
|
+
}): Promise<ForYouWorldResponse>;
|
|
281
443
|
}
|
|
@@ -57,4 +57,13 @@ export class CuratorResource {
|
|
|
57
57
|
const { retry, ...query } = params;
|
|
58
58
|
return retry === false ? this.client.get('/curator/foryou', query, { retry: false }) : this.client.get('/curator/foryou', query);
|
|
59
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* For You as an overview of the world by the member's interests, read with their own key of the app: world stories
|
|
62
|
+
* (interest-matched, with breadth), then a page of typed blocks laid out like All (a lead video, clip strips, posts,
|
|
63
|
+
* people and groups to follow, trending topics, viral posts, category shortcuts). `part` reads one half on its own.
|
|
64
|
+
* 404 until the app's operator turns it on; a 503 `for_you_world_unavailable` carries Retry-After. Always private.
|
|
65
|
+
*/
|
|
66
|
+
forYouWorld(params = {}, options) {
|
|
67
|
+
return this.client.get('/curator/foryou/world', { part: params.part, session: params.session, snapshot: params.snapshot, compass: params.compass }, options);
|
|
68
|
+
}
|
|
60
69
|
}
|
|
@@ -3,7 +3,10 @@ import type { PaginatedResponse, SingleResponse, SuccessResponse, Profile, Profi
|
|
|
3
3
|
export declare class ProfilesResource {
|
|
4
4
|
private client;
|
|
5
5
|
constructor(client: HttpClient);
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* List users in the network, newest first. Automated accounts are left out (a personal agent stays, `is_ai`), and
|
|
8
|
+
* so is an account wearing an official account's name; a page can come back shorter than `limit`.
|
|
9
|
+
*/
|
|
7
10
|
list(params?: {
|
|
8
11
|
limit?: number;
|
|
9
12
|
offset?: number;
|
|
@@ -3,7 +3,10 @@ export class ProfilesResource {
|
|
|
3
3
|
constructor(client) {
|
|
4
4
|
this.client = client;
|
|
5
5
|
}
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* List users in the network, newest first. Automated accounts are left out (a personal agent stays, `is_ai`), and
|
|
8
|
+
* so is an account wearing an official account's name; a page can come back shorter than `limit`.
|
|
9
|
+
*/
|
|
7
10
|
list(params) {
|
|
8
11
|
return this.client.get('/profiles', params);
|
|
9
12
|
}
|
|
@@ -1043,11 +1043,10 @@ export interface SocialPost {
|
|
|
1043
1043
|
};
|
|
1044
1044
|
/**
|
|
1045
1045
|
* Present, and only then, when the ActivityPub author opted out of indexing (`noindex`,
|
|
1046
|
-
* `indexable: false`, or #nobot, #noindex or #noai in their bio). The
|
|
1047
|
-
*
|
|
1048
|
-
* author-feed and conversation reads (a profile or a post someone opened)
|
|
1049
|
-
*
|
|
1050
|
-
* to signed-out visitors.
|
|
1046
|
+
* `indexable: false`, or #nobot, #noindex or #noai in their bio). The trends, trend-feed and radar
|
|
1047
|
+
* reads leave such posts out, keyless and for a member alike, and no post served from the source index
|
|
1048
|
+
* is one. The author-feed and conversation reads (a profile or a post someone opened), keyless or a
|
|
1049
|
+
* member's, still return them with this mark, so an app should never re-share or promote one.
|
|
1051
1050
|
*/
|
|
1052
1051
|
authorOptOut?: true;
|
|
1053
1052
|
/** A bridge (Bridgy Fed, Mostr, a NIP-48 proxy tag) made this post from one on another network (SocialBridge). Present only on a copy read live. */
|
package/llm.md
CHANGED
|
@@ -639,6 +639,18 @@ await r.bookmarks.unsave(key) // or uns
|
|
|
639
639
|
|
|
640
640
|
Newest saved first. Pages can be short while they skip posts the member can no longer read: page on `meta.next_cursor`, not length. Needs the member's own app key (else 403 `project_binding_required`). 503 `bookmarks_unavailable` means the server has no synced bookmarks yet: keep saves on the device (pass `{ retry: false }` to the probe so the 503 is not retried).
|
|
641
641
|
|
|
642
|
+
### r.curator.forYouWorld — For You as the world by the member's interests
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
const head = r.curator.forYouWorld({ part: 'stories', session }) // member's own app key; read the two halves at once
|
|
646
|
+
const page = await r.curator.forYouWorld({ part: 'items', session, snapshot }) // items + blocks; snapshot = a previous meta.snapshot
|
|
647
|
+
// stories: { ref, id, source: today|radar|viral, target, label, kind, breaking, general, theme, counts, reasons, ... }
|
|
648
|
+
// items: { ref, kind, target, position, block: 'top' | 'below', media, topic, reasons, explain }
|
|
649
|
+
// blocks: [{ id, type: stories|lead_video|clips|posts|people|groups|topics|viral|categories, refs, deferred?, entities?, categories?, viral? }]
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
404 while the app's operator has it off; always private (`Cache-Control: private, no-store`). A story's or item's `target` is in the app (a radar story by cluster id, a Today story as `today_story`, a post id, `/social/post/<protocol>/<id>`), never a URL out. Send `block: 'top'` with a visible view of a story in the rail or one of the first 10 items: three such views without an open rest it for a week. `meta.partial` names a source that missed its deadline; `meta.interests` are category ids for chips, never for a URL; `meta.foryou_cursor` continues on `r.curator.forYou({ cursor })`.
|
|
653
|
+
|
|
642
654
|
### r.feeds — The top of a feed (member and visitor)
|
|
643
655
|
|
|
644
656
|
```typescript
|