@recursiv/sdk 0.7.93 → 0.7.104

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
@@ -114,12 +114,13 @@ for await (const chunk of r.agents.chatStream(agent.id, { message: 'Hello!' }))
114
114
  | `r.billing` | Usage tracking, subscriptions, checkout |
115
115
  | `r.appSubscriptions` | Consumer app plans: `checkout`, `status`, `createPortalSession`, `previewTierChange`, `changeTier` |
116
116
  | `r.boosts` | Promoted posts: `create`, `mine`, `balance`, `pause`, `resume`, `cancel`, `recordEvent`, `topup`, `confirmTopup`; admin `listPendingReview`, `review`, `grant` |
117
- | `r.wallet` | Wallet, MINDS tokens (`getTokenBalance`, `getTokenLedger`), USD payouts (`getPayouts`, `startPayoutOnboarding`, `payoutLoginLink`) |
117
+ | `r.wallet` | Wallet, MINDS tokens (`getTokenBalance`, `getTokenLedger`), a wallet the member holds linked by signature (`createLinkNonce`, `linkWallet`, `listLinkedWallets`, `unlinkWallet`), USD payouts (`getPayouts`, `startPayoutOnboarding`, `payoutLoginLink`) |
118
118
  | `r.notifications` | Notification stream (`list`, `unreadCount`, `markAsRead`, `archive`, `markAllAsRead`; `category: 'mentions'` for mentions and replies only, 0.7.72) and push tokens |
119
119
  | `r.github` | GitHub integration |
120
120
  | `r.integrations` | External service connections |
121
121
  | `r.admin` | User management, stats, content reports (`listReports`, `resolveReport`, `dismissReport`) |
122
122
  | `r.moderation` | Moderation actions: `publicLog`, `mine`, `appeal`; staff `apply`, `resolveAppeal`, `list({ target_type?, target_id? })` (one target's recorded actions, newest first, at most 100; none named = the network's latest; 0.7.74) and `reverse(actionId)` (sent once: a repeat answers 404 `action_not_found`; 0.7.74); agent grants `listAgentGrants`, `grantAgent`, `revokeAgent` |
123
+ | `r.trust` | The signed trust log (0.7.96; 404 until the operator turns on `TRUST_LOG_PUBLIC_READS`): keyless `keys()` (every key that ever signed it), `mine({ before?, limit? })` (`users:read`: the caller's own signed events with the server's check `verified`). `r.moderation.publicLog` then carries `trust_log` on each action (`status`, and where the signed decision and reversal sit: `chain`, `seq`, `key_id`, `occurred_at`, `verified`). No read carries a hash or a signature |
123
124
  | `r.dispatcher` | Task queue, claims, signals, outcomes, webhooks |
124
125
  | `r.goals` | Org goals with task rollups (group dispatcher tasks) |
125
126
  | `r.linkPreview` | `get(url)` — a public link's Open Graph card (`data: null` when it has none). For a chat link pass `{ messageId }` or `{ conversationId }` on a signed-in key with `chat:read`: the link is fetched only when it is in the named message and a person wrote that message, or the caller wrote it in that conversation, else `refused: 'ai_link'`. A source with no id rejects (`ValidationError`). Not in encrypted chats: the server cannot read them, so leave `source` out there and apply the app's own rule |
@@ -9,10 +9,10 @@
9
9
  * - posts under a child-safety hold, and posts a moderator turned the assistant off for, are left out, whoever asks;
10
10
  * - a post the server's per-viewer verdict (`assist_readable`) says is not readable is left out, whoever asks;
11
11
  * - pictures go as alt text and the stored caption only: never bytes, never an address (held media not even that). A
