@recursiv/sdk 0.7.58 → 0.7.59
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 +16 -4
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +12 -0
- package/dist/index.d.ts +7 -6
- package/dist/index.js +2 -2
- package/dist/resources/agents.d.ts +70 -0
- package/dist/resources/agents.js +10 -0
- package/dist/resources/curator.d.ts +5 -1
- package/dist/resources/curator.js +6 -2
- package/dist/resources/discovery.d.ts +83 -1
- package/dist/resources/discovery.js +36 -6
- package/dist/resources/e2ee.d.ts +87 -2
- package/dist/resources/e2ee.js +31 -2
- package/dist/resources/email.d.ts +27 -3
- package/dist/resources/email.js +18 -3
- package/dist/resources/env-vars.d.ts +25 -0
- package/dist/resources/env-vars.js +8 -0
- package/dist/resources/moderation.d.ts +22 -0
- package/dist/resources/moderation.js +16 -0
- package/dist/resources/posts.d.ts +1 -1
- package/dist/resources/posts.js +6 -2
- package/dist/resources/protocols.d.ts +209 -2
- package/dist/resources/protocols.js +57 -1
- package/dist/types.d.ts +50 -0
- package/llm.md +16 -5
- package/package.json +1 -1
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` (`{ 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`) |
|
|
78
|
+
| `r.e2ee` | `status`, `registerDevice`, `devices`, `revokeDevice` (`{ cascade }` to also revoke devices approved through it; 409 `has_dependents` otherwise), `requestResetCode` and `resetAccount` (reset encrypted chat with an emailed code where `status().accountReset`), `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 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` |
|
|
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); the Viral read (fastest-moving posts across Bluesky, the Fediverse, Nostr and Minds, each against its own network's pace; 0.7.59): `getPublicViral({ network?, category?, media?: 'video', limit?: 5 | 10 | 20 | 40, cursor?, compass? })` under the member's key and keyless `getSharedViral(projectId, params)` (visitors: `compass` `all` or `hide` only; a visitor's `media: 'video'` read can carry items whose video the server withheld, so filter with the exported `viralItemHasVideo` before a video player; `item.post` narrows on `item.protocol`). `status: 'off'` resolves with no items until the app enables the read, and `getSharedViral` also resolves an older API's 401 `missing_api_key` as off; `getPublicViral` throws every 401 and 403, so a session failure is never read as off; 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
|
|
|
@@ -364,7 +364,7 @@ try {
|
|
|
364
364
|
}
|
|
365
365
|
```
|
|
366
366
|
|
|
367
|
-
Auto-retry is built in. 429 and 5xx responses retry with exponential backoff (configurable via `maxRetries`, default 2). A 429 with `X-RateLimit-Scope: action` refuses one member action past its budget and is never retried: its `RateLimitError` has `scope: 'action'` and `resetAt` (a `Date`, when that action's budget reopens).
|
|
367
|
+
Auto-retry is built in. 429 and 5xx responses retry with exponential backoff (configurable via `maxRetries`, default 2). A 429 with `X-RateLimit-Scope: action` refuses one member action past its budget and is never retried: its `RateLimitError` has `scope: 'action'` and `resetAt` (a `Date`, when that action's budget reopens). A read that holds its own deadline can ask once with `retry: false` in its params: `r.posts.list({ ...params, retry: false })` and `r.curator.forYou({ ...params, retry: false })` throw the first 5xx or 429 with no retry and no `Retry-After` sleep, and never send `retry` to the server.
|
|
368
368
|
|
|
369
369
|
## Pagination
|
|
370
370
|
|
|
@@ -664,6 +664,14 @@ and says whether the member is personalized yet (`meta.personalized`). With a
|
|
|
664
664
|
`category` (the member's first), the session also reads open-network posts from it;
|
|
665
665
|
without, it is Minds only. It never carries the radar.
|
|
666
666
|
|
|
667
|
+
Both take a Politics choice, `compass` (`all`, `mix`, `hide`, or cells in the order
|
|
668
|
+
`lo,co,ro,lm,cm,rm,ll,cl,rl`, optionally `np`), and send it with every Minds read
|
|
669
|
+
(`posts.list` and `curator.forYou` take it too). Each such page says what it did in
|
|
670
|
+
`meta.compass_filter` (`status` `applied` or `unavailable`, and counts only), and each session
|
|
671
|
+
page carries its Minds read's answer as `page.compass` (`unavailable`: the page is unfiltered). Only Minds
|
|
672
|
+
posts are filtered, so a view that leaves posts out reads best with `source: 'minds'`.
|
|
673
|
+
The catalog lists `compass_filter` on every network when the filter is served to the viewer.
|
|
674
|
+
|
|
667
675
|
`sdk.discovery.recommendations({ kind, category?, limit?, session?, exclude? })` is
|
|
668
676
|
the app's one recommender for suggestion rails: `kind` is `member`, `group`, `tag`,
|
|
669
677
|
`network_account` or `story`, and `category` is `all` or a browse category id. It
|
|
@@ -689,7 +697,11 @@ category, refreshed after 30 s, kept up to 300 s and warmed as the warmer reache
|
|
|
689
697
|
viewer's `people` and `groups`; a section that timed out, failed or is off is empty with a
|
|
690
698
|
`reason` for that request only (a failure is never cached, so asking again retries it), and one this
|
|
691
699
|
key may not read is empty with `refused` (`stories` and `network` need the member's own app
|
|
692
|
-
key with `users:read`; `people` and `groups` need `users:read`).
|
|
700
|
+
key with `users:read`; `people` and `groups` need `users:read`). `sdk.discovery.videos({ category?, limit?, cursor?, offset? })`
|
|
701
|
+
is Watch's Minds read: the app's public video posts in hot order, from one list the server shares among every viewer of
|
|
702
|
+
the app and rebuilds about once a minute, each post checked again on every call under the public floors and the viewer's
|
|
703
|
+
blocks and mutes, in the `Post` shape with the viewer's own `user_reaction` and `reposted_by_viewer_id` (page on
|
|
704
|
+
`meta.next_cursor`; a feed session's Minds slot can read it as its `list`). A plain category page
|
|
693
705
|
(`posts.list({ category })` with no other filter) reads on past a slice the safety floors
|
|
694
706
|
thinned, up to six reads, until it holds `limit` posts or its candidates end: `meta.scanned`
|
|
695
707
|
is how many it examined (the next offset is `offset + scanned`), and the stage ends on the
|
package/dist/errors.d.ts
CHANGED
|
@@ -84,3 +84,16 @@ export declare class RateLimitError extends RecursivError {
|
|
|
84
84
|
export declare class ConflictError extends RecursivError {
|
|
85
85
|
constructor(body: ApiErrorBody['error']);
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* `email.send` answered 200 but sent to nobody: every recipient was held
|
|
89
|
+
* (no marketing consent, suppressed, preference off). Thrown so a caller that
|
|
90
|
+
* only checks for success cannot report mail as sent. `details` carries the
|
|
91
|
+
* per-recipient `messages` with each `reason`.
|
|
92
|
+
*/
|
|
93
|
+
export declare class EmailNotSentError extends RecursivError {
|
|
94
|
+
constructor(body: {
|
|
95
|
+
message: string;
|
|
96
|
+
hint?: string;
|
|
97
|
+
details?: unknown;
|
|
98
|
+
});
|
|
99
|
+
}
|
package/dist/errors.js
CHANGED
|
@@ -189,3 +189,15 @@ export class ConflictError extends RecursivError {
|
|
|
189
189
|
this.name = 'ConflictError';
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* `email.send` answered 200 but sent to nobody: every recipient was held
|
|
194
|
+
* (no marketing consent, suppressed, preference off). Thrown so a caller that
|
|
195
|
+
* only checks for success cannot report mail as sent. `details` carries the
|
|
196
|
+
* per-recipient `messages` with each `reason`.
|
|
197
|
+
*/
|
|
198
|
+
export class EmailNotSentError extends RecursivError {
|
|
199
|
+
constructor(body) {
|
|
200
|
+
super(200, { type: 'email_not_sent', code: 'email_held', message: body.message, hint: body.hint, details: body.details });
|
|
201
|
+
this.name = 'EmailNotSentError';
|
|
202
|
+
}
|
|
203
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -154,12 +154,12 @@ 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, E2eeHasDependentsDetails, E2eeKeyPackageStatus, E2eeLink, E2eeLinkCancelledBy, E2eeLinkProgress, E2eeLinkRealtimeEvent, E2eeLinkState, E2eeObjectDownload, E2eeObjectUpload, E2eeRealtimeEvent, E2eeRevokeResponse, E2eeStatus, E2eeStatusReason, } from './resources/e2ee.js';
|
|
157
|
+
export type { E2eeAccountReset, E2eeDevice, E2eeDevicesRealtimeEvent, E2eeEnvelope, E2eeEvent, E2eeHasDependentsDetails, E2eeKeyPackageStatus, E2eeLink, E2eeLinkCancelledBy, E2eeLinkProgress, E2eeLinkRealtimeEvent, E2eeLinkState, E2eeObjectDownload, E2eeObjectUpload, E2eeRealtimeEvent, E2eeResetCodeSent, E2eeResetErrorCode, 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';
|
|
161
161
|
export type { EvidenceTarget, EvalType, CreateEvalInput, SimulateInput, SimulateResult, EvalRunRow, EvalResultRow, EvalRunDetail, EvidenceSummary, EvidenceEvent, EvidenceRecordDetail } from './resources/evidence.js';
|
|
162
|
-
export type { AgentMessage, AgentMessageInput, AgentInboxParams, SupportedModel, SalesLead, SalesLeadListParams, SalesLeadStatus } from './resources/agents.js';
|
|
162
|
+
export type { AgentMessage, AgentMessageInput, AgentInboxParams, AgentAskInput, AgentAskResult, SupportedModel, SalesLead, SalesLeadListParams, SalesLeadStatus } from './resources/agents.js';
|
|
163
163
|
export { TagsResource } from './resources/tags.js';
|
|
164
164
|
export { SandboxResource } from './resources/sandbox.js';
|
|
165
165
|
export { ProfilesResource } from './resources/profiles.js';
|
|
@@ -173,6 +173,7 @@ export { InviteCodesResource } from './resources/invite-codes.js';
|
|
|
173
173
|
export { InviteCodesAdminResource } from './resources/invite-codes-admin.js';
|
|
174
174
|
export { AdminResource } from './resources/admin.js';
|
|
175
175
|
export { EmailResource } from './resources/email.js';
|
|
176
|
+
export type { SendEmailInput, SendEmailResult, SendEmailMessage } from './resources/email.js';
|
|
176
177
|
export { StorageResource } from './resources/storage.js';
|
|
177
178
|
export { DatabasesResource } from './resources/databases.js';
|
|
178
179
|
export { EnvVarsResource } from './resources/env-vars.js';
|
|
@@ -194,7 +195,7 @@ export type { CuratorSource, CuratorPrompt, CuratorRunInput, CuratorRunResult, C
|
|
|
194
195
|
export { ReportsResource } from './resources/reports.js';
|
|
195
196
|
export type { ReportTargetType, ReportStatus, CreateReportInput, ReportRecord, ResolveReportInput, } from './resources/reports.js';
|
|
196
197
|
export { ModerationResource } from './resources/moderation.js';
|
|
197
|
-
export type { ModerationTargetType, ModerationActionType, ModerationAppealStatus, ModerationPrinciple, PublicModerationAction, PublicModerationLog, OwnModerationAppeal, OwnModerationAction, OwnModerationLog, ApplyModerationActionInput, } from './resources/moderation.js';
|
|
198
|
+
export type { ModerationTargetType, ModerationActionType, ModerationAppealStatus, ModerationPrinciple, PublicModerationAction, PublicModerationLog, OwnModerationAppeal, OwnModerationAction, OwnModerationLog, ApplyModerationActionInput, AgentModerationMode, AgentModerationGrant, } from './resources/moderation.js';
|
|
198
199
|
export { LinkPreviewResource } from './resources/link-preview.js';
|
|
199
200
|
export { SEARCH_SECTIONS, SearchResource } from './resources/search.js';
|
|
200
201
|
export type { SearchAnswer, SearchGroup, SearchOmitReason, SearchParams, SearchPerson, SearchRelated, SearchResponse, SearchSection, SearchStory, SearchTopic } from './resources/search.js';
|
|
@@ -214,8 +215,8 @@ export type { LinkedTokenWallet, PayoutState, TokenBalance, TokenLedgerEntry } f
|
|
|
214
215
|
export { BoostsResource } from './resources/boosts.js';
|
|
215
216
|
export type { BoostBalance, BoostBalanceResponse, BoostCampaign, BoostCampaignResponse, BoostEventResult, BoostLedgerEntry, BoostLedgerKind, BoostPlanCredit, BoostRejectionReason, BoostReviewStatus, BoostStatus, BoostTopupCheckout, BoostTopupConfirmation, BoostTopupLimits, } from './resources/boosts.js';
|
|
216
217
|
export { ProtocolsResource } from './resources/protocols.js';
|
|
217
|
-
export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, } from './resources/protocols.js';
|
|
218
|
-
export type { SocialProfile, SocialSubscription, SocialSubscriptionChange, SocialProfilePage, SocialRadar, SocialRadarCluster, SocialRadarMember, SocialRadarParams, SocialRadarPosts, SocialRadarStory, SocialRadarStoryArchive, SocialNetwork, SocialPost, SocialConversation, SocialTrend, SocialTrendProvenance, SocialTrends, SocialTrendSourceIndex, SocialTrendFeed, SocialPopularProfiles, SocialAuthorFeed, SocialFollowingFeed, SocialFollowingSource, SearchPublicProfilesParams, SearchPublicPostsParams, SocialPostSearch, HostedProtocolConnections, HostedProtocol, HostedProtocolIdentity, HostedNostrChallenge, HostedNostrIdentityProof, NativeNostrPrepareInput, NativeNostrPrepared, NativeNostrAccount, NativeNostrPostState, NativeNostrReceipt, NativeSocialProtocol, FederationIdentity, FederationIdentityView, NativeSocialAccount, NativeSocialCallbackInput, NativeReplyPrepareInput, NativePostPrepareInput, NativeMediaInput, NativeMediaItem, NativePostBatch, NativePostHistory, NativeDelegatedPostHistoryItem, NativeNostrPostHistoryItem, NativeFollowSourceInput, NativeFollowPrepareInput, NativeFollowTarget, NativeFollowReceipt, NativeFollowState, NativeFollowAccount, NativeFollowStates, NativeFollowReview, NativeLikeSourceInput, NativeRepostSourceInput, NativeLikePrepareInput, NativeRepostPrepareInput, NativeLikeTarget, NativeRepostTarget, NativeLikeReceipt, NativeRepostReceipt, NativeLikeState, NativeRepostState, NativeLikeReview, NativeRepostReview, NativeReplyReceipt, NativeReplyBatch, NativeReplyHistory, NativeDelegatedReplyHistoryItem, NativeNostrReplyResult, NativeNostrReplyHistoryItem, NativeReplyRemovalReceipt, NativeReplyRemovalPreview, SocialSourceRef, SocialSourceControl, SocialSourceControlDisplay, SocialSourceControlChange, HostedPostPreview, ConnectHostedIdentityInput, CreateHostedIdentityInput, CreatedHostedProtocolIdentity, PreviewHostedPostInput, PublishHostedPostInput, ListProtocolCandidatesParams, ProtocolAdapterMaturity, ProtocolAdapterMetadata, ProtocolCandidateListResponse, ProtocolCandidatePageMeta, ProtocolCapabilityOperation, ProtocolCapabilityStatus, ProtocolCollectionStatus, ProtocolIngestionReplayResult, ProtocolIngestionStatus, ProtocolQuarantinedCandidate, ProtocolRefreshResult, ProtocolSettings, ProtocolSettingsUpdateResult, ReplayProtocolIngestionJobInput, UpdateSettingsInput as UpdateProtocolSettingsInput, } from './resources/protocols.js';
|
|
218
|
+
export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, viralItemHasVideo, } from './resources/protocols.js';
|
|
219
|
+
export type { SocialProfile, SocialBridge, SocialSubscription, SocialSubscriptionChange, SocialProfilePage, SocialRadar, SocialRadarCluster, SocialRadarMember, SocialRadarParams, SocialRadarPosts, SocialRadarStory, SocialRadarStoryArchive, ViralBaseline, ViralItem, ViralItemFields, ViralItemSpread, ViralItemVelocity, ViralLabel, ViralMindsCard, ViralMindsItem, ViralNetwork, ViralOpenProtocol, ViralProtocol, ViralProvider, ViralReadMeta, ViralReadParams, ViralReadResponse, ViralReadStatus, ViralRef, ViralSocialItem, SocialNetwork, SocialPost, SocialConversation, SocialTrend, SocialTrendProvenance, SocialTrends, SocialTrendSourceIndex, SocialTrendFeed, SocialPopularProfiles, SocialAuthorFeed, SocialFollowingFeed, SocialFollowingSource, SearchPublicProfilesParams, SearchPublicPostsParams, SocialPostSearch, HostedProtocolConnections, HostedProtocol, HostedProtocolIdentity, HostedNostrChallenge, HostedNostrIdentityProof, NativeNostrPrepareInput, NativeNostrPrepared, NativeNostrAccount, NativeNostrPostState, NativeNostrReceipt, NativeSocialProtocol, FederationIdentity, FederationIdentityView, NativeSocialAccount, NativeSocialCallbackInput, NativeReplyPrepareInput, NativePostPrepareInput, NativeMediaInput, NativeMediaItem, NativePostBatch, NativePostHistory, NativeDelegatedPostHistoryItem, NativeNostrPostHistoryItem, NativeFollowSourceInput, NativeFollowPrepareInput, NativeFollowTarget, NativeFollowReceipt, NativeFollowState, NativeFollowAccount, NativeFollowStates, NativeFollowReview, NativeLikeSourceInput, NativeRepostSourceInput, NativeLikePrepareInput, NativeRepostPrepareInput, NativeLikeTarget, NativeRepostTarget, NativeLikeReceipt, NativeRepostReceipt, NativeLikeState, NativeRepostState, NativeLikeReview, NativeRepostReview, NativeReplyReceipt, NativeReplyBatch, NativeReplyHistory, NativeDelegatedReplyHistoryItem, NativeNostrReplyResult, NativeNostrReplyHistoryItem, NativeReplyRemovalReceipt, NativeReplyRemovalPreview, SocialSourceRef, SocialSourceControl, SocialSourceControlDisplay, SocialSourceControlChange, HostedPostPreview, ConnectHostedIdentityInput, CreateHostedIdentityInput, CreatedHostedProtocolIdentity, PreviewHostedPostInput, PublishHostedPostInput, ListProtocolCandidatesParams, ProtocolAdapterMaturity, ProtocolAdapterMetadata, ProtocolCandidateListResponse, ProtocolCandidatePageMeta, ProtocolCapabilityOperation, ProtocolCapabilityStatus, ProtocolCollectionStatus, ProtocolIngestionReplayResult, ProtocolIngestionStatus, ProtocolQuarantinedCandidate, ProtocolRefreshResult, ProtocolSettings, ProtocolSettingsUpdateResult, ReplayProtocolIngestionJobInput, UpdateSettingsInput as UpdateProtocolSettingsInput, } from './resources/protocols.js';
|
|
219
220
|
export { InboxResource } from './resources/inbox.js';
|
|
220
221
|
export { NetworkResource } from './resources/network.js';
|
|
221
222
|
export { SimulatorResource } from './resources/simulator.js';
|
|
@@ -240,7 +241,7 @@ export { TemplatesResource } from './resources/templates.js';
|
|
|
240
241
|
export type { Template, CreateTemplateInput, UpdateTemplateInput, ListTemplatesParams } from './resources/templates.js';
|
|
241
242
|
export { MediaResource } from './resources/media.js';
|
|
242
243
|
export type { GenerateImageInput, GeneratedImage, ImageProvider } from './resources/media.js';
|
|
243
|
-
export { RecursivError, AuthenticationError, AuthorizationError, LegacyHandoffError, NotFoundError, ValidationError, InsufficientCreditsError, RateLimitError, ConflictError, isActionRateLimitScope, } from './errors.js';
|
|
244
|
+
export { RecursivError, AuthenticationError, AuthorizationError, LegacyHandoffError, NotFoundError, ValidationError, InsufficientCreditsError, RateLimitError, ConflictError, isActionRateLimitScope, EmailNotSentError, } from './errors.js';
|
|
244
245
|
export type { RateLimitDetails } from './errors.js';
|
|
245
246
|
export { parseSSE } from './lib/sse.js';
|
|
246
247
|
export * from './lib/webhooks.js';
|
package/dist/index.js
CHANGED
|
@@ -261,7 +261,7 @@ export { UploadsResource } from './resources/uploads.js';
|
|
|
261
261
|
export { WalletResource } from './resources/wallet.js';
|
|
262
262
|
export { BoostsResource } from './resources/boosts.js';
|
|
263
263
|
export { ProtocolsResource } from './resources/protocols.js';
|
|
264
|
-
export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, } from './resources/protocols.js';
|
|
264
|
+
export { PROTOCOL_ADAPTER_MATURITIES, PROTOCOL_CAPABILITY_OPERATIONS, PROTOCOL_CAPABILITY_STATUSES, viralItemHasVideo, } from './resources/protocols.js';
|
|
265
265
|
export { InboxResource } from './resources/inbox.js';
|
|
266
266
|
export { NetworkResource } from './resources/network.js';
|
|
267
267
|
export { SimulatorResource } from './resources/simulator.js';
|
|
@@ -277,6 +277,6 @@ export { HumanInputResource } from './resources/human-input.js';
|
|
|
277
277
|
export { SwarmsResource } from './resources/swarms.js';
|
|
278
278
|
export { TemplatesResource } from './resources/templates.js';
|
|
279
279
|
export { MediaResource } from './resources/media.js';
|
|
280
|
-
export { RecursivError, AuthenticationError, AuthorizationError, LegacyHandoffError, NotFoundError, ValidationError, InsufficientCreditsError, RateLimitError, ConflictError, isActionRateLimitScope, } from './errors.js';
|
|
280
|
+
export { RecursivError, AuthenticationError, AuthorizationError, LegacyHandoffError, NotFoundError, ValidationError, InsufficientCreditsError, RateLimitError, ConflictError, isActionRateLimitScope, EmailNotSentError, } from './errors.js';
|
|
281
281
|
export { parseSSE } from './lib/sse.js';
|
|
282
282
|
export * from './lib/webhooks.js';
|
|
@@ -26,6 +26,68 @@ export interface AgentInboxParams {
|
|
|
26
26
|
limit?: number;
|
|
27
27
|
offset?: number;
|
|
28
28
|
}
|
|
29
|
+
export interface AgentAskInput {
|
|
30
|
+
organization_id: string;
|
|
31
|
+
/** The person whose agent you are asking: name, first name, @username, email or user id. */
|
|
32
|
+
owner: string;
|
|
33
|
+
question: string;
|
|
34
|
+
/** How far back to read their record (1-90, default 7). */
|
|
35
|
+
since_days?: number;
|
|
36
|
+
/** false = read the record only, leave nothing in their agent's inbox. */
|
|
37
|
+
deliver?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface AgentAskResult {
|
|
40
|
+
owner: {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string | null;
|
|
43
|
+
username: string | null;
|
|
44
|
+
};
|
|
45
|
+
agents: Array<{
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
client: string | null;
|
|
49
|
+
}>;
|
|
50
|
+
window: {
|
|
51
|
+
since: string;
|
|
52
|
+
days: number;
|
|
53
|
+
};
|
|
54
|
+
record: {
|
|
55
|
+
claims: Array<{
|
|
56
|
+
task_id: string;
|
|
57
|
+
task_title: string;
|
|
58
|
+
task_status: string;
|
|
59
|
+
agent: string;
|
|
60
|
+
claim_status: string;
|
|
61
|
+
claimed_at: string;
|
|
62
|
+
completed_at: string | null;
|
|
63
|
+
released_at: string | null;
|
|
64
|
+
release_reason: string | null;
|
|
65
|
+
notes: string | null;
|
|
66
|
+
context_handoff: string | null;
|
|
67
|
+
pr_urls: string[] | null;
|
|
68
|
+
commits: string[] | null;
|
|
69
|
+
}>;
|
|
70
|
+
decisions: Array<{
|
|
71
|
+
id: string;
|
|
72
|
+
decision: string;
|
|
73
|
+
context: string | null;
|
|
74
|
+
tags: string[] | null;
|
|
75
|
+
project_id: string | null;
|
|
76
|
+
created_at: string;
|
|
77
|
+
}>;
|
|
78
|
+
};
|
|
79
|
+
question: {
|
|
80
|
+
delivered: true;
|
|
81
|
+
message_id: string;
|
|
82
|
+
to_agent_id: string;
|
|
83
|
+
to_agent_name: string;
|
|
84
|
+
from_agent_id: string;
|
|
85
|
+
} | {
|
|
86
|
+
delivered: false;
|
|
87
|
+
reason: string;
|
|
88
|
+
};
|
|
89
|
+
how_to_answer: string;
|
|
90
|
+
}
|
|
29
91
|
export interface AgentLeaderboardParams extends PaginationParams {
|
|
30
92
|
organization_id?: string;
|
|
31
93
|
}
|
|
@@ -264,6 +326,14 @@ export declare class AgentsResource {
|
|
|
264
326
|
}>>;
|
|
265
327
|
/** Send a direct message to an agent */
|
|
266
328
|
sendMessage(toAgentId: string, input: AgentMessageInput): Promise<SingleResponse<AgentMessage>>;
|
|
329
|
+
/**
|
|
330
|
+
* Ask a teammate's agent by naming its owner ("bill", "@ottman", an email).
|
|
331
|
+
* Returns that person's agents' work in the organization over the window
|
|
332
|
+
* (task claims with notes, handoffs, PRs and commits; decisions) and leaves
|
|
333
|
+
* the question in their agent's inbox; its reply arrives in yours as a
|
|
334
|
+
* `result` message with `metadata.in_reply_to`.
|
|
335
|
+
*/
|
|
336
|
+
ask(input: AgentAskInput): Promise<SingleResponse<AgentAskResult>>;
|
|
267
337
|
/** Get an agent's inbox (messages sent to them) */
|
|
268
338
|
inbox(agentId: string, params?: AgentInboxParams): Promise<SingleResponse<AgentMessage[]>>;
|
|
269
339
|
/** Get unread message count for an agent */
|
package/dist/resources/agents.js
CHANGED
|
@@ -172,6 +172,16 @@ export class AgentsResource {
|
|
|
172
172
|
sendMessage(toAgentId, input) {
|
|
173
173
|
return this.client.post(`/agents/${toAgentId}/messages`, input);
|
|
174
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Ask a teammate's agent by naming its owner ("bill", "@ottman", an email).
|
|
177
|
+
* Returns that person's agents' work in the organization over the window
|
|
178
|
+
* (task claims with notes, handoffs, PRs and commits; decisions) and leaves
|
|
179
|
+
* the question in their agent's inbox; its reply arrives in yours as a
|
|
180
|
+
* `result` message with `metadata.in_reply_to`.
|
|
181
|
+
*/
|
|
182
|
+
ask(input) {
|
|
183
|
+
return this.client.post('/agents/ask', input);
|
|
184
|
+
}
|
|
175
185
|
/** Get an agent's inbox (messages sent to them) */
|
|
176
186
|
inbox(agentId, params) {
|
|
177
187
|
return this.client.get(`/agents/${agentId}/inbox`, params);
|
|
@@ -11,6 +11,10 @@ export type ForYouParams = {
|
|
|
11
11
|
discovery?: boolean;
|
|
12
12
|
/** `discover` ranks for Discover: fresher, beyond the member's follows, with their category order. */
|
|
13
13
|
surface?: ForYouSurface;
|
|
14
|
+
/** A Politics choice, as `posts.list` takes it (`ListPostsParams.compass`); the page says what it did in `meta.compass_filter`. */
|
|
15
|
+
compass?: string;
|
|
16
|
+
/** `false` asks once and is never sent, as `posts.list` takes it (`ListPostsParams.retry`). */
|
|
17
|
+
retry?: boolean;
|
|
14
18
|
};
|
|
15
19
|
export interface ForYouMeta extends PaginationMeta {
|
|
16
20
|
discovery?: DiscoveryLayout;
|
|
@@ -269,7 +273,7 @@ export declare class CuratorResource {
|
|
|
269
273
|
* affinity, no model calls). Returns posts in the same shape as
|
|
270
274
|
* `sdk.posts.list()`, so any feed UI renders it unchanged. Requires a
|
|
271
275
|
* project-scoped key (the feed is per-app). Servers that predate `cursor`,
|
|
272
|
-
* `discovery` and `surface` ignore them.
|
|
276
|
+
* `discovery` and `surface` ignore them. `retry: false` asks once and is never sent (`ListPostsParams.retry`).
|
|
273
277
|
*/
|
|
274
278
|
forYou(params?: ForYouParams): Promise<PaginatedResponse<Post> & {
|
|
275
279
|
meta: ForYouMeta;
|
|
@@ -48,9 +48,13 @@ export class CuratorResource {
|
|
|
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
50
|
* project-scoped key (the feed is per-app). Servers that predate `cursor`,
|
|
51
|
-
* `discovery` and `surface` ignore them.
|
|
51
|
+
* `discovery` and `surface` ignore them. `retry: false` asks once and is never sent (`ListPostsParams.retry`).
|
|
52
52
|
*/
|
|
53
53
|
forYou(params = {}) {
|
|
54
|
-
|
|
54
|
+
// Without `retry`, the same request older SDKs make.
|
|
55
|
+
if (!('retry' in params))
|
|
56
|
+
return this.client.get('/curator/foryou', params);
|
|
57
|
+
const { retry, ...query } = params;
|
|
58
|
+
return retry === false ? this.client.get('/curator/foryou', query, { retry: false }) : this.client.get('/curator/foryou', query);
|
|
55
59
|
}
|
|
56
60
|
}
|
|
@@ -1,10 +1,69 @@
|
|
|
1
1
|
import type { HttpClient } from '../client.js';
|
|
2
|
-
import type { DiscoveryLayout, FalloverStep, Post } from '../types.js';
|
|
2
|
+
import type { CompassFilterMeta, DiscoveryLayout, FalloverStep, MediaItem, Post } from '../types.js';
|
|
3
3
|
import type { CuratorResource } from './curator.js';
|
|
4
4
|
import type { DiscoveryLearning } from './discovery-learning.js';
|
|
5
5
|
import type { PostsResource } from './posts.js';
|
|
6
6
|
import type { ProtocolsResource, SocialNetwork, SocialPost, SocialRadar, SocialRadarPosts } from './protocols.js';
|
|
7
7
|
export type DiscoveryRecommendationKind = 'groups' | 'people' | 'tags';
|
|
8
|
+
/** A page of Watch's Minds videos (`discovery.videos`). */
|
|
9
|
+
export interface WatchVideosParams {
|
|
10
|
+
/** A browse category id: the videos among the category's judged posts. Omitted: the whole app. */
|
|
11
|
+
category?: string;
|
|
12
|
+
/** Posts per page, 1 to 25 (default 12). */
|
|
13
|
+
limit?: number;
|
|
14
|
+
/** The `meta.next_cursor` of the page before. */
|
|
15
|
+
cursor?: string;
|
|
16
|
+
/** A position in the list to start a first read at (0 to 400); a later page sends `cursor`. */
|
|
17
|
+
offset?: number;
|
|
18
|
+
}
|
|
19
|
+
/** A media item as `discovery.videos` serves it: the poster, and the player's size, length and HLS address when known. */
|
|
20
|
+
export interface WatchVideoMedia extends MediaItem {
|
|
21
|
+
thumbnail_url: string | null;
|
|
22
|
+
/** Set while the file is not ready on the CDN; absent once it is. */
|
|
23
|
+
status?: string;
|
|
24
|
+
width?: number;
|
|
25
|
+
height?: number;
|
|
26
|
+
duration_sec?: number;
|
|
27
|
+
hls_url?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A post as `discovery.videos` serves it: the `Post` shape (so a page is a valid `posts.list` page), with the engagement
|
|
31
|
+
* GET /posts sends (live votes plus imported likes, the replies the reader can open) and the viewer's own vote and repost.
|
|
32
|
+
*/
|
|
33
|
+
export interface WatchVideoPost extends Post {
|
|
34
|
+
title: string | null;
|
|
35
|
+
is_nsfw: boolean;
|
|
36
|
+
score: number;
|
|
37
|
+
upvote_count: number;
|
|
38
|
+
downvote_count: number;
|
|
39
|
+
/** The viewer's own reaction ('upvote', 'downvote', ...); null for a visitor or when they have none. */
|
|
40
|
+
user_reaction: string | null;
|
|
41
|
+
reply_count: number;
|
|
42
|
+
reply_count_external: number;
|
|
43
|
+
unique_commenters: number;
|
|
44
|
+
reposts_count: number;
|
|
45
|
+
/** Id of the viewer's own repost of the post; delete it to undo the repost. */
|
|
46
|
+
reposted_by_viewer_id: string | null;
|
|
47
|
+
media: WatchVideoMedia[];
|
|
48
|
+
}
|
|
49
|
+
export interface WatchVideosResponse {
|
|
50
|
+
/** Public Minds video posts in hot order (with the viewer's own `user_reaction` and `reposted_by_viewer_id`). */
|
|
51
|
+
data: WatchVideoPost[];
|
|
52
|
+
meta: {
|
|
53
|
+
limit: number;
|
|
54
|
+
/** The position in the list this page started at. */
|
|
55
|
+
offset: number;
|
|
56
|
+
has_more: boolean;
|
|
57
|
+
/** Pass as `cursor` for the next page; null at the end of the list. */
|
|
58
|
+
next_cursor: string | null;
|
|
59
|
+
/** Positions in the list this page examined (a client paging by offset adds it to the offset). */
|
|
60
|
+
scanned: number;
|
|
61
|
+
/** When the shared list the page was cut from was built; null when the app has none. */
|
|
62
|
+
built_at: string | null;
|
|
63
|
+
/** `no_app`: the API key is bound to no app, so there is no list. */
|
|
64
|
+
reason?: 'no_app';
|
|
65
|
+
};
|
|
66
|
+
}
|
|
8
67
|
/** What GET /discover/recommendations suggests: members, groups, tags, open-network accounts or World Today stories. */
|
|
9
68
|
export type EntityKind = 'member' | 'group' | 'tag' | 'network_account' | 'story';
|
|
10
69
|
/**
|
|
@@ -280,6 +339,12 @@ export interface DiscoveryFeedPage {
|
|
|
280
339
|
* on servers that predate it.
|
|
281
340
|
*/
|
|
282
341
|
fallover?: FalloverStep[];
|
|
342
|
+
/**
|
|
343
|
+
* What the session's Politics choice (`compass`, createFeed and createPersonalFeed) did to this page's Minds read:
|
|
344
|
+
* that read's `meta.compass_filter`, counts only. `unavailable` means the page was served unfiltered. Absent without
|
|
345
|
+
* a choice, on a page whose Minds read failed or was not made, and on servers that predate the filter.
|
|
346
|
+
*/
|
|
347
|
+
compass?: CompassFilterMeta;
|
|
283
348
|
}
|
|
284
349
|
/** A gallery strip holds up to twelve image posts gathered from the whole page. */
|
|
285
350
|
export declare const GALLERY_MAX_ITEMS = 12;
|
|
@@ -369,6 +434,16 @@ export declare class DiscoveryResource {
|
|
|
369
434
|
}, options?: {
|
|
370
435
|
retry?: boolean;
|
|
371
436
|
}): Promise<CategorySurfaceResponse>;
|
|
437
|
+
/**
|
|
438
|
+
* Watch's Minds videos for the viewer: the app's public video posts in hot order (engagement decayed by age), from
|
|
439
|
+
* one list the server shares among every viewer of the app and rebuilds about once a minute, each post checked again
|
|
440
|
+
* on every read under the public floors (not NSFW, removed or hidden; no spam-labelled or adult author or group; the
|
|
441
|
+
* cached safety verdict) and the viewer's blocks and mutes. A video whose file is gone or not on the CDN yet is left
|
|
442
|
+
* out or marked `unplayable`. Page on `meta.next_cursor`. Needs posts:read; the app is the API key's project.
|
|
443
|
+
*/
|
|
444
|
+
videos(params?: WatchVideosParams, options?: {
|
|
445
|
+
retry?: boolean;
|
|
446
|
+
}): Promise<WatchVideosResponse>;
|
|
372
447
|
/**
|
|
373
448
|
* A For you Discover feed: the member's For You ranking (asked for Discover's surface, with layouts and a
|
|
374
449
|
* snapshot cursor) in a session's Minds slot. With a category, the session also reads open-network posts
|
|
@@ -380,12 +455,19 @@ export declare class DiscoveryResource {
|
|
|
380
455
|
learning?: DiscoveryLearning;
|
|
381
456
|
recommend?: DiscoveryRecommendationSources;
|
|
382
457
|
category?: string;
|
|
458
|
+
compass?: string;
|
|
383
459
|
}): DiscoveryFeedSession;
|
|
460
|
+
/**
|
|
461
|
+
* Discover's feed session. `compass` (a Politics choice, as `posts.list` takes it) goes on every Minds read, whose
|
|
462
|
+
* pages then carry `meta.compass_filter`; the open networks' reads and the radar are not filtered by it, so a view
|
|
463
|
+
* that leaves posts out (Hide politics, Choose sides) is best read with `source: 'minds'`.
|
|
464
|
+
*/
|
|
384
465
|
createFeed(options: {
|
|
385
466
|
networks: SocialNetwork[];
|
|
386
467
|
category?: string;
|
|
387
468
|
source?: string;
|
|
388
469
|
learning?: DiscoveryLearning;
|
|
389
470
|
recommend?: DiscoveryRecommendationSources;
|
|
471
|
+
compass?: string;
|
|
390
472
|
}): DiscoveryFeedSession;
|
|
391
473
|
}
|
|
@@ -191,7 +191,12 @@ export class DiscoveryFeedSession {
|
|
|
191
191
|
if (stream.protocol === 'minds') {
|
|
192
192
|
// Discover leads with what is moving now: the REST hot order (engagement
|
|
193
193
|
// decayed by age). Hot pages by offset; the server sends no cursor for it.
|
|
194
|
-
|
|
194
|
+
// Asked once, as the open networks are: a 503 retried twice with its Retry-After ran past this read's 15 s
|
|
195
|
+
// deadline, and the Minds lane failed (Bill 2026-10-01: "couldnt load discover minds posts didnt load"). The
|
|
196
|
+
// opt-out rides in the params (ListPostsParams.retry), which a reader handed to a session forwards to read the
|
|
197
|
+
// right page at all: a second argument was dropped by the Minds app's own wrappers (lib/discoverFeedResource,
|
|
198
|
+
// lib/compassStatus withCompass, lib/watchSource), which pass the params alone (review of #4047).
|
|
199
|
+
const response = await this.posts.list({ ...params, sort: 'hot', ...(stream.cursor ? { cursor: stream.cursor } : { offset: stream.offset }), retry: false });
|
|
195
200
|
stream.offset += response.meta.scanned ?? response.meta.limit;
|
|
196
201
|
const next = response.meta.next_cursor ?? undefined;
|
|
197
202
|
stream.done = !response.meta.has_more || !!next && (next === stream.cursor || stream.used.includes(next));
|
|
@@ -202,7 +207,8 @@ export class DiscoveryFeedSession {
|
|
|
202
207
|
if (Array.isArray(response.meta.fallover))
|
|
203
208
|
stream.fallover = response.meta.fallover;
|
|
204
209
|
return { items: response.data.map(post => ({ key: key('minds', post.id), kind: 'minds', post })),
|
|
205
|
-
layout: response.meta.discovery ?? ordinary, partial: response.meta.category_filter?.status === 'partial'
|
|
210
|
+
layout: response.meta.discovery ?? ordinary, partial: response.meta.category_filter?.status === 'partial',
|
|
211
|
+
...(response.meta.compass_filter ? { compass: response.meta.compass_filter } : {}) };
|
|
206
212
|
}
|
|
207
213
|
const validatePosts = (data) => {
|
|
208
214
|
if (data.coverage !== 'provider_ranked_window' || data.items.length > 25 || data.items.some(post => post.protocol !== stream.protocol || post.author.protocol !== stream.protocol))
|
|
@@ -402,9 +408,11 @@ export class DiscoveryFeedSession {
|
|
|
402
408
|
if (cluster)
|
|
403
409
|
modules.splice(page === 0 ? 0 : Math.min(2, modules.length), 0, this.radarModule(page, cluster, clusterItems));
|
|
404
410
|
const fallover = this.streams.find(stream => stream.protocol === 'minds')?.fallover;
|
|
411
|
+
// Only the Minds read carries what a Politics choice did (the open networks' reads are not filtered by it).
|
|
412
|
+
const compass = reads.find(read => read.compass)?.compass;
|
|
405
413
|
return { modules, hasMore: this.streams.some(stream => !stream.done && !stream.failed),
|
|
406
414
|
failedSources: this.streams.filter(stream => stream.failed).map(stream => stream.protocol), partialCategories: reads.some(read => read.partial),
|
|
407
|
-
...(fallover ? { fallover } : {}) };
|
|
415
|
+
...(fallover ? { fallover } : {}), ...(compass ? { compass } : {}) };
|
|
408
416
|
}
|
|
409
417
|
/** Page 0: the top breaking cluster, else the top cluster. Every second later page: the next unused story or viral cluster. */
|
|
410
418
|
async radarCluster(page) {
|
|
@@ -583,6 +591,18 @@ export class DiscoveryResource {
|
|
|
583
591
|
throw new Error('category needs the HTTP client');
|
|
584
592
|
return this.http.get('/discover/category', params, options);
|
|
585
593
|
}
|
|
594
|
+
/**
|
|
595
|
+
* Watch's Minds videos for the viewer: the app's public video posts in hot order (engagement decayed by age), from
|
|
596
|
+
* one list the server shares among every viewer of the app and rebuilds about once a minute, each post checked again
|
|
597
|
+
* on every read under the public floors (not NSFW, removed or hidden; no spam-labelled or adult author or group; the
|
|
598
|
+
* cached safety verdict) and the viewer's blocks and mutes. A video whose file is gone or not on the CDN yet is left
|
|
599
|
+
* out or marked `unplayable`. Page on `meta.next_cursor`. Needs posts:read; the app is the API key's project.
|
|
600
|
+
*/
|
|
601
|
+
videos(params = {}, options) {
|
|
602
|
+
if (!this.http)
|
|
603
|
+
throw new Error('videos needs the HTTP client');
|
|
604
|
+
return this.http.get('/discover/videos', { ...params }, options);
|
|
605
|
+
}
|
|
586
606
|
/**
|
|
587
607
|
* A For you Discover feed: the member's For You ranking (asked for Discover's surface, with layouts and a
|
|
588
608
|
* snapshot cursor) in a session's Minds slot. With a category, the session also reads open-network posts
|
|
@@ -593,10 +613,13 @@ export class DiscoveryResource {
|
|
|
593
613
|
const curator = this.curator;
|
|
594
614
|
if (!curator)
|
|
595
615
|
throw new Error('createPersonalFeed needs the curator resource');
|
|
616
|
+
const compass = options.compass;
|
|
596
617
|
const list = {
|
|
597
|
-
// The session's `sort` and `category` are Discover's hot-order knobs; the ranker ignores them.
|
|
618
|
+
// The session's `sort` and `category` are Discover's hot-order knobs; the ranker ignores them. A Politics choice
|
|
619
|
+
// goes on every ranker read.
|
|
598
620
|
list: async (params) => {
|
|
599
|
-
const response = await curator.forYou({ limit: params?.limit, offset: params?.offset, cursor: params?.cursor, discovery: true, surface: 'discover'
|
|
621
|
+
const response = await curator.forYou({ limit: params?.limit, offset: params?.offset, cursor: params?.cursor, discovery: true, surface: 'discover',
|
|
622
|
+
...(compass ? { compass } : {}), ...(params?.retry === undefined ? {} : { retry: params.retry }) });
|
|
600
623
|
// A server that predates the cursor says has_more: false on a partial ranked page although its
|
|
601
624
|
// continuation serves the next offset. A cursor-aware server always says `personalized`, and its
|
|
602
625
|
// has_more is the end of the feed.
|
|
@@ -606,9 +629,16 @@ export class DiscoveryResource {
|
|
|
606
629
|
};
|
|
607
630
|
return new DiscoveryFeedSession(list, this.protocols, options.category ? options.networks : [], options.category, options.category ? 'all' : 'minds', options.learning, options.recommend);
|
|
608
631
|
}
|
|
632
|
+
/**
|
|
633
|
+
* Discover's feed session. `compass` (a Politics choice, as `posts.list` takes it) goes on every Minds read, whose
|
|
634
|
+
* pages then carry `meta.compass_filter`; the open networks' reads and the radar are not filtered by it, so a view
|
|
635
|
+
* that leaves posts out (Hide politics, Choose sides) is best read with `source: 'minds'`.
|
|
636
|
+
*/
|
|
609
637
|
createFeed(options) {
|
|
638
|
+
const compass = options.compass;
|
|
639
|
+
const posts = compass ? { list: params => this.posts.list({ ...params, compass }) } : this.posts;
|
|
610
640
|
// The radar rides along by default; an older server answers 404 and the session simply shows no story module.
|
|
611
|
-
return new DiscoveryFeedSession(
|
|
641
|
+
return new DiscoveryFeedSession(posts, this.protocols, options.networks, options.category, options.source, options.learning, options.recommend, params => this.protocols.getPublicRadar(params, NO_RETRY), { social: params => this.protocols.getPublicRadarPosts(params, NO_RETRY), minds: id => this.posts.get(id) });
|
|
612
642
|
}
|
|
613
643
|
}
|
|
614
644
|
/** A read bounded to three seconds; a late or failed one resolves to `fallback`, never an error. */
|