@recursiv/sdk 0.7.67 → 0.7.68

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 CHANGED
@@ -94,7 +94,7 @@ for await (const chunk of r.agents.chatStream(agent.id, { message: 'Hello!' }))
94
94
  | Resource | Key methods |
95
95
  |----------|------------|
96
96
  | `r.posts` | `create`, `update`, `list`, `liked`, `bookmarked`, `bookmark`, `unbookmark`, `search`, `replies`, `react` |
97
- | `r.bookmarks` | `save`, `unsave`, `posts`, `list`, `keys`, `merge` — the member's saved posts, open-network posts and articles, synced across devices |
97
+ | `r.bookmarks` | `save`, `unsave`, `posts`, `list`, `keys`, `merge` — the member's saved posts, open-network posts and articles, synced across devices; `collections`: `list`, `create`, `update`, `remove`, `add`, `removeItem`, `items`, `posts` — private named collections of saves (0.7.68, where `network.getConfig()` advertises `capabilities.bookmark_collections`) |
98
98
  | `r.feeds` | `top` (what the member is most likely to engage with, rotated by what they saw, with open-network lanes and the lead story), `stories` (the story tail), `publicTop` (a visitor's top, keyless and edge-cacheable) |
99
99
  | `r.communities` | `create`, `join`, `search`, `members` |
100
100
  | `r.chat` | `send`, `dm`, `createGroup` (`encrypted: true` for an end-to-end encrypted group, 0.7.59), `messages` (cursor paging), `acceptRequest`, `declineRequest`, `leave`, `deleteConversation`; a private group's admin: `addMembers`, `removeMember`, `updateGroup` (0.7.59) |
package/dist/index.d.ts CHANGED
@@ -203,10 +203,10 @@ export type { ModerationTargetType, ModerationActionType, ModerationAppealStatus
203
203
  export { LinkPreviewResource } from './resources/link-preview.js';
204
204
  export { SEARCH_SECTIONS, SearchResource } from './resources/search.js';
205
205
  export type { SearchAnswer, SearchGroup, SearchOmitReason, SearchParams, SearchPerson, SearchRelated, SearchResponse, SearchSection, SearchStory, SearchTopic } from './resources/search.js';
206
- export { BOOKMARK_MERGE_MAX_ITEMS, BookmarksResource } from './resources/bookmarks.js';
206
+ export { BOOKMARK_MERGE_MAX_ITEMS, BookmarkCollectionsResource, BookmarksResource } from './resources/bookmarks.js';
207
207
  export { FEED_TOP_NETWORKS, FeedsResource } from './resources/feeds.js';
208
208
  export type { FeedStoriesParams, FeedStoriesResponse, FeedStory, FeedTopExplain, FeedTopItem, FeedTopMeta, FeedTopNetwork, FeedTopNetworkCard, FeedTopNetworkEntry, FeedTopParams, FeedTopResponse, FeedTopTarget, PublicFeedTopMeta, PublicFeedTopParams, PublicFeedTopResponse, } from './resources/feeds.js';
209
- export type { BookmarkedPost, BookmarkInput, BookmarkItem, BookmarkKey, BookmarkKeyRow, BookmarkKind, BookmarkMergeItem, BookmarkMergeResult, BookmarkProtocol, BookmarkRequestOptions, BookmarksPage, SavedBookmark, UnsavedBookmark, } from './resources/bookmarks.js';
209
+ export type { BookmarkCollection, BookmarkCollectionInput, BookmarkCollectionKind, BookmarkCollectionPatch, BookmarkCollectionsList, BookmarkCollectionTarget, BookmarkCollectionVisibility, BookmarkedPost, BookmarkInput, BookmarkItem, BookmarkKey, BookmarkKeyRow, BookmarkKeysPage, BookmarkKind, BookmarkMergeItem, BookmarkMergeResult, BookmarkProtocol, BookmarkRequestOptions, BookmarksPage, FiledBookmark, RemovedBookmarkCollection, SavedBookmark, UnfiledBookmark, UnsavedBookmark, } from './resources/bookmarks.js';
210
210
  export { AccountsResource } from './resources/accounts.js';
211
211
  export type { SiblingAccount, SiblingAccountsResponse, SwitchAccountResult, } from './resources/accounts.js';
212
212
  export type { LinkPreview, LinkPreviewResponse, } from './resources/link-preview.js';
package/dist/index.js CHANGED
@@ -257,7 +257,7 @@ export { ReportsResource } from './resources/reports.js';
257
257
  export { ModerationResource } from './resources/moderation.js';
258
258
  export { LinkPreviewResource } from './resources/link-preview.js';
259
259
  export { SEARCH_SECTIONS, SearchResource } from './resources/search.js';
260
- export { BOOKMARK_MERGE_MAX_ITEMS, BookmarksResource } from './resources/bookmarks.js';
260
+ export { BOOKMARK_MERGE_MAX_ITEMS, BookmarkCollectionsResource, BookmarksResource } from './resources/bookmarks.js';
261
261
  export { FEED_TOP_NETWORKS, FeedsResource } from './resources/feeds.js';
262
262
  export { AccountsResource } from './resources/accounts.js';
263
263
  export { OrganizationSettingsResource } from './resources/organization-settings.js';
@@ -122,6 +122,83 @@ export interface BookmarksPage<T> extends PaginatedResponse<T> {
122
122
  next_cursor: string | null;
123
123
  };
124
124
  }
125
+ /** A page of saved keys. `collections` (0.7.68) is there only where the server serves collections. */
126
+ export interface BookmarkKeysPage extends BookmarksPage<BookmarkKeyRow> {
127
+ /**
128
+ * For this page's keys that are filed somewhere: the ids of the collections each sits in, oldest
129
+ * collection first. A key filed nowhere is absent. The whole field is absent while collections are
130
+ * off on the server, so its presence also says collections can be used.
131
+ */
132
+ collections?: Record<BookmarkKey, string[]>;
133
+ }
134
+ /** What a collection holds. Before the cutover only `posts` collections are made (any saved thing: posts, open-network posts, articles). */
135
+ export type BookmarkCollectionKind = 'posts' | 'accounts' | 'tags';
136
+ /** Who may see a collection. Before the cutover every collection is `private`. */
137
+ export type BookmarkCollectionVisibility = 'private' | 'unlisted' | 'public';
138
+ /** A member's named collection of saves in this app (0.7.68). Collections are labels on saves. */
139
+ export interface BookmarkCollection {
140
+ id: string;
141
+ kind: BookmarkCollectionKind;
142
+ /** Unique per member and app: lowercase letters and digits joined by hyphens, at most 64 characters. */
143
+ slug: string;
144
+ /** At most 120 characters. */
145
+ title: string;
146
+ /** At most 500 characters. */
147
+ description: string | null;
148
+ visibility: BookmarkCollectionVisibility;
149
+ item_count: number;
150
+ created_at: string;
151
+ updated_at: string;
152
+ }
153
+ export interface BookmarkCollectionsList {
154
+ /** Oldest first. */
155
+ data: BookmarkCollection[];
156
+ /** The most collections one member keeps in this app, and the most things one collection holds. */
157
+ meta: {
158
+ max_collections: number;
159
+ max_items: number;
160
+ };
161
+ }
162
+ /** A new collection. Without `slug` one is made from the title (made unique with -2, -3, ...). */
163
+ export interface BookmarkCollectionInput {
164
+ title: string;
165
+ description?: string | null;
166
+ slug?: string;
167
+ }
168
+ /** Any of a collection's title, description (null clears it) and slug. */
169
+ export interface BookmarkCollectionPatch {
170
+ title?: string;
171
+ description?: string | null;
172
+ slug?: string;
173
+ }
174
+ export interface RemovedBookmarkCollection {
175
+ id: string;
176
+ removed: boolean;
177
+ }
178
+ export interface FiledBookmark {
179
+ collection_id: string;
180
+ /** The saved thing's key. A bare repost is filed as its original, as saving one is: use this key and `post_id`. */
181
+ key: BookmarkKey;
182
+ filed: true;
183
+ /** False when it was already in the collection: nothing changed. */
184
+ created: boolean;
185
+ /** True when filing it saved it too. */
186
+ saved_now: boolean;
187
+ added_at: string;
188
+ item_count: number;
189
+ post_id?: string;
190
+ }
191
+ export interface UnfiledBookmark {
192
+ collection_id: string;
193
+ key: BookmarkKey;
194
+ filed: false;
195
+ /** False when it was not in the collection. It stays saved either way. */
196
+ removed: boolean;
197
+ }
198
+ /** What to file: a saved key, a Minds post, or an item (saved first if it is not saved yet). */
199
+ export type BookmarkCollectionTarget = BookmarkKey | {
200
+ postId: string;
201
+ } | BookmarkInput;
125
202
  /** Most items one `merge` call takes. */
126
203
  export declare const BOOKMARK_MERGE_MAX_ITEMS = 200;
127
204
  /**
@@ -131,6 +208,56 @@ export declare const BOOKMARK_MERGE_MAX_ITEMS = 200;
131
208
  export interface BookmarkRequestOptions {
132
209
  retry?: boolean;
133
210
  }
211
+ /**
212
+ * Bookmark collections (0.7.68): the member's private, named labels on their saves in this app.
213
+ * Filing something saves it first; one saved thing can sit in several collections; unsaving it takes it
214
+ * out of every one; deleting a collection leaves everything it held saved.
215
+ *
216
+ * Off on a server until it advertises `capabilities.bookmark_collections` (`network.getConfig()`): until
217
+ * then, and until its tables are applied, every call rejects with a 503 whose code is `lists_unavailable`
218
+ * (saving still works). A collection that is not the member's is 404 `collection_not_found`. Caps: 409
219
+ * `collection_limit` (collections per member) and `collection_item_limit` (things per collection).
220
+ */
221
+ export declare class BookmarkCollectionsResource {
222
+ private client;
223
+ constructor(client: HttpClient);
224
+ /** The member's collections in this app, oldest first, with the caps. */
225
+ list(options?: BookmarkRequestOptions): Promise<BookmarkCollectionsList>;
226
+ /**
227
+ * Make a private collection. 409 `slug_taken` for a slug the member already uses. Retried on a 5xx like any
228
+ * POST: pass an `idempotencyKey` so a retry cannot make a second collection.
229
+ */
230
+ create(input: BookmarkCollectionInput, options?: BookmarkRequestOptions & {
231
+ idempotencyKey?: string;
232
+ }): Promise<SingleResponse<BookmarkCollection>>;
233
+ /** Rename, re-describe or re-slug a collection. */
234
+ update(collectionId: string, patch: BookmarkCollectionPatch): Promise<SingleResponse<BookmarkCollection>>;
235
+ /** Delete a collection. Idempotent; what it held stays saved. */
236
+ remove(collectionId: string, options?: BookmarkRequestOptions): Promise<SingleResponse<RemovedBookmarkCollection>>;
237
+ /**
238
+ * File something in a collection; idempotent. A key or `{ postId }` files what is saved, and a Minds post is
239
+ * saved first when it is not (404 `post_not_found` if the member cannot read it); a key alone that is not saved
240
+ * is 409 `not_saved`. An item (a Minds post, open-network post or article) goes in one request that saves it if
241
+ * it is not saved and files it together: when the collection is missing (404), full (409 `collection_item_limit`)
242
+ * or unavailable (503), or the member's saves are at their cap (409 `bookmark_limit`), nothing is saved.
243
+ */
244
+ add(collectionId: string, target: BookmarkCollectionTarget, options?: BookmarkRequestOptions): Promise<SingleResponse<FiledBookmark>>;
245
+ /** Take something out of a collection. Idempotent; it stays saved, and in any other collection. */
246
+ removeItem(collectionId: string, target: BookmarkKey | {
247
+ postId: string;
248
+ }, options?: BookmarkRequestOptions): Promise<SingleResponse<UnfiledBookmark>>;
249
+ /** The open-network posts and articles filed in a collection, newest saved first. Page on `meta.next_cursor`. */
250
+ items(collectionId: string, params?: {
251
+ kind?: 'social' | 'article';
252
+ limit?: number;
253
+ cursor?: string;
254
+ }, options?: BookmarkRequestOptions): Promise<BookmarksPage<BookmarkItem>>;
255
+ /** The Minds posts filed in a collection, newest saved first, hydrated like the feed. Page on `meta.next_cursor`. */
256
+ posts(collectionId: string, params?: {
257
+ limit?: number;
258
+ cursor?: string;
259
+ }, options?: BookmarkRequestOptions): Promise<BookmarksPage<BookmarkedPost>>;
260
+ }
134
261
  /**
135
262
  * Synced bookmarks: the signed-in member's saved Minds posts, open-network posts and articles in this app,
136
263
  * across every device they sign in on. Private to the member; needs the member's own app key.
@@ -140,6 +267,8 @@ export interface BookmarkRequestOptions {
140
267
  */
141
268
  export declare class BookmarksResource {
142
269
  private client;
270
+ /** Named collections of the member's saves (0.7.68). */
271
+ readonly collections: BookmarkCollectionsResource;
143
272
  constructor(client: HttpClient);
144
273
  /** Save one item. Idempotent: saving what is saved changes nothing. 409 `bookmark_limit` past the member's limit. */
145
274
  save(item: BookmarkInput, options?: BookmarkRequestOptions): Promise<SingleResponse<SavedBookmark>>;
@@ -147,22 +276,27 @@ export declare class BookmarksResource {
147
276
  unsave(target: BookmarkKey | {
148
277
  postId: string;
149
278
  }, options?: BookmarkRequestOptions): Promise<SingleResponse<UnsavedBookmark>>;
150
- /** Saved Minds posts, newest saved first, hydrated like the feed. Page on `meta.next_cursor`. */
279
+ /** Saved Minds posts, newest saved first, hydrated like the feed; `collection` narrows to one collection (0.7.68). Page on `meta.next_cursor`. */
151
280
  posts(params?: {
152
281
  limit?: number;
153
282
  cursor?: string;
283
+ collection?: string;
154
284
  }, options?: BookmarkRequestOptions): Promise<BookmarksPage<BookmarkedPost>>;
155
- /** Saved open-network posts and articles, newest saved first. Page on `meta.next_cursor`. */
285
+ /** Saved open-network posts and articles, newest saved first; `collection` narrows to one collection (0.7.68). Page on `meta.next_cursor`. */
156
286
  list(params?: {
157
287
  kind?: 'social' | 'article';
158
288
  limit?: number;
159
289
  cursor?: string;
290
+ collection?: string;
160
291
  }, options?: BookmarkRequestOptions): Promise<BookmarksPage<BookmarkItem>>;
161
- /** Every saved key (hidden posts included), newest saved first, up to 500 a page. For a saved-state cache. */
292
+ /**
293
+ * Every saved key (hidden posts included), newest saved first, up to 500 a page. For a saved-state cache.
294
+ * Where collections are served, `collections` says which collections this page's keys are filed in.
295
+ */
162
296
  keys(params?: {
163
297
  limit?: number;
164
298
  cursor?: string;
165
- }, options?: BookmarkRequestOptions): Promise<BookmarksPage<BookmarkKeyRow>>;
299
+ }, options?: BookmarkRequestOptions): Promise<BookmarkKeysPage>;
166
300
  /**
167
301
  * Upload a device's saves, e.g. when its member signs in: at most 200 items a call. Idempotent (a second
168
302
  * merge of the same items is a no-op); invalid items and posts the member cannot read are `skipped`, and
@@ -1,5 +1,68 @@
1
1
  /** Most items one `merge` call takes. */
2
2
  export const BOOKMARK_MERGE_MAX_ITEMS = 200;
3
+ const itemPath = (collectionId, key) => `/bookmarks/collections/${encodeURIComponent(collectionId)}/items/${encodeURIComponent(key)}`;
4
+ /**
5
+ * Bookmark collections (0.7.68): the member's private, named labels on their saves in this app.
6
+ * Filing something saves it first; one saved thing can sit in several collections; unsaving it takes it
7
+ * out of every one; deleting a collection leaves everything it held saved.
8
+ *
9
+ * Off on a server until it advertises `capabilities.bookmark_collections` (`network.getConfig()`): until
10
+ * then, and until its tables are applied, every call rejects with a 503 whose code is `lists_unavailable`
11
+ * (saving still works). A collection that is not the member's is 404 `collection_not_found`. Caps: 409
12
+ * `collection_limit` (collections per member) and `collection_item_limit` (things per collection).
13
+ */
14
+ export class BookmarkCollectionsResource {
15
+ client;
16
+ constructor(client) {
17
+ this.client = client;
18
+ }
19
+ /** The member's collections in this app, oldest first, with the caps. */
20
+ list(options) {
21
+ return this.client.get('/bookmarks/collections', undefined, options);
22
+ }
23
+ /**
24
+ * Make a private collection. 409 `slug_taken` for a slug the member already uses. Retried on a 5xx like any
25
+ * POST: pass an `idempotencyKey` so a retry cannot make a second collection.
26
+ */
27
+ create(input, options) {
28
+ return this.client.post('/bookmarks/collections', input, options);
29
+ }
30
+ /** Rename, re-describe or re-slug a collection. */
31
+ update(collectionId, patch) {
32
+ return this.client.patch(`/bookmarks/collections/${encodeURIComponent(collectionId)}`, patch);
33
+ }
34
+ /** Delete a collection. Idempotent; what it held stays saved. */
35
+ remove(collectionId, options) {
36
+ return this.client.delete(`/bookmarks/collections/${encodeURIComponent(collectionId)}`, options);
37
+ }
38
+ /**
39
+ * File something in a collection; idempotent. A key or `{ postId }` files what is saved, and a Minds post is
40
+ * saved first when it is not (404 `post_not_found` if the member cannot read it); a key alone that is not saved
41
+ * is 409 `not_saved`. An item (a Minds post, open-network post or article) goes in one request that saves it if
42
+ * it is not saved and files it together: when the collection is missing (404), full (409 `collection_item_limit`)
43
+ * or unavailable (503), or the member's saves are at their cap (409 `bookmark_limit`), nothing is saved.
44
+ */
45
+ add(collectionId, target, options) {
46
+ if (typeof target === 'string')
47
+ return this.client.put(itemPath(collectionId, target), undefined, options);
48
+ if ('postId' in target)
49
+ return this.client.put(itemPath(collectionId, `post:${target.postId}`), undefined, options);
50
+ return this.client.post(`/bookmarks/collections/${encodeURIComponent(collectionId)}/items`, target, options);
51
+ }
52
+ /** Take something out of a collection. Idempotent; it stays saved, and in any other collection. */
53
+ removeItem(collectionId, target, options) {
54
+ const key = typeof target === 'string' ? target : `post:${target.postId}`;
55
+ return this.client.delete(itemPath(collectionId, key), options);
56
+ }
57
+ /** The open-network posts and articles filed in a collection, newest saved first. Page on `meta.next_cursor`. */
58
+ items(collectionId, params, options) {
59
+ return this.client.get('/bookmarks', { ...params, collection: collectionId }, options);
60
+ }
61
+ /** The Minds posts filed in a collection, newest saved first, hydrated like the feed. Page on `meta.next_cursor`. */
62
+ posts(collectionId, params, options) {
63
+ return this.client.get('/posts', { bookmarked: true, ...params, collection: collectionId }, options);
64
+ }
65
+ }
3
66
  /**
4
67
  * Synced bookmarks: the signed-in member's saved Minds posts, open-network posts and articles in this app,
5
68
  * across every device they sign in on. Private to the member; needs the member's own app key.
@@ -9,8 +72,11 @@ export const BOOKMARK_MERGE_MAX_ITEMS = 200;
9
72
  */
10
73
  export class BookmarksResource {
11
74
  client;
75
+ /** Named collections of the member's saves (0.7.68). */
76
+ collections;
12
77
  constructor(client) {
13
78
  this.client = client;
79
+ this.collections = new BookmarkCollectionsResource(client);
14
80
  }
15
81
  /** Save one item. Idempotent: saving what is saved changes nothing. 409 `bookmark_limit` past the member's limit. */
16
82
  save(item, options) {
@@ -21,15 +87,18 @@ export class BookmarksResource {
21
87
  const key = typeof target === 'string' ? target : `post:${target.postId}`;
22
88
  return this.client.delete(`/bookmarks/${encodeURIComponent(key)}`, options);
23
89
  }
24
- /** Saved Minds posts, newest saved first, hydrated like the feed. Page on `meta.next_cursor`. */
90
+ /** Saved Minds posts, newest saved first, hydrated like the feed; `collection` narrows to one collection (0.7.68). Page on `meta.next_cursor`. */
25
91
  posts(params, options) {
26
92
  return this.client.get('/posts', { bookmarked: true, ...params }, options);
27
93
  }
28
- /** Saved open-network posts and articles, newest saved first. Page on `meta.next_cursor`. */
94
+ /** Saved open-network posts and articles, newest saved first; `collection` narrows to one collection (0.7.68). Page on `meta.next_cursor`. */
29
95
  list(params, options) {
30
96
  return this.client.get('/bookmarks', params, options);
31
97
  }
32
- /** Every saved key (hidden posts included), newest saved first, up to 500 a page. For a saved-state cache. */
98
+ /**
99
+ * Every saved key (hidden posts included), newest saved first, up to 500 a page. For a saved-state cache.
100
+ * Where collections are served, `collections` says which collections this page's keys are filed in.
101
+ */
33
102
  keys(params, options) {
34
103
  return this.client.get('/bookmarks/keys', params, options);
35
104
  }
@@ -7,8 +7,14 @@ interface NetworkConfig {
7
7
  primary_color: string | null;
8
8
  theme: string | null;
9
9
  features: Record<string, unknown>;
10
+ /**
11
+ * `bookmark_collections` (0.7.68; absent on older servers): this server serves bookmark collections
12
+ * (`bookmarks.collections`). Show collections only when it is true, and still treat a 503
13
+ * `lists_unavailable` as off.
14
+ */
10
15
  capabilities: {
11
16
  ws_token: boolean;
17
+ bookmark_collections?: boolean;
12
18
  };
13
19
  auth_methods: string;
14
20
  default_template_name: string | null;
package/llm.md CHANGED
@@ -641,6 +641,23 @@ await r.bookmarks.unsave(key) // or uns
641
641
 
642
642
  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).
643
643
 
644
+ Collections (0.7.68) are private, named labels on saves: filing saves first, one thing can sit in several collections, unsaving takes it out of every one, and deleting a collection leaves what it held saved. Use them only when `(await r.network.getConfig()).data.capabilities.bookmark_collections` is true; still treat 503 `lists_unavailable` as off.
645
+
646
+ ```typescript
647
+ const { data: lists, meta: caps } = await r.bookmarks.collections.list() // oldest first; caps.max_collections (25), caps.max_items (1000)
648
+ const { data: list } = await r.bookmarks.collections.create({ title: 'Read later' }, { idempotencyKey }) // private; slug from the title
649
+ await r.bookmarks.collections.add(list.id, { postId: post.id }) // saves it first if needed; idempotent
650
+ await r.bookmarks.collections.add(list.id, socialOrArticleItem) // one request: saved and filed together, or neither
651
+ await r.bookmarks.collections.removeItem(list.id, key) // it stays saved
652
+ const { data: posts } = await r.bookmarks.collections.posts(list.id) // = r.bookmarks.posts({ collection: list.id })
653
+ const { data: items } = await r.bookmarks.collections.items(list.id) // open-network posts and articles in it
654
+ const { collections: filedIn } = await r.bookmarks.keys() // { [key]: [collection ids] }; absent while collections are off
655
+ await r.bookmarks.collections.update(list.id, { title: 'Later' })
656
+ await r.bookmarks.collections.remove(list.id)
657
+ ```
658
+
659
+ 404 `collection_not_found` for a collection that is not the member's; 409 `collection_limit`, `collection_item_limit`, `slug_taken`, `bookmark_limit` (filing that would save past the saves cap), and `not_saved` (a key that is not saved, sent without its item); 400 `not_supported_yet` for a kind other than posts or a visibility other than private.
660
+
644
661
  ### r.curator.forYouWorld — For You as the world by the member's interests
645
662
 
646
663
  ```typescript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recursiv/sdk",
3
- "version": "0.7.67",
3
+ "version": "0.7.68",
4
4
  "description": "TypeScript SDK for the Recursiv API",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",