@recursiv/sdk 0.7.93 → 0.7.96

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
@@ -120,6 +120,7 @@ for await (const chunk of r.agents.chatStream(agent.id, { message: 'Hello!' }))
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 |
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';
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';
@@ -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
+ }
package/llm.md CHANGED
@@ -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.96",
4
4
  "description": "TypeScript SDK for the Recursiv API",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",