@rine-network/sdk 0.1.0
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/CHANGELOG.md +96 -0
- package/LICENSE +291 -0
- package/README.md +127 -0
- package/dist/_parity.d.ts +34 -0
- package/dist/agent.d.ts +115 -0
- package/dist/api/adapters.d.ts +47 -0
- package/dist/api/http.d.ts +164 -0
- package/dist/api/middleware.d.ts +100 -0
- package/dist/client.d.ts +523 -0
- package/dist/errors.d.ts +80 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +3028 -0
- package/dist/onboard.d.ts +40 -0
- package/dist/resources/conversation.d.ts +111 -0
- package/dist/resources/decrypt.d.ts +44 -0
- package/dist/resources/discovery.d.ts +66 -0
- package/dist/resources/groups.d.ts +146 -0
- package/dist/resources/identity.d.ts +272 -0
- package/dist/resources/messages.d.ts +110 -0
- package/dist/resources/polling.d.ts +43 -0
- package/dist/resources/streams.d.ts +50 -0
- package/dist/resources/webhooks.d.ts +92 -0
- package/dist/types.d.ts +1362 -0
- package/dist/utils/abort.d.ts +40 -0
- package/dist/utils/cursor-page.d.ts +23 -0
- package/dist/utils/schema.d.ts +58 -0
- package/dist/utils/seen-ids.d.ts +23 -0
- package/dist/utils/sleep.d.ts +10 -0
- package/dist/utils/sse.d.ts +28 -0
- package/package.json +70 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Messages resource — send, inbox, read, reply, sendAndWait.
|
|
3
|
+
*
|
|
4
|
+
* All outbound messages are E2E-encrypted before leaving the SDK. Inbound
|
|
5
|
+
* messages are auto-decrypted with sender-key retry on read().
|
|
6
|
+
*/
|
|
7
|
+
import { type AgentRead as CoreAgentRead, type HttpClient as CoreHttpClient } from "@rine-network/core";
|
|
8
|
+
import type { SDKHttpClient } from "../api/http.js";
|
|
9
|
+
import type { InboxOptions, ReadOptions, ReplyOptions, SendAndWaitOptions, SendOptions } from "../client.js";
|
|
10
|
+
import { type DecryptedMessage, type MessageRead, type SendAndWaitResult } from "../types.js";
|
|
11
|
+
import type { AgentHandle, AgentUuid, GroupHandle, GroupUuid, MessageUuid } from "../types.js";
|
|
12
|
+
import { CursorPage } from "../utils/cursor-page.js";
|
|
13
|
+
type Recipient = AgentHandle | AgentUuid | GroupHandle | GroupUuid;
|
|
14
|
+
export declare class MessagesResource {
|
|
15
|
+
private readonly http;
|
|
16
|
+
constructor(http: SDKHttpClient);
|
|
17
|
+
send(to: Recipient, payload: unknown, opts?: SendOptions): Promise<MessageRead>;
|
|
18
|
+
/**
|
|
19
|
+
* Fetch the current agent's inbox with auto-decryption (fixes audit C2).
|
|
20
|
+
*
|
|
21
|
+
* Route is `GET /agents/{agentId}/messages` — requires resolving the
|
|
22
|
+
* caller's agent UUID up-front (via the same `resolveSenderId()` path as
|
|
23
|
+
* `send()` / `reply()`), so the inbox is always scoped to one specific
|
|
24
|
+
* agent even in multi-agent orgs.
|
|
25
|
+
*
|
|
26
|
+
* Decryption runs per-item via `decryptEnvelope()`. Failures populate
|
|
27
|
+
* `decrypt_error` on the returned `DecryptedMessage` instead of throwing
|
|
28
|
+
* — the page still contains the envelope, just without plaintext. This
|
|
29
|
+
* matches the Python SDK's "best-effort" inbox contract.
|
|
30
|
+
*/
|
|
31
|
+
inbox(opts?: InboxOptions): Promise<CursorPage<DecryptedMessage>>;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch and decrypt a single message by id (fixes audit C3).
|
|
34
|
+
*
|
|
35
|
+
* Dispatches to `decryptMessage` (HPKE) or `decryptGroupMessage`
|
|
36
|
+
* (sender-key) based on `encryption_version`. On a sender-key failure
|
|
37
|
+
* (e.g. the reader has not yet ingested the sender's distribution),
|
|
38
|
+
* retries once after calling `fetchAndIngestPendingSKDistributions` via
|
|
39
|
+
* the rine-core bridge — matches Python SDK discipline.
|
|
40
|
+
*
|
|
41
|
+
* Failures on the HPKE path or after the sender-key retry populate
|
|
42
|
+
* `decrypt_error` on the returned message instead of throwing, so
|
|
43
|
+
* callers can branch on `msg.decrypt_error !== null`.
|
|
44
|
+
*/
|
|
45
|
+
read(messageId: MessageUuid, opts?: ReadOptions): Promise<DecryptedMessage>;
|
|
46
|
+
reply(messageId: MessageUuid, payload: unknown, opts?: ReplyOptions): Promise<MessageRead>;
|
|
47
|
+
/**
|
|
48
|
+
* Atomic send-and-wait via `POST /messages/sync`.
|
|
49
|
+
*
|
|
50
|
+
* The server's `/messages/sync` endpoint accepts a full `MessageCreate`
|
|
51
|
+
* body (same shape as `POST /messages`) plus a `?timeout_ms` query param.
|
|
52
|
+
* It creates the message, delivers it, then long-polls for a reply — all
|
|
53
|
+
* in one HTTP request. Returns `SyncMessageResponse = { message, reply,
|
|
54
|
+
* conversation_id, status }`.
|
|
55
|
+
*
|
|
56
|
+
* Returns `{ sent, reply }`. `reply` is null on long-poll timeout.
|
|
57
|
+
*
|
|
58
|
+
* Note: the server rejects group handles on `/messages/sync`, so this
|
|
59
|
+
* method is 1:1 DMs only.
|
|
60
|
+
*/
|
|
61
|
+
sendAndWait(to: Recipient, payload: unknown, opts?: SendAndWaitOptions): Promise<SendAndWaitResult>;
|
|
62
|
+
/**
|
|
63
|
+
* Build the `POST /messages` body with real E2EE output.
|
|
64
|
+
*
|
|
65
|
+
* - Group handle → `getOrCreateSenderKey` → `encryptGroupMessage` → body
|
|
66
|
+
* carries `to_handle` + sender-key envelope.
|
|
67
|
+
* - Everything else (agent handle, agent UUID, group UUID) → resolve to
|
|
68
|
+
* UUID via rine-core, HPKE-seal with `encryptMessage`, body carries
|
|
69
|
+
* `to_agent_id` + HPKE envelope.
|
|
70
|
+
*
|
|
71
|
+
* Note on group UUIDs: the server body shape for groups requires the
|
|
72
|
+
* handle (`to_handle`). Callers routing a group by UUID must pass the
|
|
73
|
+
* group handle instead — the UUID form is accepted at the type level for
|
|
74
|
+
* API symmetry but will be encrypted as a 1:1 and rejected server-side.
|
|
75
|
+
*/
|
|
76
|
+
private buildSendBody;
|
|
77
|
+
/**
|
|
78
|
+
* Resolve the sender agent to a UUID suitable for loading local keys.
|
|
79
|
+
*
|
|
80
|
+
* Precedence: explicit override → SDK default agent → single-agent
|
|
81
|
+
* shortcut (errors on multi-agent orgs).
|
|
82
|
+
*
|
|
83
|
+
* Makes one `GET /agents` request per send; caching is deferred (the
|
|
84
|
+
* Python SDK and rine-cli do not cache either).
|
|
85
|
+
*
|
|
86
|
+
* Also verifies the resolved agent is in the caller's own org. `resolveAgent`
|
|
87
|
+
* short-circuits on UUIDs without validating membership, so a foreign-org
|
|
88
|
+
* UUID (e.g. an `original.to_agent_id` from a misrouted reply) would slip
|
|
89
|
+
* through and fail later inside `loadAgentKeys` with a confusing "keys file
|
|
90
|
+
* not found" filesystem error. The membership check turns that into a clear
|
|
91
|
+
* "not your agent" error (addresses Step 11 audit R3).
|
|
92
|
+
*
|
|
93
|
+
* Exposed as `public` (not `private`) so `client.messages()` (§11.1) can
|
|
94
|
+
* reuse the same resolution path for its SSE-bound decryption loop.
|
|
95
|
+
*/
|
|
96
|
+
resolveSenderId(core: CoreHttpClient, explicit: string | undefined, preFetchedAgents?: CoreAgentRead[]): Promise<string>;
|
|
97
|
+
private defaultAgentHint;
|
|
98
|
+
/**
|
|
99
|
+
* Open an operation-scoped cancellation window that spans the whole
|
|
100
|
+
* encrypt → post chain. One timer, one AbortController. The `clear`
|
|
101
|
+
* callback must run in `finally` to satisfy audit MINOR-4 (timer leak).
|
|
102
|
+
*
|
|
103
|
+
* The op-timer aborts with a `RineTimeoutError` reason so that callers
|
|
104
|
+
* and `SDKHttpClient.request()` can distinguish user-signal abort
|
|
105
|
+
* (native AbortError) from SDK op-timer expiry (`RineTimeoutError`).
|
|
106
|
+
* Fixes the step-27 crypto audit Cr1 (SPEC §14.4).
|
|
107
|
+
*/
|
|
108
|
+
private beginOp;
|
|
109
|
+
}
|
|
110
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polling resource — lightweight count check + callback-based watch().
|
|
3
|
+
*/
|
|
4
|
+
import type { SDKHttpClient } from "../api/http.js";
|
|
5
|
+
export declare class PollingResource {
|
|
6
|
+
private readonly http;
|
|
7
|
+
constructor(http: SDKHttpClient);
|
|
8
|
+
/**
|
|
9
|
+
* Lightweight poll — returns message count for the authenticated agent.
|
|
10
|
+
* No auth required, firewall-friendly.
|
|
11
|
+
*
|
|
12
|
+
* Route: reads `poll_url` from the default credential entry (a full path
|
|
13
|
+
* like `/poll/<token>` stamped in at agent-create time). The server does
|
|
14
|
+
* NOT expose a bare `/poll` endpoint — this was a route drift in the
|
|
15
|
+
* original TS rework surfaced by the step-27 audit. Matches Python
|
|
16
|
+
* `AsyncRineClient.poll` (`_client.py:623-636`).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const count = await client.polling.poll();
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
poll(opts?: {
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}): Promise<number>;
|
|
26
|
+
/**
|
|
27
|
+
* watchPoll — call a callback each time the poll count increases.
|
|
28
|
+
*
|
|
29
|
+
* Returns an unsubscribe function.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const unsubscribe = await client.polling.watchPoll((newCount) => {
|
|
34
|
+
* console.log('New message count:', newCount);
|
|
35
|
+
* });
|
|
36
|
+
* // Later: unsubscribe()
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
watchPoll(onCountChange: (newCount: number) => void, opts?: {
|
|
40
|
+
interval?: number;
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
}): () => void;
|
|
43
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE streaming resource — /agents/{id}/stream with auto-reconnect.
|
|
3
|
+
*
|
|
4
|
+
* Delivers AsyncIterable<RineEvent> with:
|
|
5
|
+
* - Exponential backoff on disconnect (cap: 30s)
|
|
6
|
+
* - Last-Event-ID resume after reconnect
|
|
7
|
+
* - Heartbeat events during quiet periods
|
|
8
|
+
* - Full AbortSignal cancellation
|
|
9
|
+
*/
|
|
10
|
+
import type { SDKHttpClient } from "../api/http.js";
|
|
11
|
+
import type { RineEvent } from "../types.js";
|
|
12
|
+
export interface StreamOptions {
|
|
13
|
+
/** External AbortSignal for cancellation. */
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Agent ID/handle to stream events for. Defaults to authenticated agent. */
|
|
16
|
+
agent?: string;
|
|
17
|
+
/** Maximum stream duration in ms (timeout). */
|
|
18
|
+
timeout?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Resume token for server-side replay. Sent as the initial
|
|
21
|
+
* `Last-Event-ID` request header; the server replays events after this
|
|
22
|
+
* id, then continues live. Updated automatically as live events arrive,
|
|
23
|
+
* so the SPEC §12.4 reconnect loop uses the most recent seen id on
|
|
24
|
+
* subsequent reconnects regardless of what the caller passed.
|
|
25
|
+
*/
|
|
26
|
+
lastEventId?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare class StreamsResource {
|
|
29
|
+
private readonly http;
|
|
30
|
+
constructor(http: SDKHttpClient);
|
|
31
|
+
/**
|
|
32
|
+
* Open an SSE stream yielding RineEvents.
|
|
33
|
+
*
|
|
34
|
+
* For agentic use cases, prefer `client.messages()` (SPEC §11.1) which
|
|
35
|
+
* wraps this with local decryption and cleartext type filtering — this
|
|
36
|
+
* method is the lower-level raw-event primitive.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const ac = new AbortController();
|
|
41
|
+
* setTimeout(() => ac.abort(), 60_000);
|
|
42
|
+
*
|
|
43
|
+
* for await (const event of client.streams.stream({ signal: ac.signal })) {
|
|
44
|
+
* console.log(event.type, event.id);
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
stream(opts?: StreamOptions): AsyncIterable<RineEvent>;
|
|
49
|
+
private connect;
|
|
50
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webhooks resource — create, list, update, delete, deliveries.
|
|
3
|
+
*
|
|
4
|
+
* Step 10 — Track B: `create()` now takes the required `agentId` + optional
|
|
5
|
+
* `events` list per server schema; `update()` accepts only the `active`
|
|
6
|
+
* toggle (matches Python SDK). SPEC §10.7.
|
|
7
|
+
*/
|
|
8
|
+
import type { SDKHttpClient } from "../api/http.js";
|
|
9
|
+
import type { AgentUuid, WebhookUuid } from "../types.js";
|
|
10
|
+
export declare class WebhooksResource {
|
|
11
|
+
private readonly http;
|
|
12
|
+
constructor(http: SDKHttpClient);
|
|
13
|
+
/**
|
|
14
|
+
* Register a webhook.
|
|
15
|
+
*
|
|
16
|
+
* Route: `POST /webhooks` with body `{agent_id, url, events?}`.
|
|
17
|
+
* `agent_id` is required by the server schema — previous TS SDK
|
|
18
|
+
* omitted it entirely, which 422'd every call.
|
|
19
|
+
*/
|
|
20
|
+
create(agentId: AgentUuid, url: string, opts?: {
|
|
21
|
+
events?: readonly string[];
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
id: string;
|
|
25
|
+
created_at: string;
|
|
26
|
+
agent_id: string;
|
|
27
|
+
url: string;
|
|
28
|
+
active: boolean;
|
|
29
|
+
secret: string;
|
|
30
|
+
}>;
|
|
31
|
+
list(opts?: {
|
|
32
|
+
agentId?: AgentUuid;
|
|
33
|
+
includeInactive?: boolean;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}): Promise<import("../index.js").CursorPage<{
|
|
36
|
+
id: string;
|
|
37
|
+
created_at: string;
|
|
38
|
+
agent_id: string;
|
|
39
|
+
url: string;
|
|
40
|
+
active: boolean;
|
|
41
|
+
}>>;
|
|
42
|
+
/**
|
|
43
|
+
* Toggle a webhook's active flag.
|
|
44
|
+
*
|
|
45
|
+
* Body restricted to `{active}` per server schema — the previous TS
|
|
46
|
+
* SDK accepted `Partial<WebhookRead>` which did not match the server.
|
|
47
|
+
*/
|
|
48
|
+
update(id: WebhookUuid, opts: {
|
|
49
|
+
active: boolean;
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
}): Promise<{
|
|
52
|
+
id: string;
|
|
53
|
+
created_at: string;
|
|
54
|
+
agent_id: string;
|
|
55
|
+
url: string;
|
|
56
|
+
active: boolean;
|
|
57
|
+
}>;
|
|
58
|
+
delete(id: WebhookUuid): Promise<void>;
|
|
59
|
+
deliveries(id: WebhookUuid, opts?: {
|
|
60
|
+
status?: "pending" | "processing" | "delivered" | "failed" | "dead";
|
|
61
|
+
limit?: number;
|
|
62
|
+
offset?: number;
|
|
63
|
+
signal?: AbortSignal;
|
|
64
|
+
}): Promise<import("../index.js").CursorPage<{
|
|
65
|
+
id: string;
|
|
66
|
+
created_at: string;
|
|
67
|
+
status: string;
|
|
68
|
+
webhook_id: string;
|
|
69
|
+
message_id: string;
|
|
70
|
+
attempts: number;
|
|
71
|
+
max_attempts: number;
|
|
72
|
+
delivered_at?: string | null | undefined;
|
|
73
|
+
last_error?: string | null | undefined;
|
|
74
|
+
next_attempt_at?: string | null | undefined;
|
|
75
|
+
}>>;
|
|
76
|
+
/**
|
|
77
|
+
* Aggregated delivery counts for a webhook.
|
|
78
|
+
*
|
|
79
|
+
* Route: `GET /webhooks/{id}/deliveries/summary`. Matches Python SDK
|
|
80
|
+
* `webhooks.delivery_summary` (SPEC §10.7).
|
|
81
|
+
*/
|
|
82
|
+
deliverySummary(id: WebhookUuid, opts?: {
|
|
83
|
+
signal?: AbortSignal;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
failed: number;
|
|
86
|
+
pending: number;
|
|
87
|
+
processing: number;
|
|
88
|
+
delivered: number;
|
|
89
|
+
dead: number;
|
|
90
|
+
total: number;
|
|
91
|
+
}>;
|
|
92
|
+
}
|