@recursiv/sdk 0.7.57 → 0.7.58

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
@@ -75,7 +75,7 @@ for await (const chunk of r.agents.chatStream(agent.id, { message: 'Hello!' }))
75
75
  | Resource | Key methods |
76
76
  |----------|------------|
77
77
  | `r.agents` | `create`, `update`, `chat`, `chatStream`, `retryChatStream`, `grantProjectAccess`, `conversations` |
78
- | `r.e2ee` | `status`, `registerDevice`, `devices`, `revokeDevice`, `publishKeyPackages`, `keyPackageStatus`, `claimKeyPackage`, `appendEvent`, `events`, `acknowledge`, `conversations`; device linking by scan: `createLink`, `link`, `scannedLink`, `approveLink`, `completeLink`, `linkProgress`, `cancelLink` (flag-gated E2EE v2 transport; its doorbell is `r.realtime.onE2eeEvent`, which carries a small message's stored ciphertext to the owner's own sockets; link and device changes arrive on `r.realtime.onE2eeLink` and `onE2eeDevices`) |
78
+ | `r.e2ee` | `status`, `registerDevice`, `devices`, `revokeDevice` (`{ cascade }` to also revoke devices approved through it; 409 `has_dependents` otherwise), `publishKeyPackages`, `keyPackageStatus`, `claimKeyPackage`, `appendEvent`, `events`, `acknowledge`, `conversations`; device linking by scan: `createLink`, `link`, `scannedLink`, `approveLink`, `completeLink`, `linkProgress`, `cancelLink` (flag-gated E2EE v2 transport; its doorbell is `r.realtime.onE2eeEvent`, which carries a small message's stored ciphertext to the owner's own sockets; link and device changes arrive on `r.realtime.onE2eeLink` and `onE2eeDevices`) |
79
79
  | `r.brain` | `sendMessage` |
80
80
  | `r.commands` | `execute`, `gatePrompt` |
81
81
  | `r.projectBrain` | `tasks`, `decisions`, `milestones`, `completeTask`, `usage` |
@@ -115,7 +115,7 @@ for await (const chunk of r.agents.chatStream(agent.id, { message: 'Hello!' }))
115
115
  | `r.admin` | User management, stats, content reports (`listReports`, `resolveReport`, `dismissReport`) |
116
116
  | `r.dispatcher` | Task queue, claims, signals, outcomes, webhooks |
117
117
  | `r.goals` | Org goals with task rollups (group dispatcher tasks) |
