@recursiv/sdk 0.7.123 → 0.7.195

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.
@@ -28,7 +28,22 @@ export const PROTOCOL_ADAPTER_MATURITIES = Object.freeze([
28
28
  'beta',
29
29
  'stable',
30
30
  ]);
31
+ function nostrStepUpBody(stepUp) {
32
+ const password = typeof stepUp?.password === 'string' ? stepUp.password : '';
33
+ const emailCode = typeof stepUp?.emailCode === 'string' ? stepUp.emailCode.trim() : '';
34
+ if (Boolean(password) === Boolean(emailCode)) {
35
+ throw new ValidationError({ type: 'validation_error', code: 'invalid_input', message: 'Send the account password, or the emailed nostr_key code, not both' });
36
+ }
37
+ return password ? { password } : { email_code: emailCode };
38
+ }
31
39
  const NATIVE_NETWORKS = ['activitypub', 'atproto', 'nostr'];
40
+ function engageOneBody(input) {
41
+ if (input.identity !== undefined && input.identity !== 'native' && input.identity !== 'linked') {
42
+ throw new ValidationError({ type: 'validation_error', code: 'invalid_input', message: 'identity must be native or linked' });
43
+ }
44
+ return { clientMutationId: input.clientMutationId, protocol: input.protocol, nativeId: input.nativeId, action: input.action,
45
+ ...(input.identity !== undefined ? { identity: input.identity } : {}), ...(input.accountId !== undefined ? { accountId: input.accountId } : {}) };
46
+ }
32
47
  function nativeNetworkPath(network) {
33
48
  if (!NATIVE_NETWORKS.includes(network)) {
34
49
  throw new ValidationError({ type: 'validation_error', code: 'invalid_network', message: 'network must be activitypub, atproto or nostr' });
@@ -201,6 +216,15 @@ export class ProtocolsResource {
201
216
  throw error;
202
217
  }
203
218
  }
219
+ /**
220
+ * A category's stories, open-network posts and clips for a signed-out visitor, in one keyless read (SharedCategorySurface).
221
+ * The answer is the same for every visitor of the app, category and Politics choice, and the URL carries nothing else,
222
+ * so a shared cache may keep it for 30 s. Only `category` and `compass` are sent: the server refuses any other
223
+ * parameter. An API that predates the route answers 401 `missing_api_key` (it falls through to the keyed routes) or 404.
224
+ */
225
+ getSharedCategorySurface(projectId, params, options) {
226
+ return this.client.get(`/protocols/public/${encodeURIComponent(projectId)}/category`, { category: params.category, ...(params.compass !== undefined ? { compass: params.compass } : {}) }, ...readOptions(options));
227
+ }
204
228
  publicNetworks() {
205
229
  return this.client.get('/protocols/social/networks');
206
230
  }
@@ -315,9 +339,14 @@ export class ProtocolsResource {
315
339
  async getPublicViral(params = {}, options) {
316
340
  return viralRead(await this.client.get('/protocols/social/viral', viralQuery(params), ...readOptions(options)));
317
341
  }
318
- /** Provider-ranked public accounts with explicit provenance; served from the app's index when a fresh snapshot exists. */
342
+ /**
343
+ * Popular public accounts with explicit provenance; served from the app's index when a fresh snapshot exists.
344
+ * `protocol: 'all'` reads the famous accounts of every network in one list, paged for infinite scroll, optionally
345
+ * narrowed to a `category`; `compass: 'hide'` leaves political accounts out of any list.
346
+ */
319
347
  getPublicPopularProfiles(params) {
320
- return this.client.get('/protocols/social/popular-profiles', { protocol: params.protocol, limit: params.limit, cursor: params.cursor });
348
+ return this.client.get('/protocols/social/popular-profiles', { protocol: params.protocol, limit: params.limit, cursor: params.cursor,
349
+ ...(params.category !== undefined ? { category: params.category } : {}), ...(params.compass !== undefined ? { compass: params.compass } : {}) });
321
350
  }
322
351
  /** Read this connected account's current native following; never infer it from a public count. */
323
352
  nativeFollowState(input) {
@@ -550,6 +579,122 @@ export class ProtocolsResource {
550
579
  const body = input.enabled ? { enabled: true } : { enabled: false, ...(input.removePast !== undefined ? { remove_past: input.removePast } : {}) };
551
580
  return this.client.put(nativeNetworkPath(network), body);
552
581
  }
582
+ /**
583
+ * Which identity a one-tap action uses on a network when the member also linked an outside account there (0.7.191).
584
+ * `linked` needs a linked account (409 `linked_account_required`); `native` needs the network on, ready or pending
585
+ * (409 `native_network_off`) and a network that can send a tap as the member's identity (503
586
+ * `native_network_unavailable`, reason `adapter_missing`, otherwise), and sets the identity up now when that is what the
587
+ * choice needs. Needs `users:write`.
588
+ */
589
+ setEngageDefault(network, engageDefault) {
590
+ if (engageDefault !== 'native' && engageDefault !== 'linked') {
591
+ throw new ValidationError({ type: 'validation_error', code: 'invalid_input', message: 'engageDefault must be native or linked' });
592
+ }
593
+ return this.client.put(`${nativeNetworkPath(network)}/engage-default`, { engage_default: engageDefault });
594
+ }
595
+ /**
596
+ * "Get my AT Protocol password" (0.7.191): the PDS emails a reset code to the member's verified address, the one their hosted AT
597
+ * Protocol account uses; Minds never holds or shows that password (it keeps only a revocable app password, which the
598
+ * member can revoke from any AT Protocol app). Needs a step-up (403 `step_up_required` / `step_up_failed`). Other
599
+ * refusals: 404 `no_identity`, 409 `needs_verified_email` or `email_changed`, 429 `rate_limited`. Needs `users:write`.
600
+ * Never auto-retried.
601
+ */
602
+ claimAtprotoPassword(proof) {
603
+ const body = 'password' in proof ? { password: proof.password } : { email_code: proof.emailCode };
604
+ return this.client.post(`${nativeNetworkPath('atproto')}/claim-password`, body, { retry: false });
605
+ }
606
+ /**
607
+ * "Let Minds act as your AT Protocol account" (0.7.191): the way back when AT Protocol reads `needs_action` with reason
608
+ * `needs_atproto_grant` (an account made before Minds ran it natively) or `error` with `app_password_revoked`. The member
609
+ * enters their AT Protocol account's password once (the main one, which `claimAtprotoPassword` lets them set, or a
610
+ * non-privileged app password they made); Minds keeps only a new revocable app password and drops the password given.
611
+ * Refusals: 403 `password_failed`, 400 `privileged_app_password` (one that can read direct messages), 409
612
+ * `identity_mismatch`, 404 `no_identity`, 429 `rate_limited`. Needs `users:write`. Never auto-retried.
613
+ */
614
+ grantAtproto(input) {
615
+ return this.client.post(`${nativeNetworkPath('atproto')}/grant`, { password: input.password }, { retry: false });
616
+ }
617
+ /** The member's one-tap actions waiting for their native identity to be set up, oldest first (0.7.191). Needs `users:read`. */
618
+ pendingInteractions() {
619
+ return this.client.get('/protocols/interactions/pending');
620
+ }
621
+ /**
622
+ * One-tap like or unlike (0.7.191). A native answer is sent (`NativeEngageSent`) or queued (`NativeEngageQueued`, 202)
623
+ * while the identity is set up; a linked answer is the review to submit with `submitNativeLike`, as before. Refusals:
624
+ * 409 `native_network_off` (with `reason`), 409 `linked_account_required`, 429 `too_many_pending`, and 503
625
+ * `native_network_unavailable` with reason `adapter_missing` while the network cannot send a tap as the member's identity
626
+ * (a linked account acts instead when there is one; nothing is set up or queued). Keep
627
+ * `clientMutationId` across retries: a retried tap is never sent twice, and once it expired unsent the retry answers
628
+ * `delivery: { state: 'failed', code: 'interaction_expired' }` (a new tap takes a new id). The same id on a different
629
+ * action, target or words is 409 `client_mutation_reused`. A tap whose identity went off before it was sent answers
630
+ * `delivery: { state: 'failed', code: 'native_network_off' }`. Never auto-retried.
631
+ */
632
+ engageLike(input) {
633
+ return this.client.post('/protocols/social/likes/prepare', engageOneBody(input), { retry: false });
634
+ }
635
+ /** One-tap repost or unrepost (0.7.191); answers as `engageLike` does (linked: submit with `submitNativeRepost`). */
636
+ engageRepost(input) {
637
+ return this.client.post('/protocols/social/reposts/prepare', engageOneBody(input), { retry: false });
638
+ }
639
+ /** One-tap follow or unfollow (0.7.191); answers as `engageLike` does (linked: submit with `submitNativeFollow`). */
640
+ engageFollow(input) {
641
+ return this.client.post('/protocols/social/follows/prepare', engageOneBody(input), { retry: false });
642
+ }
643
+ /**
644
+ * A reply as the member's own identity on the parent's network, or (identity `linked`, or `accountIds`) the shared
645
+ * reply review as `prepareNativeReply` (0.7.191). Answers as `engageLike` does. `media` takes only the member's own
646
+ * Minds uploads, native or linked (400 `invalid_reply` otherwise; 422 `media_unsupported` for a GIF with other images
647
+ * on ActivityPub).
648
+ */
649
+ engageReply(input) {
650
+ return this.client.post('/protocols/social/replies/prepare', { clientMutationId: input.clientMutationId, text: input.text,
651
+ parent: { protocol: input.parent.protocol, nativeId: input.parent.nativeId, ...(input.parent.readRef !== undefined ? { readRef: input.parent.readRef } : {}) },
652
+ ...(input.media !== undefined ? { media: nativeMediaInput(input.media) } : {}),
653
+ ...(input.identity !== undefined ? { identity: input.identity } : {}),
654
+ ...(input.accountIds !== undefined ? { accountIds: input.accountIds } : {}) }, { retry: false });
655
+ }
656
+ /**
657
+ * A quote of a post as the member's own identity on its network, or (identity `linked`, or `accountIds`) the post
658
+ * review as `prepareNativePost` (0.7.191). A post with no quote is never native: the member's posts in the app reach
659
+ * their networks on their own (409 `native_post_from_app`). Answers as `engageLike` does.
660
+ */
661
+ engageQuote(input) {
662
+ return this.client.post('/protocols/social/posts/prepare', { clientMutationId: input.clientMutationId, text: input.text,
663
+ quote: { protocol: input.quote.protocol, nativeId: input.quote.nativeId },
664
+ ...(input.media !== undefined ? { media: nativeMediaInput(input.media) } : {}),
665
+ ...(input.identity !== undefined ? { identity: input.identity } : {}),
666
+ ...(input.accountIds !== undefined ? { accountIds: input.accountIds } : {}) }, { retry: false });
667
+ }
668
+ /**
669
+ * Takes the member's managed Nostr key home, step 1: the key as an `nsec`, after a step-up (403 `step_up_required`
670
+ * or `step_up_failed`, 429 `rate_limited`, 404 `no_managed_key`). Minds keeps its copy. Never retried. Needs
671
+ * `users:write`.
672
+ */
673
+ exportNostrKey(stepUp) {
674
+ return this.client.post('/protocols/networks/nostr/export', nostrStepUpBody(stepUp), { retry: false });
675
+ }
676
+ /** Step 2a: a single-use challenge for the member's signer to sign with the same key (NIP-07, never published). */
677
+ nostrRebindChallenge() {
678
+ return this.client.post('/protocols/networks/nostr/rebind-challenge', {});
679
+ }
680
+ /**
681
+ * Step 2b: the signed challenge. A signature from the identity's own key sets the mode to `attached` (409
682
+ * `rebind_mismatch` for another key; 400 `invalid_proof`, `expired_proof` or `used_proof`). Minds still holds its copy.
683
+ */
684
+ rebindNostrKey(event) {
685
+ return this.client.post('/protocols/networks/nostr/rebind', { event }, { retry: false });
686
+ }
687
+ /**
688
+ * Step 3: after a step-up, and only once rebound (409 `rebind_required`), Minds deletes its encrypted copy of the
689
+ * key. First it signs, with the copy, a takedown for everything it published with the key, kept so a post deletion,
690
+ * "Remove what I already shared" or the account's deletion still takes Minds' notes down (409 `too_many_published`
691
+ * when there is too much: the copy is kept). The NIP-05 address keeps the same key; every later Nostr action is a
692
+ * signing request for the member's device. Not undoable by Minds: make sure their signer holds the key first. Never
693
+ * retried.
694
+ */
695
+ deleteManagedNostrCopy(stepUp) {
696
+ return this.client.post('/protocols/networks/nostr/delete-managed-copy', nostrStepUpBody(stepUp), { retry: false });
697
+ }
553
698
  /** Current Minds-hosted ActivityPub state for this app user; never provisions. */
554
699
  federationIdentity() {
555
700
  return this.client.get('/protocols/social/federation/identity');
@@ -577,7 +722,7 @@ export class ProtocolsResource {
577
722
  source: { protocol: input.source.protocol, nativeId: input.source.nativeId,
578
723
  ...(input.source.readRef !== undefined ? { readRef: input.source.readRef } : {}) } }
579
724
  : { action: input.action, postId: input.postId };
580
- return this.client.post(`/protocols/social/nostr/${encodeURIComponent(id)}/prepare`, body, { retry: false });
725
+ return this.client.post(`/protocols/social/nostr/${encodeURIComponent(id)}/prepare`, input.send === true ? { ...body, send: true } : body, { retry: false });
581
726
  }
582
727
  /** Pass only the public signed event. After a timeout, read the prepared postId (delete) or eventId (publish/reply/linked_post).
583
728
  * Any user-selected retry keeps the same intent/event. */
@@ -644,9 +789,11 @@ export class ProtocolsResource {
644
789
  *
645
790
  * Failures to expect: `handle_unavailable` (409, taken or reserved; choose
646
791
  * another), `identity_conflict` (409, the member already has one),
647
- * `creation_in_progress` (409), and the operator-side 503s
648
- * `handle_dns_unavailable`, `handle_unresolvable`, `handle_unverified` and
649
- * `hosted_server_unavailable`, which succeed unchanged once the operator is done.
792
+ * `creation_in_progress` (409), `outbound_refused` (403, the server's one
793
+ * outbound guard said no before the PDS was asked anything; nothing was
794
+ * created), and the operator-side 503s `handle_dns_unavailable`,
795
+ * `handle_unresolvable`, `handle_unverified` and `hosted_server_unavailable`,
796
+ * which succeed unchanged once the operator is done.
650
797
  */
651
798
  createHostedIdentity(input) {
652
799
  const { protocol, handle, email } = input;
@@ -1,10 +1,11 @@
1
1
  import type { HttpClient } from '../client.js';
2
2
  import type { PaginatedResponse, SingleResponse } from '../types.js';
3
- export type ReportTargetType = 'post' | 'user' | 'community' | 'message' | 'source_actor' | 'source_post';
3
+ export type ReportTargetType = 'post' | 'user' | 'community' | 'message' | 'sealed_answer' | 'source_actor' | 'source_post';
4
4
  export type ReportStatus = 'pending' | 'in_review' | 'escalated' | 'resolved' | 'dismissed';
5
5
  export interface CreateReportInput {
6
6
  /** External sources require protocols.reportSource so evidence is verified. */
7
7
  target_type: Exclude<ReportTargetType, 'source_actor' | 'source_post'>;
8
+ /** For sealed_answer, the authenticated project key's project id; it does not accuse the reporter. Requires supporting API. */
8
9
  target_id: string;
9
10
  reason: string;
10
11
  details?: string;
@@ -32,9 +33,13 @@ export declare class ReportsResource {
32
33
  private client;
33
34
  constructor(client: HttpClient);
34
35
  /**
35
- * Submit a content report. Targets a post, user, community, or message
36
+ * Submit a content report. Targets a post, user, community, message, or Sealed answer
36
37
  * by ID, with a short reason and optional free-text details. Reporter
37
38
  * is the authenticated user.
39
+ * A sealed_answer targets the key's own project and needs posts:write on a human-owned,
40
+ * non-agent project key. This intake does not recheck live app membership; the Sealed
41
+ * gateway's report route does. Review applies no account enforcement.
42
+ * Deploy supporting API before client adoption.
38
43
  *
39
44
  * Sent once, never retried automatically: past the member's report budget
40
45
  * the server answers 429 (`RateLimitError`, `retryAfter` = seconds until
@@ -42,6 +47,10 @@ export declare class ReportsResource {
42
47
  */
43
48
  create(input: CreateReportInput): Promise<SingleResponse<{
44
49
  success: true;
50
+ id?: string;
51
+ existing?: boolean;
52
+ /** Sealed answers: false when a join kept the reason but the selected exchange did not fit in full. */
53
+ details_kept?: boolean;
45
54
  }>>;
46
55
  /** List recent reports in the caller's project/network (admin only). */
47
56
  list(): Promise<PaginatedResponse<ReportRecord>>;
@@ -4,9 +4,13 @@ export class ReportsResource {
4
4
  this.client = client;
5
5
  }
6
6
  /**
7
- * Submit a content report. Targets a post, user, community, or message
7
+ * Submit a content report. Targets a post, user, community, message, or Sealed answer
8
8
  * by ID, with a short reason and optional free-text details. Reporter
9
9
  * is the authenticated user.
10
+ * A sealed_answer targets the key's own project and needs posts:write on a human-owned,
11
+ * non-agent project key. This intake does not recheck live app membership; the Sealed
12
+ * gateway's report route does. Review applies no account enforcement.
13
+ * Deploy supporting API before client adoption.
10
14
  *
11
15
  * Sent once, never retried automatically: past the member's report budget
12
16
  * the server answers 429 (`RateLimitError`, `retryAfter` = seconds until
@@ -35,9 +35,35 @@ export interface SearchLadder {
35
35
  pending: number;
36
36
  unavailable: string[];
37
37
  }
38
- /** A post as a search lists it: `via` says how the ladder found it (absent from servers before 0.7.79). */
38
+ /**
39
+ * What a search post's picture is (server 0.7.162, picture-facts-v1: Jev's background read of pictures every floor
40
+ * cleared, cached 30 days). Layout hints only, never a safety signal: absent until the picture is judged, when the
41
+ * server's switch is off, or on servers before 0.7.162, and a client keeps its own layout then.
42
+ */
43
+ export interface SearchPicture {
44
+ /** `text_graphic`: a screenshot, headline card, table, chart, poster or infographic. `other`: a meme or anything else. */
45
+ kind: 'photo' | 'illustration' | 'text_graphic' | 'other';
46
+ /** Most of what it says is written text: show it whole (contain), not cropped, and do not lead with it. */
47
+ textHeavy: boolean;
48
+ /** How good a big tile it makes, 0 (unusable) to 3 (striking). */
49
+ tileQuality: number;
50
+ /** Where its main subject is, as fractions of the width (`x`) and height (`y`) from the top left: a crop's object position. */
51
+ focal?: {
52
+ x: number;
53
+ y: number;
54
+ };
55
+ /**
56
+ * Whether the picture itself shows what was searched (0.7.190, search-picture-subject-v1, cached 7 days per query and
57
+ * picture): on a visitor's `deep` stage only, for the page's top pictures. Absent unless the operator turned on
58
+ * `SEARCH_PICTURE_SUBJECT` (with picture facts), and until that query's picture is judged. A layout hint (make a big
59
+ * tile of it when `true`), never a reason to hide a result and never a safety signal.
60
+ */
61
+ showsQuery?: boolean;
62
+ }
63
+ /** A post as a search lists it: `via` says how the ladder found it (absent from servers before 0.7.79); `picture`: SearchPicture. */
39
64
  export type SearchPost = Post & {
40
65
  via?: SearchVia;
66
+ picture?: SearchPicture;
41
67
  };
42
68
  /**
43
69
  * A visitor's search tabs (tRPC `publicDiscovery.search`, read keyless through the app's public client). `media` (server
@@ -62,12 +88,50 @@ export interface PublicSearchPage<T = Record<string, unknown>> {
62
88
  };
63
89
  /** The `media` tab only: what the web has for the words. Absent where the app does not get it (`ladder.unavailable` names `media`). */
64
90
  media?: SearchMedia;
91
+ /**
92
+ * A posts tab's deep stage, page 1 only (server 0.7.137): searches related to what the words mean, best first, for
93
+ * related-topic chips ("hockey": NHL, Stanley Cup). Absent when the server has none in time, and from older servers.
94
+ */
95
+ related_queries?: Array<{
96
+ query: string;
97
+ }>;
98
+ /**
99
+ * The page's clips in lead order (server 0.7.173): its posts' clips, the open networks' and the `media` tab's videos,
100
+ * the most about the words first (`SearchVideoLeadEntry`). The `videos` tab's `items` already come in this order.
101
+ * Absent with no clip, from older servers, or when the operator turned the lead order off.
102
+ */
103
+ video_lead?: SearchVideoLeadEntry[];
104
+ }
105
+ /** Where a clip in a search's `video_lead` came from: a Minds member's post, an open-network post, PeerTube, or the web. */
106
+ export type SearchVideoLeadSource = 'minds' | 'open_network' | 'peertube' | 'web';
107
+ /**
108
+ * One clip of a search answer in lead order (server 0.7.173). The order: `on_subject` (`on`: about the words, `loose`: it
109
+ * mentions them, `off`: the popular tail), then freshness (within a day, a week, 30 days, a year, older, undated last),
110
+ * then a Minds member's clip before any other, then the newer. Play the first entry as the lead. `section` and `index`
111
+ * point at the item in the answer (`items` on a visitor's page); `ref` is the Minds post id, the open-network post's
112
+ * `sourceUrl` or the media item's `url`. A client merging two answers' entries sorts by the same rules.
113
+ */
114
+ export interface SearchVideoLeadEntry {
115
+ section: 'top_posts' | 'latest_posts' | 'open_network' | 'media' | 'items';
116
+ index: number;
117
+ ref: string;
118
+ source: SearchVideoLeadSource;
119
+ on_subject: 'on' | 'loose' | 'off';
120
+ /** ISO 8601, when the clip is dated. */
121
+ published_at: string | null;
65
122
  }
66
123
  /** The kinds of a search's media items, in the order the server lists them. */
67
124
  export declare const SEARCH_MEDIA_KINDS: readonly ["about", "video", "article", "image", "audio"];
68
125
  export type SearchMediaKind = (typeof SEARCH_MEDIA_KINDS)[number];
69
- /** Where a media item was found. */
70
- export type SearchMediaSource = 'brave' | 'wikipedia' | 'peertube' | 'openverse';
126
+ /**
127
+ * Where a media item was found. `eventregistry` (0.7.133): a news article from the thousands the server's news lanes
128
+ * read each day (Event Registry and outlet feeds), matched by its headline: show its headline, `description` (a short
129
+ * excerpt), `publisher` (the outlet), `published_at`, `thumbnail` and link to `url`, never more of the article.
130
+ * `youtube` (0.7.181): a video the YouTube Data API found for the words; it always has YouTube's player as `embed`: play
131
+ * it in place by YouTube's player rules (no autoplay with sound, nothing drawn over it, YouTube named as the source)
132
+ * rather than opening `url`.
133
+ */
134
+ export type SearchMediaSource = 'brave' | 'wikipedia' | 'peertube' | 'openverse' | 'eventregistry' | 'youtube';
71
135
  /**
72
136
  * How a video may play in place: YouTube's own player for `id` (use youtube-nocookie.com and follow its player rules:
73
137
  * at least 200x200, nothing drawn over it, YouTube shown as the source), or a PeerTube instance's own embed page.
@@ -106,8 +170,20 @@ export interface SearchMediaItem {
106
170
  * Visitors and members on safe defaults are never served such an item.
107
171
  */
108
172
  sensitive?: true;
173
+ /**
174
+ * The same PeerTube video as a native Fediverse post (0.7.155, `SocialPost.software: 'peertube'`): show the post, which
175
+ * plays in place from its channel, and never open `url`. Present only on a PeerTube video the server could read off its
176
+ * own instance; the item's other fields stay for an app that does not read it.
177
+ */
178
+ post?: SocialPost;
109
179
  }
110
- export type SearchMediaProvider = 'brave_web' | 'brave_images' | 'wikipedia' | 'peertube' | 'openverse_images' | 'openverse_audio';
180
+ /**
181
+ * The reads behind the media section. `news_index` (0.7.133): today's articles about the words from those the server's
182
+ * news lanes already read; `eventregistry`: a live per-query Event Registry read, where the server has one; `youtube`
183
+ * (0.7.181): YouTube's videos for the words, asked only when the web's own videos about them are thin or the words name
184
+ * sport or music (`skipped` otherwise), within the server's daily YouTube quota (`budget` past it).
185
+ */
186
+ export type SearchMediaProvider = 'brave_web' | 'brave_images' | 'wikipedia' | 'peertube' | 'openverse_images' | 'openverse_audio' | 'news_index' | 'eventregistry' | 'youtube';
111
187
  /**
112
188
  * What each provider did for this answer; `timeout`: it is still reading, ask again shortly for more; `budget`: a
113
189
  * spending limit held it back (the day's Brave calls, or this caller's own calls a day or fresh answers an hour, past
@@ -226,6 +302,14 @@ export interface SearchRelated {
226
302
  slug: string;
227
303
  count: number;
228
304
  }>;
305
+ /**
306
+ * Searches related to the query's subject, best first, for related-topic chips ("hockey": NHL, Stanley Cup, ice hockey):
307
+ * from the server's understanding of the query (server 0.7.137), so a query whose posts carry no topic still has them.
308
+ * Absent when the server has none for the query, and from older servers.
309
+ */
310
+ queries?: Array<{
311
+ query: string;
312
+ }>;
229
313
  }
230
314
  /** One blended search answer. Only answered sections are present; an answered section may be empty. */
231
315
  export interface SearchAnswer {
@@ -285,6 +369,12 @@ export interface SearchAnswer {
285
369
  few_results: boolean;
286
370
  /** The search ladder's account of the answer (server 0.7.79): present when the server ran the ladder. */
287
371
  ladder?: SearchLadder;
372
+ /**
373
+ * Every clip the answer holds (Top's and Latest's Minds clips, the open networks', the media section's videos) in the
374
+ * order to lead and play them (server 0.7.173, `SearchVideoLeadEntry`): the most about the words first, then the
375
+ * freshest, a Minds member's clip winning a tie. Absent with no clip, from older servers, or when turned off.
376
+ */
377
+ video_lead?: SearchVideoLeadEntry[];
288
378
  }
289
379
  export interface SearchResponse {
290
380
  data: SearchAnswer;
@@ -1,10 +1,19 @@
1
1
  import type { HttpClient } from '../client.js';
2
2
  import type { ChangePasswordInput, ConfirmationCodePurpose, ConfirmationCodeSent, DeletionStatus, DisableAccountInput, LoginHistoryEntry, PaginatedResponse, RequestEmailChangeInput, RevokeOtherSessionsInput, RevokeOtherSessionsResult, Session, SingleResponse, SuccessResponse, UpdateAppearanceInput, UpdateContentPreferencesInput, UpdateNotificationChannelsInput, UpdatePrivacyInput, UserPreferences } from '../types.js';
3
+ import type { MemberExperience, UpdateMemberExperienceInput } from './member-experience.js';
3
4
  export declare class SettingsResource {
4
5
  private client;
5
6
  constructor(client: HttpClient);
6
7
  /** Get user preferences */
7
8
  getPreferences(): Promise<SingleResponse<UserPreferences>>;
9
+ /** Read your explicit goals and category starting point in this app; requires your own project-bound key. */
10
+ getExperience(): Promise<SingleResponse<MemberExperience>>;
11
+ /** Save explicit choices at the current version. This changes the saved starting point, not whole-feed ranking. */
12
+ updateExperience(input: UpdateMemberExperienceInput): Promise<SingleResponse<MemberExperience>>;
13
+ /** Restore the previous choices if this version is still current; a stale Undo is refused. */
14
+ undoExperience(input: {
15
+ version: number;
16
+ }): Promise<SingleResponse<MemberExperience>>;
8
17
  /**
9
18
  * Download a portable ZIP containing the caller's profile, posts, social
10
19
  * graph, authored messages, account activity, preferences, and fetchable
@@ -50,8 +59,9 @@ export declare class SettingsResource {
50
59
  * Email a six-digit confirmation code to the account's current address.
51
60
  * Only for accounts with no password (`profiles.me().has_password === false`);
52
61
  * a password account answers `password_required`. Send the code as
53
- * `email_code` to `requestEmailChange`, or as `emailCode` to the
54
- * `auth.*TwoFactor` methods.
62
+ * `email_code` to `requestEmailChange`, as `emailCode` to the
63
+ * `auth.*TwoFactor` methods, or (purpose `nostr_key`) as `emailCode` to
64
+ * `protocols.exportNostrKey` and `protocols.deleteManagedNostrCopy`.
55
65
  */
56
66
  requestConfirmationCode(purpose: ConfirmationCodePurpose): Promise<SingleResponse<ConfirmationCodeSent>>;
57
67
  /**
@@ -8,6 +8,18 @@ export class SettingsResource {
8
8
  getPreferences() {
9
9
  return this.client.get('/settings/preferences');
10
10
  }
11
+ /** Read your explicit goals and category starting point in this app; requires your own project-bound key. */
12
+ getExperience() {
13
+ return this.client.get('/settings/preferences/experience');
14
+ }
15
+ /** Save explicit choices at the current version. This changes the saved starting point, not whole-feed ranking. */
16
+ updateExperience(input) {
17
+ return this.client.patch('/settings/preferences/experience', input);
18
+ }
19
+ /** Restore the previous choices if this version is still current; a stale Undo is refused. */
20
+ undoExperience(input) {
21
+ return this.client.post('/settings/preferences/experience/undo', input);
22
+ }
11
23
  /**
12
24
  * Download a portable ZIP containing the caller's profile, posts, social
13
25
  * graph, authored messages, account activity, preferences, and fetchable
@@ -87,8 +99,9 @@ export class SettingsResource {
87
99
  * Email a six-digit confirmation code to the account's current address.
88
100
  * Only for accounts with no password (`profiles.me().has_password === false`);
89
101
  * a password account answers `password_required`. Send the code as
90
- * `email_code` to `requestEmailChange`, or as `emailCode` to the
91
- * `auth.*TwoFactor` methods.
102
+ * `email_code` to `requestEmailChange`, as `emailCode` to the
103
+ * `auth.*TwoFactor` methods, or (purpose `nostr_key`) as `emailCode` to
104
+ * `protocols.exportNostrKey` and `protocols.deleteManagedNostrCopy`.
92
105
  */
93
106
  requestConfirmationCode(purpose) {
94
107
  return this.client.post('/settings/confirmation-code', { purpose });
package/dist/types.d.ts CHANGED
@@ -184,6 +184,19 @@ export interface UserSummary {
184
184
  * servers older than this field and from reads that do not label accounts.
185
185
  */
186
186
  is_nsfw?: boolean;
187
+ /**
188
+ * An account the operator vouches for: draw the verified badge. Carried by a
189
+ * post's author. An app that draws one mark next to a name draws verified
190
+ * before `founder` before the plan mark. Absent from servers older than this
191
+ * field and from reads that do not mark accounts.
192
+ */
193
+ verified?: boolean;
194
+ /** The account's Plus plan is live. Absent from reads that do not mark accounts. */
195
+ plus?: boolean;
196
+ /** The account's Pro plan is live. Absent from reads that do not mark accounts. */
197
+ pro?: boolean;
198
+ /** A founding member. Absent from reads that do not mark accounts. */
199
+ founder?: boolean;
187
200
  }
188
201
  export interface User extends UserSummary {
189
202
  bio: string | null;
@@ -1378,6 +1391,13 @@ export interface AgentChatResult {
1378
1391
  export interface AgentConversation {
1379
1392
  id: string;
1380
1393
  type: string;
1394
+ /**
1395
+ * The conversation's own name (a group's, the Asks thread's), else, for a one-to-one chat, its title: the first 60
1396
+ * characters of the first message the agent did not send, looked for in the chat's first 20 messages, made by the
1397
+ * server with no model call and gone when that message is. Null when no such message is among the first 20 (before
1398
+ * anyone but the agent has written in it, for one); absent from a server that predates it.
1399
+ */
1400
+ name?: string | null;
1381
1401
  members: {
1382
1402
  id: string;
1383
1403
  name: string;
@@ -1404,6 +1424,11 @@ export interface AgentConversationMessage {
1404
1424
  } | null;
1405
1425
  created_at: string;
1406
1426
  }
1427
+ /** A new chat with the caller's own personal agent, as `agents.createConversation` returns it. */
1428
+ export interface CreatedAgentConversation extends AgentConversation {
1429
+ /** False when the member's empty chat with the agent in this app was handed back instead of a second blank one. */
1430
+ created: boolean;
1431
+ }
1407
1432
  export interface CreateTagInput {
1408
1433
  name: string;
1409
1434
  description?: string;
@@ -1760,7 +1785,7 @@ export interface RequestEmailChangeInput {
1760
1785
  email_code?: string;
1761
1786
  }
1762
1787
  /** What a confirmation code is for. A code for one purpose never confirms another. */
1763
- export type ConfirmationCodePurpose = 'email_change' | 'two_factor';
1788
+ export type ConfirmationCodePurpose = 'email_change' | 'two_factor' | 'nostr_key';
1764
1789
  export interface ConfirmationCodeSent {
1765
1790
  success: true;
1766
1791
  purpose: ConfirmationCodePurpose;