12
- * picture keeps its plain id, and Minds' last child-safety check time (`checked_at`) when its input says `held` is
13
- * exactly `false` (2.1: "checked within the last 24 hours and not held"), so a renderer given the caller's image
14
- * cache may attach one on the asked-about post, parent or quote (never a reply's) as a picture while that check is
15
- * under 24 hours old (renderBundleForModel);
12
+ * picture keeps its plain id, and the time it last passed Minds' current checks (`checked_at`) when its input says
13
+ * `held` is exactly `false` (2.1: "checked within the last 24 hours and not held"; GET /posts sends both together,
14
+ * recursiv#5012), so a renderer given the caller's image cache may attach one on the asked-about post, parent or
15
+ * quote (never a reply's) as a picture while that check is under 24 hours old (renderBundleForModel);
16
16
  * - every string loses what a reader cannot see (stripHiddenText) and is cut to its limit, and the bundle has a total
17
17
  * that the asked-about post is cut to fit as well.
18
18
  *
@@ -54,9 +54,9 @@ export interface SubjectMediaInput {
54
54
  */
55
55
  id?: string | null;
56
56
  /**
57
- * When Minds last matched this picture against the child-safety hash lists (the post payload's `media[].checked_at`,
58
- * sealed-full-scope-v1 2.1, gate P1): an ISO time with its zone, written only by the server. Kept only when `held`
59
- * is exactly `false`. A picture can go to a model as a picture only while this is under 24 hours old by the
57
+ * When the picture last passed Minds' current checks (the post payload's `media[].checked_at`, sent with `held:
58
+ * false`, sealed-full-scope-v1 2.1): an ISO time with its zone, written only by the server. Under Bill's 2026-10-11
59
+ * departure from gate P1 no hash-bank check is among them (recursiv#5012). Kept only when `held` is exactly `false`. A picture can go to a model as a picture only while this is under 24 hours old by the
60
60
  * renderer's clock; absent, not an ISO time with its zone, or without `held: false`, means alt text and the stored
61
61
  * caption only, as for every other picture.
62
62
  */
package/dist/index.d.ts CHANGED
@@ -60,6 +60,7 @@ import { JobsResource } from './resources/jobs.js';
60
60
  import { CuratorResource } from './resources/curator.js';
61
61
  import { ReportsResource } from './resources/reports.js';
62
62
  import { ModerationResource } from './resources/moderation.js';
63
+ import { TrustResource } from './resources/trust.js';
63
64
  import { JudgmentsResource } from './resources/judgments.js';
64
65
  import { LinkPreviewResource } from './resources/link-preview.js';
65
66
  import { SearchResource } from './resources/search.js';
@@ -134,6 +135,8 @@ export declare class Recursiv {
134
135
  readonly boosts: BoostsResource;
135
136
  readonly reports: ReportsResource;
136
137
  readonly moderation: ModerationResource;
138
+ /** The signed trust log: its public keys, and the member's own signed events (0.7.96). */
139
+ readonly trust: TrustResource;
137
140
  /** Jev's labels of a post: read them, dispute or appeal one, and (staff) review a dispute. */
138
141
  readonly judgments: JudgmentsResource;
139
142
  readonly linkPreview: LinkPreviewResource;
@@ -216,7 +219,9 @@ export type { ReportTargetType, ReportStatus, CreateReportInput, ReportRecord, R
216
219
  export { JudgmentsResource, isJudgmentSharedWordsError } from './resources/judgments.js';
217
220
  export type { JudgmentSubjectKind, JudgmentSource, JudgmentOverrideMethod, PostLabelsStatus, PostLabelsQuery, PostLabelsSubject, PostLabelsCategory, PostLabelsPolitics, PostJudgmentRecord, PostJudgment, PostSafetyAttribution, PostLabelsCategoryView, PostLabelsSummaryView, PostLabelsFullView, PostLabels, DisputeJudgmentInput, JudgmentDispute, ReviewJudgmentInput, JudgmentReviewUpheld, JudgmentReviewAwaitingReviewer, JudgmentReviewOverridden, JudgmentReview, JudgmentSharedWordsDetails, JudgmentSharedWordsError, } from './resources/judgments.js';
218
221
  export { ModerationResource } from './resources/moderation.js';
219
- export type { ModerationTargetType, ModerationActionType, ModerationAppealStatus, ModerationPrinciple, PublicModerationAction, PublicModerationLog, OwnModerationAppeal, OwnModerationAction, OwnModerationLog, ApplyModerationActionInput, ModerationAction, ListModerationActionsParams, RecordedModerationTargetType, AgentModerationMode, AgentModerationGrant, } from './resources/moderation.js';
222
+ export type { ModerationTargetType, ModerationActionType, ModerationAppealStatus, ModerationPrinciple, PublicModerationAction, PublicModerationLog, OwnModerationAppeal, OwnModerationAction, OwnModerationLog, ApplyModerationActionInput, ModerationAction, ListModerationActionsParams, RecordedModerationTargetType, AgentModerationMode, AgentModerationGrant, ModerationTrustStatus, ModerationTrustLog, ModerationTrustWindow, } from './resources/moderation.js';
223
+ export { TrustResource } from './resources/trust.js';
224
+ export type { TrustEnvelope, OwnTrustEvent, TrustPublicKey, OwnTrustEvents } from './resources/trust.js';
220
225
  export { LinkPreviewResource } from './resources/link-preview.js';
221
226
  export { SEARCH_SECTIONS, SearchResource } from './resources/search.js';
222
227
  export type { PublicSearchPage, PublicSearchTab, SearchAnswer, SearchGroup, SearchLadder, SearchOmitReason, SearchParams, SearchPerson, SearchPost, SearchRelated, SearchResponse, SearchSection, SearchStage, SearchStory, SearchTopic, SearchVia, } from './resources/search.js';
@@ -238,7 +243,7 @@ export { OrganizationSecurityResource } from './resources/organization-security.
238
243
  export { UploadsResource } from './resources/uploads.js';
239
244
  export type { UploadMediaInput, UploadUrlInput, UploadUrlResult } from './resources/uploads.js';
240
245
  export { WalletResource } from './resources/wallet.js';
241
- export type { LinkedTokenWallet, PayoutState, TokenBalance, TokenLedgerEntry } from './resources/wallet.js';
246
+ export type { LinkedTokenWallet, PayoutState, TokenBalance, TokenLedgerEntry, WalletLink, WalletLinkNonce } from './resources/wallet.js';
242
247
  export { BoostsResource } from './resources/boosts.js';
243
248
  export type { BoostBalance, BoostBalanceResponse, BoostCampaign, BoostCampaignResponse, BoostEventResult, BoostLedgerEntry, BoostLedgerKind, BoostPlanCredit, BoostRejectionReason, BoostReviewStatus, BoostStatus, BoostTopupCheckout, BoostTopupConfirmation, BoostTopupLimits, } from './resources/boosts.js';
244
249
  export { ProtocolsResource } from './resources/protocols.js';
package/dist/index.js CHANGED
@@ -61,6 +61,7 @@ import { JobsResource } from './resources/jobs.js';
61
61
  import { CuratorResource } from './resources/curator.js';
62
62
  import { ReportsResource } from './resources/reports.js';
63
63
  import { ModerationResource } from './resources/moderation.js';
64
+ import { TrustResource } from './resources/trust.js';
64
65
  import { JudgmentsResource } from './resources/judgments.js';
65
66
  import { LinkPreviewResource } from './resources/link-preview.js';
66
67
  import { SearchResource } from './resources/search.js';
@@ -135,6 +136,8 @@ export class Recursiv {
135
136
  boosts;
136
137
  reports;
137
138
  moderation;
139
+ /** The signed trust log: its public keys, and the member's own signed events (0.7.96). */
140
+ trust;
138
141
  /** Jev's labels of a post: read them, dispute or appeal one, and (staff) review a dispute. */
139
142
  judgments;
140
143
  linkPreview;
@@ -211,6 +214,7 @@ export class Recursiv {
211
214
  this.boosts = new BoostsResource(client);
212
215
  this.reports = new ReportsResource(client);
213
216
  this.moderation = new ModerationResource(client);
217
+ this.trust = new TrustResource(client);
214
218
  this.judgments = new JudgmentsResource(client);
215
219
  this.linkPreview = new LinkPreviewResource(client);
216
220
  this.search = new SearchResource(client);
@@ -274,6 +278,7 @@ export { STORY_POOL_MAX_POSTS, STORY_POST_NETWORKS, STORY_POSTS_PAGE_MAX } from
274
278
  export { ReportsResource } from './resources/reports.js';
275
279
  export { JudgmentsResource, isJudgmentSharedWordsError } from './resources/judgments.js';
276
280
  export { ModerationResource } from './resources/moderation.js';
281
+ export { TrustResource } from './resources/trust.js';
277
282
  export { LinkPreviewResource } from './resources/link-preview.js';
278
283
  export { SEARCH_SECTIONS, SearchResource } from './resources/search.js';
279
284
  export { BOOKMARK_MERGE_MAX_ITEMS, BookmarkCollectionsResource, BookmarksResource } from './resources/bookmarks.js';
@@ -76,4 +76,235 @@ export declare const PRIVACY_FACTS: readonly [{
76
76
  readonly capability: "chat_tier";
77
77
  readonly step: "S29";
78
78
  readonly says: "No Sealed route sends a push notification or writes a notification: a Sealed answer goes back only on the request that asked for it.";
79
+ }, {
80
+ readonly id: "ai_prefs.agent_enabled";
81
+ readonly status: "planned";
82
+ readonly enforcement: "server_and_client";
83
+ readonly capability: "agent_enabled";
84
+ readonly step: "S9";
85
+ readonly says: "When a member turns their personal agent off, their turns to it make no provider call, it is not created again at sign-in, its chat leaves their conversation list and it sends them no push.";
86
+ }, {
87
+ readonly id: "ai_prefs.standard_allowed";
88
+ readonly status: "planned";
89
+ readonly enforcement: "server";
90
+ readonly capability: "standard_allowed";
91
+ readonly step: "S28";
92
+ readonly says: "When a member turns Standard AI off, no agent makes a call through OpenRouter or a model maker for a turn they send.";
93
+ }, {
94
+ readonly id: "ai_prefs.memory_facts";
95
+ readonly status: "planned";
96
+ readonly enforcement: "server";
97
+ readonly capability: "memory_facts";
98
+ readonly step: "S11";
99
+ readonly says: "When a member turns memory off, no agent in the app saves new facts about them, and saved facts are not sent with their turns.";
100
+ }, {
101
+ readonly id: "ai_prefs.memory_recall";
102
+ readonly status: "planned";
103
+ readonly enforcement: "server";
104
+ readonly capability: "memory_recall";
105
+ readonly step: "S11";
106
+ readonly says: "When a member turns off using their other chats, a turn carries only that chat's own messages and, while memory is on, saved facts.";
107
+ }, {
108
+ readonly id: "ai_prefs.memory_summaries";
109
+ readonly status: "planned";
110
+ readonly enforcement: "server";
111
+ readonly capability: "memory_summaries";
112
+ readonly step: "S11";
113
+ readonly says: "When a member turns summaries off, no summary call is made for their chats.";
114
+ }, {
115
+ readonly id: "ai_prefs.chat_memory";
116
+ readonly status: "planned";
117
+ readonly enforcement: "server";
118
+ readonly capability: "chat_memory";
119
+ readonly step: "S13";
120
+ readonly says: "When memory is off for one chat or one turn, nothing from it is saved to memory or used in other chats, and saved facts are not sent from it.";
121
+ }, {
122
+ readonly id: "ai_prefs.activity";
123
+ readonly status: "planned";
124
+ readonly enforcement: "server";
125
+ readonly capability: "activity";
126
+ readonly step: "S26";
127
+ readonly says: "Who a member follows, what they upvoted, their groups and their interests go with a turn only for the parts they ticked, and only once they decided.";
128
+ }, {
129
+ readonly id: "ai_prefs.feed_from_questions";
130
+ readonly status: "planned";
131
+ readonly enforcement: "server_and_client";
132
+ readonly capability: "feed_from_questions";
133
+ readonly step: "S26";
134
+ readonly says: "Asking an agent about a post is stored as a feed signal only when the member turned that on, and only the post id is stored, never the question.";
135
+ }, {
136
+ readonly id: "ai_prefs.push_preview";
137
+ readonly status: "enforced";
138
+ readonly enforcement: "server";
139
+ readonly capability: "push_preview";
140
+ readonly step: "S16";
141
+ readonly says: "A push for a message an AI agent sends in a chat carries the agent's name and none of the message's words, unless the member turned the preview on; a push whose sender cannot be read carries none of its words either.";
142
+ }, {
143
+ readonly id: "ai_prefs.standard_history_days";
144
+ readonly status: "planned";
145
+ readonly enforcement: "server";
146
+ readonly capability: "standard_history_days";
147
+ readonly step: "S24";
148
+ readonly says: "When a member picks 7 or 30 days, a daily job deletes their one-on-one agent chats older than that, with the chats' summaries and usage copies; billing rows without content stay.";
149
+ }, {
150
+ readonly id: "notifications.ai_message";
151
+ readonly status: "planned";
152
+ readonly enforcement: "server";
153
+ readonly capability: "push_ai_replies";
154
+ readonly step: "S16";
155
+ readonly says: "Pushes for agent replies have their own setting, separate from messages from people, and start from the member's Messages push setting.";
156
+ }, {
157
+ readonly id: "reports.ai_review_filter";
158
+ readonly status: "planned";
159
+ readonly enforcement: "server";
160
+ readonly capability: "report_ai_review";
161
+ readonly step: "S20";
162
+ readonly says: "An agent's key cannot list, resolve or dismiss a report whose reporter turned AI review off.";
163
+ }, {
164
+ readonly id: "posts.ai_ask_allowed";
165
+ readonly status: "planned";
166
+ readonly enforcement: "server_and_client";
167
+ readonly capability: "allow_ask_on_my_posts";
168
+ readonly step: "S22";
169
+ readonly says: "When an author turns asks off, agents do not read their posts from links, and each post carries ai_ask_allowed false so apps hide the ask option.";
170
+ }, {
171
+ readonly id: "posts.public_posts_ai";
172
+ readonly status: "planned";
173
+ readonly enforcement: "server";
174
+ readonly capability: "public_posts_ai";
175
+ readonly step: "S22";
176
+ readonly says: "When an author turns it off, their public posts are not embedded, topic or leaning labelled, or picked for editions, and existing vectors and those labels are removed; safety labels still run.";
177
+ }, {
178
+ readonly id: "openrouter.deny_all_paths";
179
+ readonly status: "planned";
180
+ readonly enforcement: "server";
181
+ readonly capability: null;
182
+ readonly step: "S4";
183
+ readonly says: "Every OpenRouter request, on the direct, fallback and summary paths, asks for providers whose stated policy is not to collect data (data_collection: deny). That is their policy; it is not checked.";
184
+ }, {
185
+ readonly id: "account.export_ai";
186
+ readonly status: "planned";
187
+ readonly enforcement: "server";
188
+ readonly capability: "memory_manage";
189
+ readonly step: "S18";
190
+ readonly says: "The account download includes the member's agent chats, the agents' replies, what agents saved about them and their agent's settings.";
191
+ }, {
192
+ readonly id: "account.delete_personal_agent";
193
+ readonly status: "planned";
194
+ readonly enforcement: "server";
195
+ readonly capability: null;
196
+ readonly step: "S18";
197
+ readonly says: "Deleting an account deletes the member's personal agent, its instructions, its saved preferences and its decision rows.";
198
+ }, {
199
+ readonly id: "sealed.guard_checks_every_turn";
200
+ readonly status: "planned";
201
+ readonly enforcement: "client";
202
+ readonly capability: "chat_tier";
203
+ readonly step: "S29";
204
+ readonly says: "Every Sealed message and every Sealed answer goes through the sealed text check (gpt-oss-safeguard-120b) before it is sent or shown; with no check, nothing is sent.";
205
+ }, {
206
+ readonly id: "sealed.picture_checked_on_phone";
207
+ readonly status: "planned";
208
+ readonly enforcement: "device";
209
+ readonly capability: "chat_tier";
210
+ readonly step: "S29";
211
+ readonly says: "Every phone picture added to a Sealed chat passes the on-phone nudity check first; one it flags stays on the phone unless the member is a known adult whose adult setting is on, in a build that applies the adult policy.";
212
+ }, {
213
+ readonly id: "sealed.picture_check_block_only";
214
+ readonly status: "planned";
215
+ readonly enforcement: "server_and_client";
216
+ readonly capability: "chat_tier";
217
+ readonly step: "S28";
218
+ readonly says: "The sealed picture check (gemma4-31b) sees the picture alone, before anything else of the turn is sent, and only blocks: no report, flag or verdict reaches Minds. The gateway sees only that a check request was made, and counts it in the day's checks.";
219
+ }, {
220
+ readonly id: "sealed.post_picture_server_checked";
221
+ readonly status: "planned";
222
+ readonly enforcement: "server_and_client";
223
+ readonly capability: "chat_tier";
224
+ readonly step: "S28";
225
+ readonly says: "A post picture goes into a Sealed chat only once the server's current checks have cleared it, and never while it or its post is held or under a child-safety report; no hash-bank match is claimed.";
226
+ }, {
227
+ readonly id: "sealed.search_via_tinfoil_to_exa";
228
+ readonly status: "planned";
229
+ readonly enforcement: "server_and_client";
230
+ readonly capability: "chat_tier";
231
+ readonly step: "S28";
232
+ readonly says: "Sealed search runs only through Tinfoil's search, which sends the search words and page addresses to Exa, and nothing of the member's account or IP address.";
233
+ }, {
234
+ readonly id: "sealed.search_filters_in_body";
235
+ readonly status: "planned";
236
+ readonly enforcement: "client";
237
+ readonly capability: "chat_tier";
238
+ readonly step: "S29";
239
+ readonly says: "The phone sets the PII and injection filters in the sealed body of every message that searches, and never a location; a search with no filter marker turns search off for the chat.";
240
+ }, {
241
+ readonly id: "sealed.memory_on_phone_only";
242
+ readonly status: "planned";
243
+ readonly enforcement: "device";
244
+ readonly capability: "sealed_history";
245
+ readonly step: "S29";
246
+ readonly says: "Sealed memory and About you live only in the phone's no-backup store, under the account, never on Minds.";
247
+ }, {
248
+ readonly id: "sealed.memory_not_with_search_temporary_or_standard";
249
+ readonly status: "planned";
250
+ readonly enforcement: "client";
251
+ readonly capability: "chat_tier";
252
+ readonly step: "S29";
253
+ readonly says: "Sealed memory and About you never go with a message that searches, a temporary chat or a Standard turn, and memory tags in answers to messages that carry someone else's words are ignored.";
254
+ }, {
255
+ readonly id: "sealed.signout_clears_phone";
256
+ readonly status: "planned";
257
+ readonly enforcement: "client";
258
+ readonly capability: "sealed_history";
259
+ readonly step: "S29";
260
+ readonly says: "Signing out clears the account's Sealed chats, pictures, memory and About you from the phone, after a warning.";
261
+ }, {
262
+ readonly id: "sealed.adult_setting_web_known_adult";
263
+ readonly status: "planned";
264
+ readonly enforcement: "server_and_client";
265
+ readonly capability: null;
266
+ readonly step: "S29";
267
+ readonly says: "The adult setting (D17) changes only on the web, only a member Minds knows is 18 or over can turn it on, and the phone only reads it.";
268
+ }, {
269
+ readonly id: "sealed.search_question_only";
270
+ readonly status: "planned";
271
+ readonly enforcement: "client";
272
+ readonly capability: "chat_tier";
273
+ readonly step: "S29";
274
+ readonly says: "A Sealed message that searches carries only the question: no earlier message, memory, About you or phone picture.";
275
+ }, {
276
+ readonly id: "sealed.search_off_with_others_content";
277
+ readonly status: "planned";
278
+ readonly enforcement: "client";
279
+ readonly capability: "chat_tier";
280
+ readonly step: "S29";
281
+ readonly says: "A Sealed message that carries someone else's words (a post, a members-only post, or messages from any chat) does not search.";
282
+ }, {
283
+ readonly id: "sealed.search_shown_as_sent";
284
+ readonly status: "planned";
285
+ readonly enforcement: "client";
286
+ readonly capability: "chat_tier";
287
+ readonly step: "S29";
288
+ readonly says: "The search words shown are the words Exa got (the filter's redacted query), and each page opened is shown with its full address.";
289
+ }, {
290
+ readonly id: "sealed.temporary_not_saved";
291
+ readonly status: "planned";
292
+ readonly enforcement: "client";
293
+ readonly capability: "sealed_history";
294
+ readonly step: "S29";
295
+ readonly says: "A temporary Sealed chat writes nothing to the phone: no history, picture or memory.";
296
+ }, {
297
+ readonly id: "sealed.services_from_path";
298
+ readonly status: "planned";
299
+ readonly enforcement: "client";
300
+ readonly capability: "chat_tier";
301
+ readonly step: "S29";
302
+ readonly says: "'Other services this chat used' is computed from the path the chat's turns took.";
303
+ }, {
304
+ readonly id: "sealed.export_to_phone_only";
305
+ readonly status: "planned";
306
+ readonly enforcement: "client";
307
+ readonly capability: "sealed_history";
308
+ readonly step: "S29";
309
+ readonly says: "Exporting a Sealed chat writes a file on the phone and sends nothing.";
79
310
  }];
@@ -90,4 +90,268 @@ export const PRIVACY_FACTS = [
90
90
  step: "S29",
91
91
  says: "No Sealed route sends a push notification or writes a notification: a Sealed answer goes back only on the request that asked for it.",
92
92
  },
93
+ {
94
+ id: "ai_prefs.agent_enabled",
95
+ status: "planned",
96
+ enforcement: "server_and_client",
97
+ capability: "agent_enabled",
98
+ step: "S9",
99
+ says: "When a member turns their personal agent off, their turns to it make no provider call, it is not created again at sign-in, its chat leaves their conversation list and it sends them no push.",
100
+ },
101
+ {
102
+ id: "ai_prefs.standard_allowed",
103
+ status: "planned",
104
+ enforcement: "server",
105
+ capability: "standard_allowed",
106
+ step: "S28",
107
+ says: "When a member turns Standard AI off, no agent makes a call through OpenRouter or a model maker for a turn they send.",
108
+ },
109
+ {
110
+ id: "ai_prefs.memory_facts",
111
+ status: "planned",
112
+ enforcement: "server",
113
+ capability: "memory_facts",
114
+ step: "S11",
115
+ says: "When a member turns memory off, no agent in the app saves new facts about them, and saved facts are not sent with their turns.",
116
+ },
117
+ {
118
+ id: "ai_prefs.memory_recall",
119
+ status: "planned",
120
+ enforcement: "server",
121
+ capability: "memory_recall",
122
+ step: "S11",
123
+ says: "When a member turns off using their other chats, a turn carries only that chat's own messages and, while memory is on, saved facts.",
124
+ },
125
+ {
126
+ id: "ai_prefs.memory_summaries",
127
+ status: "planned",
128
+ enforcement: "server",
129
+ capability: "memory_summaries",
130
+ step: "S11",
131
+ says: "When a member turns summaries off, no summary call is made for their chats.",
132
+ },
133
+ {
134
+ id: "ai_prefs.chat_memory",
135
+ status: "planned",
136
+ enforcement: "server",
137
+ capability: "chat_memory",
138
+ step: "S13",
139
+ says: "When memory is off for one chat or one turn, nothing from it is saved to memory or used in other chats, and saved facts are not sent from it.",
140
+ },
141
+ {
142
+ id: "ai_prefs.activity",
143
+ status: "planned",
144
+ enforcement: "server",
145
+ capability: "activity",
146
+ step: "S26",
147
+ says: "Who a member follows, what they upvoted, their groups and their interests go with a turn only for the parts they ticked, and only once they decided.",
148
+ },
149
+ {
150
+ id: "ai_prefs.feed_from_questions",
151
+ status: "planned",
152
+ enforcement: "server_and_client",
153
+ capability: "feed_from_questions",
154
+ step: "S26",
155
+ says: "Asking an agent about a post is stored as a feed signal only when the member turned that on, and only the post id is stored, never the question.",
156
+ },
157
+ {
158
+ id: "ai_prefs.push_preview",
159
+ status: "enforced",
160
+ enforcement: "server",
161
+ capability: "push_preview",
162
+ step: "S16",
163
+ says: "A push for a message an AI agent sends in a chat carries the agent's name and none of the message's words, unless the member turned the preview on; a push whose sender cannot be read carries none of its words either.",
164
+ },
165
+ {
166
+ id: "ai_prefs.standard_history_days",
167
+ status: "planned",
168
+ enforcement: "server",
169
+ capability: "standard_history_days",
170
+ step: "S24",
171
+ says: "When a member picks 7 or 30 days, a daily job deletes their one-on-one agent chats older than that, with the chats' summaries and usage copies; billing rows without content stay.",
172
+ },
173
+ {
174
+ id: "notifications.ai_message",
175
+ status: "planned",
176
+ enforcement: "server",
177
+ capability: "push_ai_replies",
178
+ step: "S16",
179
+ says: "Pushes for agent replies have their own setting, separate from messages from people, and start from the member's Messages push setting.",
180
+ },
181
+ {
182
+ id: "reports.ai_review_filter",
183
+ status: "planned",
184
+ enforcement: "server",
185
+ capability: "report_ai_review",
186
+ step: "S20",
187
+ says: "An agent's key cannot list, resolve or dismiss a report whose reporter turned AI review off.",
188
+ },
189
+ {
190
+ id: "posts.ai_ask_allowed",
191
+ status: "planned",
192
+ enforcement: "server_and_client",
193
+ capability: "allow_ask_on_my_posts",
194
+ step: "S22",
195
+ says: "When an author turns asks off, agents do not read their posts from links, and each post carries ai_ask_allowed false so apps hide the ask option.",
196
+ },
197
+ {
198
+ id: "posts.public_posts_ai",
199
+ status: "planned",
200
+ enforcement: "server",
201
+ capability: "public_posts_ai",
202
+ step: "S22",
203
+ says: "When an author turns it off, their public posts are not embedded, topic or leaning labelled, or picked for editions, and existing vectors and those labels are removed; safety labels still run.",
204
+ },
205
+ {
206
+ id: "openrouter.deny_all_paths",
207
+ status: "planned",
208
+ enforcement: "server",
209
+ capability: null,
210
+ step: "S4",
211
+ says: "Every OpenRouter request, on the direct, fallback and summary paths, asks for providers whose stated policy is not to collect data (data_collection: deny). That is their policy; it is not checked.",
212
+ },
213
+ {
214
+ id: "account.export_ai",
215
+ status: "planned",
216
+ enforcement: "server",
217
+ capability: "memory_manage",
218
+ step: "S18",
219
+ says: "The account download includes the member's agent chats, the agents' replies, what agents saved about them and their agent's settings.",
220
+ },
221
+ {
222
+ id: "account.delete_personal_agent",
223
+ status: "planned",
224
+ enforcement: "server",
225
+ capability: null,
226
+ step: "S18",
227
+ says: "Deleting an account deletes the member's personal agent, its instructions, its saved preferences and its decision rows.",
228
+ },
229
+ {
230
+ id: "sealed.guard_checks_every_turn",
231
+ status: "planned",
232
+ enforcement: "client",
233
+ capability: "chat_tier",
234
+ step: "S29",
235
+ says: "Every Sealed message and every Sealed answer goes through the sealed text check (gpt-oss-safeguard-120b) before it is sent or shown; with no check, nothing is sent.",
236
+ },
237
+ {
238
+ id: "sealed.picture_checked_on_phone",
239
+ status: "planned",
240
+ enforcement: "device",
241
+ capability: "chat_tier",
242
+ step: "S29",
243
+ says: "Every phone picture added to a Sealed chat passes the on-phone nudity check first; one it flags stays on the phone unless the member is a known adult whose adult setting is on, in a build that applies the adult policy.",
244
+ },
245
+ {
246
+ id: "sealed.picture_check_block_only",
247
+ status: "planned",
248
+ enforcement: "server_and_client",
249
+ capability: "chat_tier",
250
+ step: "S28",
251
+ says: "The sealed picture check (gemma4-31b) sees the picture alone, before anything else of the turn is sent, and only blocks: no report, flag or verdict reaches Minds. The gateway sees only that a check request was made, and counts it in the day's checks.",
252
+ },
253
+ {
254
+ id: "sealed.post_picture_server_checked",
255
+ status: "planned",
256
+ enforcement: "server_and_client",
257
+ capability: "chat_tier",
258
+ step: "S28",
259
+ says: "A post picture goes into a Sealed chat only once the server's current checks have cleared it, and never while it or its post is held or under a child-safety report; no hash-bank match is claimed.",
260
+ },
261
+ {
262
+ id: "sealed.search_via_tinfoil_to_exa",
263
+ status: "planned",
264
+ enforcement: "server_and_client",
265
+ capability: "chat_tier",
266
+ step: "S28",
267
+ says: "Sealed search runs only through Tinfoil's search, which sends the search words and page addresses to Exa, and nothing of the member's account or IP address.",
268
+ },
269
+ {
270
+ id: "sealed.search_filters_in_body",
271
+ status: "planned",
272
+ enforcement: "client",
273
+ capability: "chat_tier",
274
+ step: "S29",
275
+ says: "The phone sets the PII and injection filters in the sealed body of every message that searches, and never a location; a search with no filter marker turns search off for the chat.",
276
+ },
277
+ {
278
+ id: "sealed.memory_on_phone_only",
279
+ status: "planned",
280
+ enforcement: "device",
281
+ capability: "sealed_history",
282
+ step: "S29",
283
+ says: "Sealed memory and About you live only in the phone's no-backup store, under the account, never on Minds.",
284
+ },
285
+ {
286
+ id: "sealed.memory_not_with_search_temporary_or_standard",
287
+ status: "planned",
288
+ enforcement: "client",
289
+ capability: "chat_tier",
290
+ step: "S29",
291
+ says: "Sealed memory and About you never go with a message that searches, a temporary chat or a Standard turn, and memory tags in answers to messages that carry someone else's words are ignored.",
292
+ },
293
+ {
294
+ id: "sealed.signout_clears_phone",
295
+ status: "planned",
296
+ enforcement: "client",
297
+ capability: "sealed_history",
298
+ step: "S29",
299
+ says: "Signing out clears the account's Sealed chats, pictures, memory and About you from the phone, after a warning.",
300
+ },
301
+ {
302
+ id: "sealed.adult_setting_web_known_adult",
303
+ status: "planned",
304
+ enforcement: "server_and_client",
305
+ capability: null,
306
+ step: "S29",
307
+ says: "The adult setting (D17) changes only on the web, only a member Minds knows is 18 or over can turn it on, and the phone only reads it.",
308
+ },
309
+ {
310
+ id: "sealed.search_question_only",
311
+ status: "planned",
312
+ enforcement: "client",
313
+ capability: "chat_tier",
314
+ step: "S29",
315
+ says: "A Sealed message that searches carries only the question: no earlier message, memory, About you or phone picture.",
316
+ },
317
+ {
318
+ id: "sealed.search_off_with_others_content",
319
+ status: "planned",
320
+ enforcement: "client",
321
+ capability: "chat_tier",
322
+ step: "S29",
323
+ says: "A Sealed message that carries someone else's words (a post, a members-only post, or messages from any chat) does not search.",
324
+ },
325
+ {
326
+ id: "sealed.search_shown_as_sent",
327
+ status: "planned",
328
+ enforcement: "client",
329
+ capability: "chat_tier",
330
+ step: "S29",
331
+ says: "The search words shown are the words Exa got (the filter's redacted query), and each page opened is shown with its full address.",
332
+ },
333
+ {
334
+ id: "sealed.temporary_not_saved",
335
+ status: "planned",
336
+ enforcement: "client",
337
+ capability: "sealed_history",
338
+ step: "S29",
339
+ says: "A temporary Sealed chat writes nothing to the phone: no history, picture or memory.",
340
+ },
341
+ {
342
+ id: "sealed.services_from_path",
343
+ status: "planned",
344
+ enforcement: "client",
345
+ capability: "chat_tier",
346
+ step: "S29",
347
+ says: "'Other services this chat used' is computed from the path the chat's turns took.",
348
+ },
349
+ {
350
+ id: "sealed.export_to_phone_only",
351
+ status: "planned",
352
+ enforcement: "client",
353
+ capability: "sealed_history",
354
+ step: "S29",
355
+ says: "Exporting a Sealed chat writes a file on the phone and sends nothing.",
356
+ },
93
357
  ];
@@ -1,5 +1,6 @@
1
1
  import type { HttpClient } from '../client.js';
2
2
  import type { SingleResponse } from '../types.js';
3
+ import type { TrustEnvelope } from './trust.js';
3
4
  export type ModerationTargetType = 'post' | 'user' | 'message' | 'community' | 'agent' | 'source_actor' | 'source_post';
4
5
  export type ModerationActionType = 'down_rank' | 'label' | 'remove' | 'suspend' | 'ban';
5
6
  export type ModerationAppealStatus = 'none' | 'pending' | 'upheld' | 'overturned';
@@ -8,9 +9,30 @@ export interface ModerationPrinciple {
8
9
  title: string;
9
10
  summary: string;
10
11
  }
12
+ /**
13
+ * Whether a decision is in the signed trust log, by the server's check (0.7.96): `verified` (signed, and its signature,
14
+ * hash and link to the event before it hold), `unverified` (signed, and one of those does not), `unsigned` (decided
15
+ * before the log was written, or not signed yet), `unavailable` (the log could not be read just now).
16
+ */
17
+ export type ModerationTrustStatus = 'verified' | 'unverified' | 'unsigned' | 'unavailable';
18
+ /** One decision's signed envelopes: where they sit in the chain and what signed them, never the moderator, the subject or a hash. */
19
+ export interface ModerationTrustLog {
20
+ status: ModerationTrustStatus;
21
+ decision: TrustEnvelope | null;
22
+ reversal: TrustEnvelope | null;
23
+ }
24
+ /** The page as a whole: unverified if any action is, verified if any is signed, else unsigned. */
25
+ export interface ModerationTrustWindow {
26
+ status: ModerationTrustStatus;
27
+ verified: number;
28
+ unverified: number;
29
+ unsigned: number;
30
+ }
11
31
  export interface PublicModerationAction {
12
32
  id: string;
13
33
  target_type: ModerationTargetType;
34
+ /** One sentence: what kind of thing was acted on and how, never which one. */
35
+ description?: string;
14
36
  action: ModerationActionType;
15
37
  policy: string | null;
16
38
  actor_type: 'human' | 'ai' | 'system';
@@ -18,6 +40,8 @@ export interface PublicModerationAction {
18
40
  reversed_at: string | null;
19
41
  created_at: string;
20
42
  appeal_status: ModerationAppealStatus;
43
+ /** Present once the operator turns on the signed log's reads (TRUST_LOG_PUBLIC_READS); absent before. */
44
+ trust_log?: ModerationTrustLog;
21
45
  }
22
46
  export interface PublicModerationLog {
23
47
  principles: ModerationPrinciple[];
@@ -27,6 +51,8 @@ export interface PublicModerationLog {
27
51
  offset: number;
28
52
  has_more: boolean;
29
53
  };
54
+ /** Present once the operator turns on the signed log's reads; absent before. */
55
+ trust_log?: ModerationTrustWindow;
30
56
  }
31
57
  export interface OwnModerationAppeal {
32
58
  id: string;
@@ -0,0 +1,85 @@
1
+ import type { HttpClient } from '../client.js';
2
+ import type { SingleResponse } from '../types.js';
3
+ /**
4
+ * Where one event sits in the signed trust log, which key signed it, and whether the server's check of it holds
5
+ * (0.7.96). The public moderation log carries one per signed decision and reversal (`PublicModerationAction.trust_log`):
6
+ * never the moderator, the subject or the payload, and never a hash or a signature. The log's v1 encoding signs the
7
+ * moderator and the subject unsalted, so a published hash or signature would let anyone test guesses of who acted on
8
+ * what; `verified` is the server's verdict, not something a client re-checks.
9
+ */
10
+ export interface TrustEnvelope {
11
+ /** The chain the event is on: the network's id. */
12
+ chain: string;
13
+ seq: number;
14
+ key_id: string;
15
+ algorithm: 'ed25519';
16
+ occurred_at: string;
17
+ /** The server's own check: the signature, the hash, and the link to the event before it. */
18
+ verified: boolean;
19
+ }
20
+ /** One of the caller's own events: what they did, where it sits in the log, and the server's check of it. */
21
+ export interface OwnTrustEvent extends TrustEnvelope {
22
+ id: number;
23
+ network_id: string;
24
+ project_id: string | null;
25
+ /** e.g. `follow`, `unfollow`, `block`, `mute`, `hide`, `appeal`, `moderation_action` (a moderator's own decision). */
26
+ kind: string;
27
+ actor: {
28
+ kind: 'user' | 'agent' | 'system';
29
+ user_id: string | null;
30
+ principal_id: string | null;
31
+ };
32
+ subject: {
33
+ kind: string;
34
+ id: string | null;
35
+ key: string | null;
36
+ principal_id: string | null;
37
+ };
38
+ payload: Record<string, unknown>;
39
+ }
40
+ /** A public key that signed the log. A retired or compromised key still verifies what it signed before that instant. */
41
+ export interface TrustPublicKey {
42
+ key_id: string;
43
+ algorithm: 'ed25519';
44
+ /** base64 SPKI DER. */
45
+ public_key: string;
46
+ activated_at: string | null;
47
+ retired_at: string | null;
48
+ compromised_at: string | null;
49
+ }
50
+ export interface OwnTrustEvents {
51
+ events: OwnTrustEvent[];
52
+ /** The keys that signed this page's events. */
53
+ keys: TrustPublicKey[];
54
+ pagination: {
55
+ limit: number;
56
+ before: number | null;
57
+ has_more: boolean;
58
+ next_before: number | null;
59
+ };
60
+ }
61
+ /**
62
+ * The signed trust log (0.7.96). Both reads answer 404 (`NotFoundError`) until the operator turns on
63
+ * TRUST_LOG_PUBLIC_READS. Signed moderation decisions are on the public moderation log itself
64
+ * (`r.moderation.publicLog`, `trust_log` on each action).
65
+ */
66
+ export declare class TrustResource {
67
+ private client;
68
+ constructor(client: HttpClient);
69
+ /**
70
+ * Keyless: every public key that ever signed the log, retired and compromised ones included. Public material: pin
71
+ * them to see a rotation, or check a full row an auditor holds.
72
+ */
73
+ keys(): Promise<SingleResponse<{
74
+ keys: TrustPublicKey[];
75
+ }>>;
76
+ /**
77
+ * The caller's own events, newest first: the follows, blocks, mutes, hides and appeals they made (a moderator's own
78
+ * decisions too), each with where it sits in the log and the server's check. Never a hash or a signature. Page with
79
+ * `before: pagination.next_before`. Needs `users:read`.
80
+ */
81
+ mine(params?: {
82
+ before?: number;
83
+ limit?: number;
84
+ }): Promise<SingleResponse<OwnTrustEvents>>;
85
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The signed trust log (0.7.96). Both reads answer 404 (`NotFoundError`) until the operator turns on
3
+ * TRUST_LOG_PUBLIC_READS. Signed moderation decisions are on the public moderation log itself
4
+ * (`r.moderation.publicLog`, `trust_log` on each action).
5
+ */
6
+ export class TrustResource {
7
+ client;
8
+ constructor(client) {
9
+ this.client = client;
10
+ }
11
+ /**
12
+ * Keyless: every public key that ever signed the log, retired and compromised ones included. Public material: pin
13
+ * them to see a rotation, or check a full row an auditor holds.
14
+ */
15
+ keys() {
16
+ return this.client.get('/transparency/trust/keys');
17
+ }
18
+ /**
19
+ * The caller's own events, newest first: the follows, blocks, mutes, hides and appeals they made (a moderator's own
20
+ * decisions too), each with where it sits in the log and the server's check. Never a hash or a signature. Page with
21
+ * `before: pagination.next_before`. Needs `users:read`.
22
+ */
23
+ mine(params = {}) {
24
+ return this.client.get('/trust/me', { before: params.before, limit: params.limit });
25
+ }
26
+ }
@@ -1,5 +1,5 @@
1
1
  import type { HttpClient } from '../client.js';
2
- import type { PaginatedResponse, SingleResponse } from '../types.js';
2
+ import type { DeleteResponse, PaginatedResponse, SingleResponse } from '../types.js';
3
3
  interface WalletInfo {
4
4
  configured: boolean;
5
5
  address: string | null;
@@ -7,12 +7,41 @@ interface WalletInfo {
7
7
  balance_wei: string | null;
8
8
  user_index: number | null;
9
9
  is_smart_account: boolean | null;
10
+ /** 'custodial_wallet_off_for_members' when a member asks: Minds-held wallets are for agents; members link their own (`createLinkNonce`, `linkWallet`). */
11
+ reason?: string;
10
12
  }
11
13
  interface WalletBalance {
12
14
  configured: boolean;
13
15
  address: string | null;
14
16
  balance: string | null;
15
17
  balance_wei: string | null;
18
+ /** 'custodial_wallet_off_for_members' when a member asks. */
19
+ reason?: string;
20
+ }
21
+ /** A nonce for a wallet link message (EIP-4361), from `createLinkNonce`. */
22
+ export interface WalletLinkNonce {
23
+ /** Put this in the message's `Nonce:` line. One waits per account for ten minutes; asking again replaces it. */
24
+ nonce: string;
25
+ issued_at: string;
26
+ expires_at: string;
27
+ /** The statement line the message must carry word for word; a message without it, or with another one, is refused (`siwe_message_invalid`). */
28
+ statement: string;
29
+ /** The hosts a link message may name as its domain. */
30
+ domains: string[];
31
+ /** The chain ids a link may name. */
32
+ chain_ids: number[];
33
+ /** The EIP-4361 text to sign, when address, chain id, domain and uri were sent; otherwise null. */
34
+ message: string | null;
35
+ }
36
+ /** A wallet on the account: one the member linked by signature, or one imported with their account. */
37
+ export interface WalletLink {
38
+ chain: string;
39
+ chain_id: number | null;
40
+ /** EIP-55 checksummed for a signed link. */
41
+ address: string;
42
+ /** When a signature proved the member holds it; null for an imported address never proved. */
43
+ verified_at: string | null;
44
+ imported: boolean;
16
45
  }
17
46
  interface WalletConfig {
18
47
  configured: boolean;
@@ -94,7 +123,36 @@ export declare class WalletResource {
94
123
  payoutLoginLink(): Promise<SingleResponse<{
95
124
  url: string;
96
125
  }>>;
97
- /** Send ETH from the current user's wallet */
126
+ /**
127
+ * Start linking a wallet the member holds. Returns a one-time nonce (ten
128
+ * minutes). Pass the wallet's address, its chain id, the app's host and URL to
129
+ * also get the EIP-4361 message text to sign. Minds never holds the wallet's
130
+ * key and the wallet is never the login.
131
+ */
132
+ createLinkNonce(params?: {
133
+ address: string;
134
+ chainId: number;
135
+ domain: string;
136
+ uri: string;
137
+ }): Promise<SingleResponse<WalletLinkNonce>>;
138
+ /**
139
+ * Link the wallet that signed `message` (a Sign-In with Ethereum message
140
+ * carrying a nonce from `createLinkNonce`). Plain keys and smart wallets
141
+ * (EIP-1271, and EIP-6492 before deployment) both link. A nonce works once.
142
+ * The link is screened like a send before it is written: 451 for a blocked or
143
+ * unknown region, 403 `wallet_address_sanctioned`, 503 when screening cannot answer.
144
+ */
145
+ linkWallet(message: string, signature: string): Promise<SingleResponse<WalletLink & {
146
+ signer: 'key' | 'smart_wallet';
147
+ }>>;
148
+ /** The member's wallets: links they signed and addresses imported with their account. */
149
+ listLinkedWallets(): Promise<{
150
+ data: WalletLink[];
151
+ meta: Record<string, never>;
152
+ }>;
153
+ /** Unlink an address, on one chain (e.g. 'base') or on every chain when none is named. */
154
+ unlinkWallet(address: string, chain?: string): Promise<DeleteResponse>;
155
+ /** Send ETH from the current user's Minds-held wallet (agents; off for members, who link their own wallet) */
98
156
  send(toAddress: string, amountEth: string): Promise<SingleResponse<unknown>>;
99
157
  /** Check wallet system configuration (admin) */
100
158
  getConfig(): Promise<SingleResponse<WalletConfig>>;
@@ -31,7 +31,35 @@ export class WalletResource {
31
31
  payoutLoginLink() {
32
32
  return this.client.post('/wallet/payouts/login-link', {});
33
33
  }
34
- /** Send ETH from the current user's wallet */
34
+ /**
35
+ * Start linking a wallet the member holds. Returns a one-time nonce (ten
36
+ * minutes). Pass the wallet's address, its chain id, the app's host and URL to
37
+ * also get the EIP-4361 message text to sign. Minds never holds the wallet's
38
+ * key and the wallet is never the login.
39
+ */
40
+ createLinkNonce(params) {
41
+ return this.client.post('/wallet/links/nonce', params ? { address: params.address, chain_id: params.chainId, domain: params.domain, uri: params.uri } : {});
42
+ }
43
+ /**
44
+ * Link the wallet that signed `message` (a Sign-In with Ethereum message
45
+ * carrying a nonce from `createLinkNonce`). Plain keys and smart wallets
46
+ * (EIP-1271, and EIP-6492 before deployment) both link. A nonce works once.
47
+ * The link is screened like a send before it is written: 451 for a blocked or
48
+ * unknown region, 403 `wallet_address_sanctioned`, 503 when screening cannot answer.
49
+ */
50
+ linkWallet(message, signature) {
51
+ return this.client.post('/wallet/links', { message, signature });
52
+ }
53
+ /** The member's wallets: links they signed and addresses imported with their account. */
54
+ listLinkedWallets() {
55
+ return this.client.get('/wallet/links');
56
+ }
57
+ /** Unlink an address, on one chain (e.g. 'base') or on every chain when none is named. */
58
+ unlinkWallet(address, chain) {
59
+ const query = chain ? `?chain=${encodeURIComponent(chain)}` : '';
60
+ return this.client.delete(`/wallet/links/${encodeURIComponent(address)}${query}`);
61
+ }
62
+ /** Send ETH from the current user's Minds-held wallet (agents; off for members, who link their own wallet) */
35
63
  send(toAddress, amountEth) {
36
64
  return this.client.post('/wallet/send', { to_address: toAddress, amount_eth: amountEth });
37
65
  }
package/dist/types.d.ts CHANGED
@@ -242,6 +242,18 @@ export interface MediaItem {
242
242
  * of Watch and clip queues and show the poster instead. Absent when the file plays or is unjudged.
243
243
  */
244
244
  unplayable?: boolean;
245
+ /**
246
+ * On an image only, in the member's own app with Sealed on: the time (ISO 8601) this read found the picture passed
247
+ * Minds' current checks (visibility, holds, adult labels). No hash-bank or image-classifier check runs. Absent for any
248
+ * other item, and whenever a check could not be read. Sealed sends a post picture only while this is under 24 hours
249
+ * old.
250
+ */
251
+ checked_at?: string;
252
+ /**
253
+ * `false` exactly when `checked_at` is set, and absent otherwise: the payload's "not held" mark. Pass the item as it
254
+ * came to `buildSubjectBundle` (`@recursiv/sdk/assistant`), which keeps `checked_at` only beside `held: false`.
255
+ */
256
+ held?: false;
245
257
  }
246
258
  /** The group a post is in, as every post payload carries it. */
247
259
  export interface PostCommunity {
package/llm.md CHANGED
@@ -851,7 +851,7 @@ const showCheckedLine = isFactLive('sealed.attest_before_send', capabilities, {
851
851
  - `r.email` — Email campaigns, batch sending, and transactional email. **Pass `category: 'transactional'`** for receipts, invites, confirmations and alerts: `r.email.send({ to, subject, html, category: 'transactional' })`. Without it the send is treated as marketing and held for anyone who has not given marketing consent. A send where every recipient was held throws `EmailNotSentError` (its message carries the reason). A `status: 'partial'` result lists each recipient's `status` and `reason` in `messages`.
852
852
  - `r.webhooks` — Register inbound webhook endpoints: `register()`, `list()`, `delete()`. Webhook events execute handler code in project sandbox.
853
853
  - `r.jobs` — Scheduled cron jobs: `create({ name, cron, handler_code })`, `list()`, `update()`, `delete()`. Handlers execute in project sandbox on schedule.
854
- - `r.wallet` — Wallet, MINDS tokens (`getTokenBalance`, `getTokenLedger`; wei stays a string), USD payouts (`getPayouts`, `startPayoutOnboarding`, `payoutLoginLink`)
854
+ - `r.wallet` — Wallet, MINDS tokens (`getTokenBalance`, `getTokenLedger`; wei stays a string), USD payouts (`getPayouts`, `startPayoutOnboarding`, `payoutLoginLink`). Link a wallet the member holds (0.7.104; the server answers 404 `wallet_link_disabled` until it turns linking on): `const { data: n } = await r.wallet.createLinkNonce({ address, chainId: 8453, domain: 'minds.com', uri: 'https://minds.com' })`, have the wallet sign `n.message` (a message you build yourself must carry `n.statement` word for word), then `await r.wallet.linkWallet(n.message, signature)` (plain keys and smart wallets, EIP-1271/6492; a nonce works once; 409 `wallet_linked_to_another_account`; screened like a send: 451 blocked or unknown region, 403 `wallet_address_sanctioned`, 503 `sanctions_screening_unavailable`); `listLinkedWallets()`, `unlinkWallet(address, chain?)`. The Minds-held wallet (`getMyWallet`, `getBalance`, `send`) is for agents: a member gets `configured: false` with `reason: 'custodial_wallet_off_for_members'` and `send` answers 403.
855
855
  - `r.freeTier` — Free tier limits and status
856
856
 
857
857
  ```typescript
@@ -866,6 +866,7 @@ await r.appSubscriptions.changeTier({ tier: 'pro', proration_date: quote.prorati
866
866
  ```
867
867
  - `r.admin` — Admin operations (user management, stats, network settings); content reports: `listReports({ status? })`, `resolveReport(id)`, `dismissReport(id)` (project-bound keys see only their app's reports)
868
868
  - `r.moderation` — Moderation actions. Staff (admin key), 0.7.74: `const { data: actions } = await r.moderation.list({ target_type: 'user', target_id: userId })` reads one target's recorded actions (`ModerationAction`: `id`, `target_type` incl. `source_item`, `action`, `label`, `reason`, `actor_id`, `actor_type`, `source_report_id`, `expires_at`, `reversed_at`, `created_at`), newest first, at most 100, inside the caller's network and a project-bound key's app; `list()` with no target reads the network's latest. Unban = reverse each ban still in force: `for (const a of actions.filter(a => a.action === 'ban' && !a.reversed_at)) await r.moderation.reverse(a.id)`; the target's state is derived again from what is still in force. `reverse` is sent once, never retried: 404 `action_not_found` (`NotFoundError`) means already reversed or not in the caller's scope; 409 `use_judgment_review` means a reviewed label override (change it with `r.judgments.review`). An older SDK has neither method. Also `apply`, `publicLog`, `mine`, `appeal`, `resolveAppeal`, and agent grants `listAgentGrants`, `grantAgent(agentId, 'shadow' | 'act')`, `revokeAgent`.
869
+ - `r.trust` — The signed trust log (0.7.96; both reads answer 404, `NotFoundError`, until the operator turns on `TRUST_LOG_PUBLIC_READS`). `r.trust.keys()` (keyless) lists every public key that ever signed it (`key_id`, `algorithm` `ed25519`, `public_key` base64 SPKI DER, `activated_at`, `retired_at`, `compromised_at`). `r.trust.mine({ before?, limit? })` (`users:read`) reads the caller's own signed events, newest first (their follows, blocks, mutes, hides, appeals, and a moderator's own decisions: `kind`, `actor`, `subject`, `payload`, `chain`, `seq`, `key_id`, `occurred_at`, and the server's check `verified`) with the `keys` that signed the page; page with `before: pagination.next_before`. On the public log, `r.moderation.publicLog(networkId)` then carries `trust_log` on each action (`status`: `verified` | `unverified` | `unsigned` | `unavailable`, and the signed `decision` and `reversal`: `chain`, `seq`, `key_id`, `algorithm`, `occurred_at`, `verified`) and on the page (`status` and the count of each). No read carries a hash or a signature (the v1 encoding signs the moderator and the subject unsalted, so one would let anyone test guesses of who acted on what): `verified` is the server's verdict.
869
870
  - `r.judgments` (0.7.71) — Jev's labels of one post. `get({ kind: 'post' | 'network_post', id })`: switch on `data.view` — `'full'` for the post's author and staff (`judgments` with answers, `safety` verdict, `viral.withheld`; staff also `reviewer_ids`, `review_note`), `'summary'` for other members (`category`, `politics` band in words with its `judgment_id`; never a probability or cell). `data.status === 'unavailable'` (returned, not thrown): hide label actions. `getPublic(projectId, { kind, id })` on an anonymous client: `view: 'category'` only. `dispute(judgmentId, { question_key: 'placement', proposed: 'cm' | … | 'not_political', note? })` (safety: `question_key: 'safety'`, author only): the author's dispute is an appeal; a repeat answers `existing: true`. Staff: `review(judgmentId, { outcome: 'uphold' } | { outcome: 'override', proposed, note?, apply_to_shared? })`, sent once (never retried): a compass override answers 202 `{ status: 'awaiting_reviewer', agreeing, needed }` until a second reviewer (or an agreeing Jev re-judge) proposes the same; a safety override to `'none'` that would free other posts throws 409 `shared_words` (`isJudgmentSharedWordsError(e)`, `e.details.shared_posts`) until resent with `apply_to_shared: true`. Budgets (60 reads/hour, 25 of one author's posts, 20 disputes/day) throw `RateLimitError` with `scope: 'action'` at once. Example: `const { data } = await r.judgments.get({ kind: 'post', id }); if (data.status === 'ok' && data.view === 'summary' && data.politics) await r.judgments.dispute(data.politics.judgment_id, { question_key: 'placement', proposed: 'not_political' })`
870
871
  - `r.inviteCodes` / `r.inviteCodesAdmin` — Invite code management
871
872
  - `r.organizationSettings` / `r.organizationSecurity` — Org configuration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recursiv/sdk",
3
- "version": "0.7.93",
3
+ "version": "0.7.104",
4
4
  "description": "TypeScript SDK for the Recursiv API",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",