118
- | `r.protocols` | Private Minds safety: `sourceControls` (current enablement and saved choices; filter with `control`, each item may carry a `display` label), `setSourceControl`, `onSourceControlChange`, `reportSource`. Delegated accounts: `nativeSocialAccounts`, `startNativeSocialConnection`, `finishNativeSocialConnection`, `disconnectNativeSocialAccount`. Native follows: `nativeFollowStates` (every connected account's state for one source, one read), `nativeFollowState`, `prepareNativeFollow`, `submitNativeFollow`, `nativeFollowStatus` (native following or pending approval, distinct from a Minds feed subscription; preserve the complete signed Nostr list). Native reposts and undo: `nativeRepostState`, `prepareNativeRepost`, `submitNativeRepost`, `nativeRepostStatus` (public posts, explicit approval, connected account, no uncertain retries). Native likes and unlikes: `nativeLikeState`, `prepareNativeLike`, `submitNativeLike`, `nativeLikeStatus` (connected authority, app enablement and explicit approval; resume pending actions instead of duplicating them). Reviewed replies and optional linked posts: `prepareNativeReply`, `submitNativeReply`, `nativeReplyStatus`, `nativeReplyHistory`, `prepareNativeReplyRemoval`, `removeNativeReply` (require deployed API support and app enablement). Keyless shared post links: `sharedNetworks(projectId)`, `getSharedConversation(projectId, { protocol, post, readRef? })`. Member public reading: `searchPublicPosts` (selected account required for Bluesky/ActivityPub; public Nostr search), `getConnectedSocialConversation` (preserve result readerAccountId/readRef), `publicNetworks`, `searchPublicProfiles`, `getPublicProfile`, `getPublicAuthorFeed`, `getFollowingFeed`, `getPublicConversation`, `getPublicTrends`, `getPublicTrendFeed`; radar stories: `getPublicRadarStory` (one story by id with its posts; one that has left the radar comes with its archived copy and the live story it continues as; the id may be a World Today edition story's, and the answer then names it in `editionStory` under the story's radar id), keyless `getSharedRadarStory(projectId, { cluster })` and `getSharedRadarPosts(projectId, { cluster })` (keyless reads carry images and videos only from outlets and members marked `visitorMedia`; signed-in reads keep all media, so a share card uses only those); private app subscriptions: `listSubscriptions`, `subscribeToProfile`, `unsubscribeFromProfile`, `onSubscriptionChange`. `list` returns bounded adapter `maturity`, `limitations`, and exhaustive `supported`/`planned`/`unsupported` implementation capabilities (not provider health or enablement); settings, candidate refresh/status, search, and read-only quarantined candidate review via `listCandidates` / `getCandidate` |
118
+ | `r.protocols` | Private Minds safety: `sourceControls` (current enablement and saved choices; filter with `control`, each item may carry a `display` label), `setSourceControl`, `onSourceControlChange`, `reportSource`. Delegated accounts: `nativeSocialAccounts`, `startNativeSocialConnection`, `finishNativeSocialConnection`, `disconnectNativeSocialAccount`. Native follows: `nativeFollowStates` (every connected account's state for one source, one read), `nativeFollowState`, `prepareNativeFollow`, `submitNativeFollow`, `nativeFollowStatus` (native following or pending approval, distinct from a Minds feed subscription; preserve the complete signed Nostr list). Native reposts and undo: `nativeRepostState`, `prepareNativeRepost`, `submitNativeRepost`, `nativeRepostStatus` (public posts, explicit approval, connected account, no uncertain retries). Native likes and unlikes: `nativeLikeState`, `prepareNativeLike`, `submitNativeLike`, `nativeLikeStatus` (connected authority, app enablement and explicit approval; resume pending actions instead of duplicating them). Reviewed replies and optional linked posts: `prepareNativeReply`, `submitNativeReply`, `nativeReplyStatus`, `nativeReplyHistory`, `prepareNativeReplyRemoval`, `removeNativeReply` (require deployed API support and app enablement). Keyless shared post links: `sharedNetworks(projectId)`, `getSharedConversation(projectId, { protocol, post, readRef? })`. Member public reading: `searchPublicPosts` (selected account required for Bluesky/ActivityPub; public Nostr search), `getConnectedSocialConversation` (preserve result readerAccountId/readRef), `publicNetworks`, `searchPublicProfiles`, `getPublicProfile`, `getPublicAuthorFeed`, `getFollowingFeed`, `getPublicConversation`, `getPublicTrends`, `getPublicTrendFeed`; radar stories: `getPublicRadarStory` (one story by id with its posts; one that left the radar within its minimum lifetime, or within the last half hour, still answers live with `liveUntil` and the story that continues it; one that has left for longer comes with its archived copy and the live story it continues as; the id may be a World Today edition story's, and the answer then names it in `editionStory` under the story's radar id), keyless `getSharedRadarStory(projectId, { cluster })` and `getSharedRadarPosts(projectId, { cluster })` (keyless reads carry images and videos only from outlets and members marked `visitorMedia`; signed-in reads keep all media, so a share card uses only those); private app subscriptions: `listSubscriptions`, `subscribeToProfile`, `unsubscribeFromProfile`, `onSubscriptionChange`. `list` returns bounded adapter `maturity`, `limitations`, and exhaustive `supported`/`planned`/`unsupported` implementation capabilities (not provider health or enablement); settings, candidate refresh/status, search, and read-only quarantined candidate review via `listCandidates` / `getCandidate` |
119
119
 
120
120
  Full reference: see [llm.md](./llm.md) (ships with this package) or the type definitions in `dist/`.
121
121
 
package/dist/index.d.ts CHANGED
@@ -154,7 +154,7 @@ export { UsersResource } from './resources/users.js';
154
154
  export { CommunitiesResource } from './resources/communities.js';
155
155
  export { ChatResource } from './resources/chat.js';
156
156
  export { E2eeResource } from './resources/e2ee.js';
157
- export type { E2eeDevice, E2eeDevicesRealtimeEvent, E2eeEnvelope, E2eeEvent, E2eeKeyPackageStatus, E2eeLink, E2eeLinkCancelledBy, E2eeLinkProgress, E2eeLinkRealtimeEvent, E2eeLinkState, E2eeObjectDownload, E2eeObjectUpload, E2eeRealtimeEvent, E2eeStatus, E2eeStatusReason, } from './resources/e2ee.js';
157
+ export type { E2eeDevice, E2eeDevicesRealtimeEvent, E2eeEnvelope, E2eeEvent, E2eeHasDependentsDetails, E2eeKeyPackageStatus, E2eeLink, E2eeLinkCancelledBy, E2eeLinkProgress, E2eeLinkRealtimeEvent, E2eeLinkState, E2eeObjectDownload, E2eeObjectUpload, E2eeRealtimeEvent, E2eeRevokeResponse, E2eeStatus, E2eeStatusReason, } from './resources/e2ee.js';
158
158
  export { ProjectsResource } from './resources/projects.js';
159
159
  export { AgentsResource, SUPPORTED_MODELS } from './resources/agents.js';
160
160
  export { EvidenceResource } from './resources/evidence.js';
@@ -163,6 +163,23 @@ export interface E2eeLinkRealtimeEvent {
163
163
  linkId: string;
164
164
  state: 'scanned' | 'approved' | 'completed' | 'progress' | 'cancelled';
165
165
  }
166
+ /**
167
+ * The `details` of a 409 `has_dependents` refusal from `revokeDevice` (read
168
+ * them from the thrown `ConflictError`'s `details`): the ids of the account's
169
+ * active devices that were approved through the device and would stop
170
+ * working with it, and whether it is the account's root (main) device, which
171
+ * every device chains to; once the root is revoked the account cannot link a
172
+ * new device.
173
+ */
174
+ export interface E2eeHasDependentsDetails {
175
+ dependents: string[];
176
+ root: boolean;
177
+ }
178
+ /** `revokeDevice`'s answer: the device, and every device the call revoked (the target first). */
179
+ export interface E2eeRevokeResponse extends SingleResponse<E2eeDevice> {
180
+ /** Absent on relays before 0.7.58. Empty when the device was already revoked and nothing else was. */
181
+ revoked?: string[];
182
+ }
166
183
  /**
167
184
  * The realtime `e2ee:devices` event (`r.realtime.onE2eeDevices`): `packages`
168
185
  * when one of the account's devices can now be claimed (it published after
@@ -203,7 +220,18 @@ export declare class E2eeResource {
203
220
  }): Promise<{
204
221
  data: E2eeDevice[];
205
222
  }>;
206
- revokeDevice(deviceId: string): Promise<SingleResponse<E2eeDevice>>;
223
+ /**
224
+ * Revoke one of your devices. When other active devices were approved
225
+ * through it, or it is the account's root (main) device, the relay changes
226
+ * nothing and throws a `ConflictError` with code `has_dependents` and
227
+ * `details: E2eeHasDependentsDetails`, so the app can say which devices
228
+ * would be signed out. Call again with `{ cascade: true }` to revoke it and
229
+ * every device chained through it (relays from 0.7.58; older relays ignore
230
+ * the body and revoke only the device).
231
+ */
232
+ revokeDevice(deviceId: string, input?: {
233
+ cascade?: boolean;
234
+ }): Promise<E2eeRevokeResponse>;
207
235
  /** Publish one-time key packages for one of your devices; `available` is how many it now has. */
208
236
  publishKeyPackages(input: {
209
237
  device_id: string;
@@ -28,8 +28,17 @@ export class E2eeResource {
28
28
  devices(params) {
29
29
  return this.client.get('/e2ee/devices', params);
30
30
  }
31
- revokeDevice(deviceId) {
32
- return this.client.post(`/e2ee/devices/${encodeURIComponent(deviceId)}/revoke`);
31
+ /**
32
+ * Revoke one of your devices. When other active devices were approved
33
+ * through it, or it is the account's root (main) device, the relay changes
34
+ * nothing and throws a `ConflictError` with code `has_dependents` and
35
+ * `details: E2eeHasDependentsDetails`, so the app can say which devices
36
+ * would be signed out. Call again with `{ cascade: true }` to revoke it and
37
+ * every device chained through it (relays from 0.7.58; older relays ignore
38
+ * the body and revoke only the device).
39
+ */
40
+ revokeDevice(deviceId, input) {
41
+ return this.client.post(`/e2ee/devices/${encodeURIComponent(deviceId)}/revoke`, input ?? {});
33
42
  }
34
43
  /** Publish one-time key packages for one of your devices; `available` is how many it now has. */
35
44
  publishKeyPackages(input) {
@@ -990,7 +990,10 @@ export interface SocialPost {
990
990
  * older than 15 minutes when the provider answers in time). Absent: the counts are from this read.
991
991
  */
992
992
  countsObservedAt?: string;
993
- /** Pixel dimensions when the source declares them (Bluesky aspect ratio, Mastodon attachment meta), so a card can take the clip's shape before it loads. */
993
+ /**
994
+ * Pixel dimensions when the source declares them (Bluesky aspect ratio, Mastodon attachment meta, Nostr NIP-92 `dim`), so a
995
+ * card can take the clip's shape before it loads. Each entry of a sensitive post carries `sensitive: true`.
996
+ */
994
997
  media: Array<{
995
998
  type: 'image' | 'video';
996
999
  url: string;
@@ -998,8 +1001,15 @@ export interface SocialPost {
998
1001
  poster?: string;
999
1002
  width?: number;
1000
1003
  height?: number;
1004
+ sensitive?: true;
1001
1005
  }>;
1002
1006
  hasAdditionalContent: boolean;
1007
+ /**
1008
+ * The author marked the post sensitive with one of Minds' sensitive tags (#nsfw, #nudity and the rest), in its text or
1009
+ * among the network's own tags: cover its media as a Minds post flagged NSFW is covered. A post the network itself marks
1010
+ * (a Mastodon sensitive flag or content warning, a Bluesky label, a Nostr content-warning) is never returned at all.
1011
+ */
1012
+ sensitive?: boolean;
1003
1013
  /** At most one independently filtered quoted post. */
1004
1014
  quote?: {
1005
1015
  state: 'available';
@@ -1152,7 +1162,11 @@ export interface SocialRadarMember {
1152
1162
  */
1153
1163
  visitorMedia?: true;
1154
1164
  }
1155
- /** One story on the radar. `breaking` is outlet corroboration inside a short window; `viral` is social velocity above its network's norm. */
1165
+ /**
1166
+ * One story on the radar. `breaking` is outlet corroboration inside a short window; `viral` is social velocity above its
1167
+ * network's norm, from two or more people, on a story still gaining engagement, reported by no outlet or by two or more.
1168
+ * `velocity.perHour` is the engagement its posts gained per hour since the last build, counting only posts read on both.
1169
+ */
1156
1170
  export interface SocialRadarCluster {
1157
1171
  id: string;
1158
1172
  /** Verbatim: a World Today headline, a provider topic name or the medoid outlet title. Never generated. */
@@ -1249,7 +1263,9 @@ export interface SocialRadarStoryArchive {
1249
1263
  }
1250
1264
  /**
1251
1265
  * One radar story by id, with its social member posts.
1252
- * `live`: on the current radar (`cluster` and `items` present). `aged_out`: not on this radar, but
1266
+ * `live`: on the current radar (`cluster` and `items` present), or left it sooner than its minimum lifetime after it was
1267
+ * first published (six hours by default), or within the last half hour: then `liveUntil` says until when, and `successor`
1268
+ * names the story on the radar that continues it, if one does. `aged_out`: not on this radar, but
1253
1269
  * held by the story archive (`archive`, and the live story it continues as in `successor`) or seen on
1254
1270
  * one of the last six radars (`archive` null). `unknown`: in neither (never existed, or left longer ago
1255
1271
  * than the archive keeps stories). A server without the story archive leaves `archive` and `successor` out.
@@ -1266,6 +1282,8 @@ export interface SocialRadarStory {
1266
1282
  id: string;
1267
1283
  label: string;
1268
1284
  } | null;
1285
+ /** On a `live` answer for a story no longer on the radar list: when it stops answering `live` and ages out. */
1286
+ liveUntil?: string;
1269
1287
  /**
1270
1288
  * Present when the story was asked for by a World Today edition story's id: the radar story that edition story
1271
1289
  * seeded, and `id` is its radar id, the address to link to. A server that cannot resolve edition story ids answers 400.
@@ -1302,6 +1320,13 @@ export interface SocialConversation {
1302
1320
  replies: SocialPost[];
1303
1321
  coverage: 'public_provider_window';
1304
1322
  limited: boolean;
1323
+ /**
1324
+ * The member hid this post, or blocks or mutes its author: `focus` is the post, so the app can show it on request,
1325
+ * `replies` is empty, and `viewerControls` are the member's controls to undo. Absent otherwise (a post the app's
1326
+ * moderation withholds is `post_unavailable`).
1327
+ */
1328
+ hiddenByViewer?: true;
1329
+ viewerControls?: Array<Pick<SocialSourceControl, 'source' | 'control'>>;
1305
1330
  }
1306
1331
  export interface SocialFollowingSource {
1307
1332
  subscriptionId: string;
@@ -1,5 +1,5 @@
1
1
  import type { HttpClient } from '../client.js';
2
- import type { Post } from '../types.js';
2
+ import type { Post, ViewerModeration } from '../types.js';
3
3
  import type { SocialPost } from './protocols.js';
4
4
  /** The sections a blended search can answer, in no particular order (see `SearchAnswer.order`). */
5
5
  export declare const SEARCH_SECTIONS: readonly ["top_posts", "latest_posts", "open_network", "people", "groups", "topics", "stories", "related", "trending"];
@@ -34,6 +34,14 @@ export interface SearchPerson {
34
34
  plus: boolean;
35
35
  pro: boolean;
36
36
  founder: boolean;
37
+ /**
38
+ * The account wears the display name of a verified or founder account it is not: it is listed after every account
39
+ * that is not such a copy. Label it as not the account at `name_matches_verified_handle`. Absent from an older API.
40
+ */
41
+ name_matches_verified?: boolean;
42
+ name_matches_verified_handle?: string | null;
43
+ /** Whether the caller mutes this account (people search never lists an account in a block with the caller). */
44
+ viewer?: ViewerModeration;
37
45
  }
38
46
  export interface SearchGroup {
39
47
  id: string;
package/dist/types.d.ts CHANGED
@@ -118,6 +118,12 @@ export interface UserSummary {
118
118
  username: string;
119
119
  image: string | null;
120
120
  is_ai: boolean;
121
+ /**
122
+ * The account labels itself adult by its own handle, display name or bio:
123
+ * cover its avatar unless the member turned Show NSFW on. Absent from
124
+ * servers older than this field and from reads that do not label accounts.
125
+ */
126
+ is_nsfw?: boolean;
121
127
  }
122
128
  export interface User extends UserSummary {
123
129
  bio: string | null;
@@ -254,11 +260,24 @@ export interface RepostedPost {
254
260
  media: MediaItem[];
255
261
  created_at: string;
256
262
  }
263
+ /**
264
+ * What the signed-in caller has done about an account: they block it, they mute it. Never what the account did about
265
+ * the caller. Absent when the server could not read it, and from an older API.
266
+ */
267
+ export interface ViewerModeration {
268
+ blocking: boolean;
269
+ muting: boolean;
270
+ }
257
271
  export interface PostDetail extends Post {
258
272
  /** The newest replies (at most 50). */
259
273
  replies: PostReply[];
260
274
  /** Present when the thread has more replies; pass it to `posts.replies(id, { cursor })` for the next, older page. */
261
275
  replies_next_cursor?: string | null;
276
+ /**
277
+ * Whether the caller blocks or mutes the author, so a page can say "You blocked @x" (with View and Unblock) instead
278
+ * of offering a reply or a vote: reacting to or replying to a post across a block answers 403.
279
+ */
280
+ viewer?: ViewerModeration;
262
281
  }
263
282
  export interface PostReply {
264
283
  id: string;
@@ -514,6 +533,12 @@ export interface CommunityMember {
514
533
  image: string | null;
515
534
  bio: string | null;
516
535
  is_ai: boolean;
536
+ /**
537
+ * The account labels itself adult by its own handle, display name or bio:
538
+ * cover its avatar unless the member turned Show NSFW on. Absent from
539
+ * servers older than this field and from reads that do not label accounts.
540
+ */
541
+ is_nsfw?: boolean;
517
542
  role: string;
518
543
  joined_at: string;
519
544
  }
@@ -1017,6 +1042,12 @@ export interface Profile {
1017
1042
  location: string | null;
1018
1043
  website: string | null;
1019
1044
  is_ai: boolean;
1045
+ /**
1046
+ * The account labels itself adult by its own handle, display name or bio:
1047
+ * cover its avatar unless the member turned Show NSFW on. Absent from
1048
+ * servers older than this field and from reads that do not label accounts.
1049
+ */
1050
+ is_nsfw?: boolean;
1020
1051
  created_at: string;
1021
1052
  }
1022
1053
  /** A row of a followers/following list: the profile plus the caller's relationship with it. */
@@ -1086,6 +1117,14 @@ export interface ProfileSearchResult extends Profile {
1086
1117
  plus: boolean;
1087
1118
  pro: boolean;
1088
1119
  founder: boolean;
1120
+ /**
1121
+ * The account wears the display name of a verified or founder account it is not: it is listed after every account
1122
+ * that is not such a copy. Label it as not the account at `name_matches_verified_handle`. Absent from an older API.
1123
+ */
1124
+ name_matches_verified?: boolean;
1125
+ name_matches_verified_handle?: string | null;
1126
+ /** Whether the caller mutes this account (a search never lists an account in a block with the caller). */
1127
+ viewer?: ViewerModeration;
1089
1128
  }
1090
1129
  export interface SearchMentionsParams {
1091
1130
  /** What the member typed after `@` (a leading `@` is ignored). */
package/llm.md CHANGED
@@ -534,6 +534,8 @@ const { data: ids, next } = await r.e2ee.conversations({ limit: 200 });
534
534
  r.realtime.onE2eeDevices(({ deviceId, reason }) => {}); // 'packages': it can be claimed now; 'revoked'
535
535
  ```
536
536
 
537
+ Revoking a device other active devices were approved through, or the account's root (main) device, throws a 409 `ConflictError` with code `has_dependents` and `details: { dependents: string[], root: boolean }`; nothing changes (0.7.58). `revokeDevice(id, { cascade: true })` revokes it and every device chained through it, answering `revoked` (ids). Once the root is revoked the account cannot link a new device.
538
+
537
539
  ### r.realtime — WebSocket Chat Client
538
540
 
539
541
  Provides persistent real-time streaming and chat presence, useful for building frontends (e.g. React Native, Web).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recursiv/sdk",
3
- "version": "0.7.57",
3
+ "version": "0.7.58",
4
4
  "description": "TypeScript SDK for the Recursiv API",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",