@rayrun/sdk 0.2.0 → 0.3.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/README.md +27 -2
- package/index.d.ts +85 -3
- package/index.js +28 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,8 +14,28 @@ const { items: connections } = await rayrun.connections.list();
|
|
|
14
14
|
Create keys in **Dashboard → Settings → API keys**. The plaintext is shown once.
|
|
15
15
|
|
|
16
16
|
The client covers catalog search, connection and credential setup, OAuth links, indexing, tool and
|
|
17
|
-
client policies, activity, review queues, and webhooks. Safe reads retry
|
|
18
|
-
and transient network failures; writes do not retry automatically.
|
|
17
|
+
client policies, reusable access profiles, activity, review queues, and webhooks. Safe reads retry
|
|
18
|
+
rate limits, server errors, and transient network failures; writes do not retry automatically.
|
|
19
|
+
|
|
20
|
+
## Reuse one access ceiling across clients
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const { profile } = await rayrun.accessProfiles.create({
|
|
24
|
+
name: 'Support agents',
|
|
25
|
+
description: 'Read by default; sensitive tools stay blocked.',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await rayrun.accessProfiles.setPolicy(profile.uid, 'read-only', profile.toolPolicyVersion);
|
|
29
|
+
await rayrun.accessProfiles.update(profile.uid, {
|
|
30
|
+
description: 'Read by default; sensitive tools stay blocked.',
|
|
31
|
+
expectedVersion: profile.toolPolicyVersion + 1,
|
|
32
|
+
name: 'Support agents',
|
|
33
|
+
});
|
|
34
|
+
await rayrun.clients.setAccessProfile(clientUid, profile.uid, clientToolPolicyVersion);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The effective policy is always the intersection of the workspace, profile, and client rules. A
|
|
38
|
+
profile can narrow access but cannot grant something blocked by the workspace or client.
|
|
19
39
|
|
|
20
40
|
## Stream code run-ahead
|
|
21
41
|
|
|
@@ -73,6 +93,11 @@ const valid = verifyWebhookSignature({
|
|
|
73
93
|
|
|
74
94
|
After verification, parse the body as `WebhookPayload`. Every event has a stable `id`, `type`, and
|
|
75
95
|
`occurredAt`; its `data` shape is narrowed by `type`. Use `id` to deduplicate retries.
|
|
96
|
+
For `activity.call`, `arguments` and `result` contain the captured tool payloads, or `null` when
|
|
97
|
+
capture was disabled for that connection, the webhook did not opt in with
|
|
98
|
+
`forwardToolPayloads: true`, or no result existed. `payloadCaptured` distinguishes a metadata-only
|
|
99
|
+
webhook from a call where capture was disabled. Rayrun observes MCP tool arguments and results; it
|
|
100
|
+
does not receive the host's full Claude or GPT prompt, assistant response, or surrounding chat.
|
|
76
101
|
|
|
77
102
|
```ts
|
|
78
103
|
import type { WebhookPayload } from '@rayrun/sdk';
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
/* oxlint-disable perfectionist/sort-classes, perfectionist/sort-modules, perfectionist/sort-object-types, perfectionist/sort-union-types -- Public types follow the documented API resource order. */
|
|
2
2
|
export type CursorPage<T> = { items: T[]; page: { nextCursor: string | null } };
|
|
3
|
+
export type JsonValue =
|
|
4
|
+
| boolean
|
|
5
|
+
| null
|
|
6
|
+
| number
|
|
7
|
+
| string
|
|
8
|
+
| JsonValue[]
|
|
9
|
+
| { [key: string]: JsonValue };
|
|
3
10
|
export type PageQuery = { cursor?: string; limit?: number };
|
|
4
11
|
export type ToolDecision = 'allow' | 'ask' | 'block';
|
|
5
12
|
export type ToolAccessMode = 'read-only' | 'ask-before-changes' | 'allow-all' | 'custom';
|
|
13
|
+
export type AccessProfileMode = 'read-only' | 'ask-before-changes' | 'allow-all' | 'block-all';
|
|
6
14
|
export type Risk = 'read' | 'change' | 'destructive' | 'unknown';
|
|
7
15
|
export type Connection = {
|
|
8
16
|
authorizedAt: string | null;
|
|
@@ -17,6 +25,7 @@ export type Connection = {
|
|
|
17
25
|
slug: string;
|
|
18
26
|
status: 'connected' | 'disabled' | 'error' | 'indexing' | 'needs-authorization' | 'new';
|
|
19
27
|
toolAccessMode: ToolAccessMode;
|
|
28
|
+
toolPolicyVersion: number;
|
|
20
29
|
};
|
|
21
30
|
export type CatalogEntry = {
|
|
22
31
|
authType: Connection['authType'];
|
|
@@ -43,15 +52,33 @@ export type Tool = {
|
|
|
43
52
|
title: string | null;
|
|
44
53
|
};
|
|
45
54
|
export type Client = {
|
|
55
|
+
accessProfile: Pick<AccessProfile, 'name' | 'uid'> | null;
|
|
46
56
|
clientName: string;
|
|
47
57
|
grantedAt: string;
|
|
48
58
|
lastUsedAt: string | null;
|
|
49
59
|
redirectHost: string;
|
|
50
60
|
revokedAt: string | null;
|
|
51
61
|
toolAccessMode: ToolAccessMode;
|
|
62
|
+
toolPolicyVersion: number;
|
|
52
63
|
uid: string;
|
|
53
64
|
userName: string;
|
|
54
65
|
};
|
|
66
|
+
export type AccessProfile = {
|
|
67
|
+
assignedClientCount: number;
|
|
68
|
+
description: string;
|
|
69
|
+
name: string;
|
|
70
|
+
toolAccessMode: AccessProfileMode;
|
|
71
|
+
toolPolicyVersion: number;
|
|
72
|
+
uid: string;
|
|
73
|
+
};
|
|
74
|
+
export type AccessProfileTool = {
|
|
75
|
+
available: boolean;
|
|
76
|
+
decision: ToolDecision | null;
|
|
77
|
+
name: string;
|
|
78
|
+
riskLevel: Risk;
|
|
79
|
+
serviceName: string;
|
|
80
|
+
uid: string;
|
|
81
|
+
};
|
|
55
82
|
export type Activity = {
|
|
56
83
|
calledAt: string;
|
|
57
84
|
clientName: string | null;
|
|
@@ -77,6 +104,7 @@ export type Webhook = {
|
|
|
77
104
|
description: string | null;
|
|
78
105
|
enabled: boolean;
|
|
79
106
|
eventTypes: WebhookEvent[];
|
|
107
|
+
forwardToolPayloads: boolean;
|
|
80
108
|
uid: string;
|
|
81
109
|
url: string;
|
|
82
110
|
};
|
|
@@ -103,7 +131,17 @@ export type WebhookEvent =
|
|
|
103
131
|
| 'review.changed'
|
|
104
132
|
| 'tool.definition-changed'
|
|
105
133
|
| 'tool.policy-changed';
|
|
106
|
-
export type
|
|
134
|
+
export type WebhookDeliveryEvent = Exclude<WebhookEvent, '*'> | 'webhook.test';
|
|
135
|
+
export type ToolPolicyEventType =
|
|
136
|
+
| 'access-profile-archived'
|
|
137
|
+
| 'access-profile-assigned'
|
|
138
|
+
| 'access-profile-changed'
|
|
139
|
+
| 'access-profile-created'
|
|
140
|
+
| 'client-mode-changed'
|
|
141
|
+
| 'client-tool-rule-changed'
|
|
142
|
+
| 'workspace-mode-changed'
|
|
143
|
+
| 'workspace-tool-rule-changed';
|
|
144
|
+
export type WebhookEnvelope<T extends WebhookDeliveryEvent, D> = {
|
|
107
145
|
data: D;
|
|
108
146
|
id: string;
|
|
109
147
|
occurredAt: string;
|
|
@@ -114,12 +152,25 @@ export type WebhookPayload =
|
|
|
114
152
|
'activity.call',
|
|
115
153
|
{
|
|
116
154
|
activityId: string;
|
|
155
|
+
arguments: JsonValue;
|
|
117
156
|
calledAt: string;
|
|
157
|
+
clientUid: string | null;
|
|
118
158
|
connectionUid: string | null;
|
|
119
159
|
errorCode: string | null;
|
|
160
|
+
payloadCaptured: boolean;
|
|
120
161
|
policyDecision: ToolDecision | null;
|
|
162
|
+
result: JsonValue;
|
|
163
|
+
sessionUid: string;
|
|
121
164
|
succeeded: boolean | null;
|
|
122
165
|
toolName: string;
|
|
166
|
+
userUid: string | null;
|
|
167
|
+
}
|
|
168
|
+
>
|
|
169
|
+
| WebhookEnvelope<
|
|
170
|
+
'webhook.test',
|
|
171
|
+
{
|
|
172
|
+
endpointUid: string;
|
|
173
|
+
message: string;
|
|
123
174
|
}
|
|
124
175
|
>
|
|
125
176
|
| WebhookEnvelope<
|
|
@@ -159,7 +210,10 @@ export type WebhookPayload =
|
|
|
159
210
|
{
|
|
160
211
|
connectionUid: string | null;
|
|
161
212
|
decision: ToolDecision | null;
|
|
162
|
-
eventType:
|
|
213
|
+
eventType: ToolPolicyEventType;
|
|
214
|
+
metadata: Record<string, JsonValue>;
|
|
215
|
+
oauthClientConsentUid: string | null;
|
|
216
|
+
oauthClientName: string | null;
|
|
163
217
|
toolUid: string | null;
|
|
164
218
|
}
|
|
165
219
|
>;
|
|
@@ -198,7 +252,7 @@ export class Rayrun {
|
|
|
198
252
|
| { kind: 'openapi'; specificationUrl: string; baseUrl?: string; name?: string },
|
|
199
253
|
): Promise<{ connection: { uid: string } }>;
|
|
200
254
|
createOAuthLink(uid: string): Promise<{ authorizationUrl: string }>;
|
|
201
|
-
delete(uid: string): Promise<void>;
|
|
255
|
+
delete(uid: string, expectedVersion: number): Promise<void>;
|
|
202
256
|
index(uid: string): Promise<{ enqueued: boolean }>;
|
|
203
257
|
list(query?: PageQuery): Promise<CursorPage<Connection>>;
|
|
204
258
|
setCredential(uid: string, body: Credential): Promise<{ enqueued: boolean }>;
|
|
@@ -218,6 +272,11 @@ export class Rayrun {
|
|
|
218
272
|
};
|
|
219
273
|
clients: {
|
|
220
274
|
list(query?: PageQuery): Promise<CursorPage<Client>>;
|
|
275
|
+
setAccessProfile(
|
|
276
|
+
uid: string,
|
|
277
|
+
profileUid: string | null,
|
|
278
|
+
expectedVersion: number,
|
|
279
|
+
): Promise<void>;
|
|
221
280
|
setPolicy(uid: string, mode: Exclude<ToolAccessMode, 'custom'>): Promise<void>;
|
|
222
281
|
setToolPolicy(
|
|
223
282
|
uid: string,
|
|
@@ -225,6 +284,28 @@ export class Rayrun {
|
|
|
225
284
|
body: { decision: ToolDecision | null; riskConfirmed?: boolean },
|
|
226
285
|
): Promise<void>;
|
|
227
286
|
};
|
|
287
|
+
accessProfiles: {
|
|
288
|
+
archive(uid: string, expectedVersion: number): Promise<void>;
|
|
289
|
+
create(body: { description: string; name: string }): Promise<{ profile: AccessProfile }>;
|
|
290
|
+
/** @deprecated Use archive. */
|
|
291
|
+
delete(uid: string, expectedVersion: number): Promise<void>;
|
|
292
|
+
list(query?: PageQuery): Promise<CursorPage<AccessProfile>>;
|
|
293
|
+
listTools(uid: string, query?: PageQuery): Promise<CursorPage<AccessProfileTool>>;
|
|
294
|
+
setPolicy(uid: string, mode: AccessProfileMode, expectedVersion: number): Promise<void>;
|
|
295
|
+
setToolPolicy(
|
|
296
|
+
uid: string,
|
|
297
|
+
toolUid: string,
|
|
298
|
+
body: {
|
|
299
|
+
decision: ToolDecision | null;
|
|
300
|
+
expectedVersion: number;
|
|
301
|
+
riskConfirmed?: boolean;
|
|
302
|
+
},
|
|
303
|
+
): Promise<void>;
|
|
304
|
+
update(
|
|
305
|
+
uid: string,
|
|
306
|
+
body: { description: string; expectedVersion: number; name: string },
|
|
307
|
+
): Promise<void>;
|
|
308
|
+
};
|
|
228
309
|
activity: { list(query?: PageQuery): Promise<CursorPage<Activity>> };
|
|
229
310
|
reviews: { list(query?: PageQuery): Promise<CursorPage<Review>> };
|
|
230
311
|
webhooks: {
|
|
@@ -232,6 +313,7 @@ export class Rayrun {
|
|
|
232
313
|
url: string;
|
|
233
314
|
description?: string | null;
|
|
234
315
|
eventTypes: WebhookEvent[];
|
|
316
|
+
forwardToolPayloads?: boolean;
|
|
235
317
|
}): Promise<{ uid: string; secret: string }>;
|
|
236
318
|
delete(uid: string): Promise<void>;
|
|
237
319
|
list(): Promise<{ items: Webhook[] }>;
|
package/index.js
CHANGED
|
@@ -80,6 +80,8 @@ export const verifyWebhookSignature = ({
|
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
export class Rayrun {
|
|
83
|
+
#apiKey;
|
|
84
|
+
|
|
83
85
|
constructor({
|
|
84
86
|
apiKey,
|
|
85
87
|
baseUrl = 'https://ray.run',
|
|
@@ -88,7 +90,7 @@ export class Rayrun {
|
|
|
88
90
|
if (!apiKey) throw new TypeError('Rayrun requires an apiKey.');
|
|
89
91
|
if (!fetchImplementation) throw new TypeError('Rayrun requires a fetch implementation.');
|
|
90
92
|
|
|
91
|
-
this
|
|
93
|
+
this.#apiKey = apiKey;
|
|
92
94
|
this.baseUrl = baseUrl.replace(/\/$/u, '');
|
|
93
95
|
this.fetch = fetchImplementation;
|
|
94
96
|
|
|
@@ -112,10 +114,30 @@ export class Rayrun {
|
|
|
112
114
|
};
|
|
113
115
|
this.clients = {
|
|
114
116
|
list: (query) => this.request('GET', '/clients', { query }),
|
|
117
|
+
setAccessProfile: (uid, profileUid, expectedVersion) =>
|
|
118
|
+
this.request('PATCH', `/clients/${uid}/access-profile`, {
|
|
119
|
+
body: { expectedVersion, profileUid },
|
|
120
|
+
}),
|
|
115
121
|
setPolicy: (uid, mode) => this.request('PATCH', `/clients/${uid}/policy`, { body: { mode } }),
|
|
116
122
|
setToolPolicy: (uid, toolUid, body) =>
|
|
117
123
|
this.request('PATCH', `/clients/${uid}/tools/${toolUid}/policy`, { body }),
|
|
118
124
|
};
|
|
125
|
+
const archiveAccessProfile = (uid, expectedVersion) =>
|
|
126
|
+
this.request('DELETE', `/access-profiles/${uid}`, { query: { expectedVersion } });
|
|
127
|
+
this.accessProfiles = {
|
|
128
|
+
archive: archiveAccessProfile,
|
|
129
|
+
create: (body) => this.request('POST', '/access-profiles', { body }),
|
|
130
|
+
delete: archiveAccessProfile,
|
|
131
|
+
list: (query) => this.request('GET', '/access-profiles', { query }),
|
|
132
|
+
listTools: (uid, query) => this.request('GET', `/access-profiles/${uid}/tools`, { query }),
|
|
133
|
+
setPolicy: (uid, mode, expectedVersion) =>
|
|
134
|
+
this.request('PATCH', `/access-profiles/${uid}/policy`, {
|
|
135
|
+
body: { expectedVersion, mode },
|
|
136
|
+
}),
|
|
137
|
+
setToolPolicy: (uid, toolUid, body) =>
|
|
138
|
+
this.request('PATCH', `/access-profiles/${uid}/tools/${toolUid}/policy`, { body }),
|
|
139
|
+
update: (uid, body) => this.request('PATCH', `/access-profiles/${uid}`, { body }),
|
|
140
|
+
};
|
|
119
141
|
this.activity = { list: (query) => this.request('GET', '/activity', { query }) };
|
|
120
142
|
this.reviews = { list: (query) => this.request('GET', '/reviews', { query }) };
|
|
121
143
|
this.webhooks = {
|
|
@@ -140,7 +162,7 @@ export class Rayrun {
|
|
|
140
162
|
response = await this.fetch(url, {
|
|
141
163
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
142
164
|
headers: withoutUndefined({
|
|
143
|
-
authorization: `Bearer ${this
|
|
165
|
+
authorization: `Bearer ${this.#apiKey}`,
|
|
144
166
|
'content-type': body === undefined ? undefined : 'application/json',
|
|
145
167
|
'user-agent': '@rayrun/sdk',
|
|
146
168
|
}),
|
|
@@ -266,6 +288,8 @@ export class RayrunCodeRunAheadSession {
|
|
|
266
288
|
}
|
|
267
289
|
|
|
268
290
|
export class RayrunGateway {
|
|
291
|
+
#accessToken;
|
|
292
|
+
|
|
269
293
|
constructor({
|
|
270
294
|
accessToken,
|
|
271
295
|
baseUrl = 'https://ray.run',
|
|
@@ -274,7 +298,7 @@ export class RayrunGateway {
|
|
|
274
298
|
if (!accessToken) throw new TypeError('RayrunGateway requires an accessToken.');
|
|
275
299
|
if (!fetchImplementation) throw new TypeError('RayrunGateway requires a fetch implementation.');
|
|
276
300
|
|
|
277
|
-
this
|
|
301
|
+
this.#accessToken = accessToken;
|
|
278
302
|
this.baseUrl = baseUrl.replace(/\/$/u, '');
|
|
279
303
|
this.fetch = fetchImplementation;
|
|
280
304
|
this.codeRunAhead = {
|
|
@@ -298,7 +322,7 @@ export class RayrunGateway {
|
|
|
298
322
|
const response = await this.fetch(`${this.baseUrl}/mcp/run-ahead`, {
|
|
299
323
|
body: JSON.stringify(body),
|
|
300
324
|
headers: {
|
|
301
|
-
authorization: `Bearer ${this
|
|
325
|
+
authorization: `Bearer ${this.#accessToken}`,
|
|
302
326
|
'content-type': 'application/json',
|
|
303
327
|
'user-agent': '@rayrun/sdk',
|
|
304
328
|
},
|