@rustrak/client 0.1.2 → 0.2.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 +119 -192
- package/dist/index.cjs +81 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -1
- package/dist/index.d.ts +53 -1
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -1
- package/package.json +23 -5
package/README.md
CHANGED
|
@@ -1,200 +1,180 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://abians.github.io/rustrak">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/AbianS/rustrak/main/apps/docs/public/logo.svg" alt="Rustrak" width="64" height="64" />
|
|
4
|
+
</a>
|
|
5
|
+
<h1>@rustrak/client</h1>
|
|
6
|
+
<p>Official TypeScript client for the <a href="https://abians.github.io/rustrak">Rustrak</a> self-hosted error tracking API</p>
|
|
7
|
+
|
|
8
|
+
<p>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@rustrak/client">
|
|
10
|
+
<img src="https://img.shields.io/npm/v/@rustrak/client?style=flat-square&color=cb3837" alt="npm version" />
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/@rustrak/client">
|
|
13
|
+
<img src="https://img.shields.io/npm/dw/@rustrak/client?style=flat-square" alt="weekly downloads" />
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://bundlephobia.com/package/@rustrak/client">
|
|
16
|
+
<img src="https://img.shields.io/bundlephobia/minzip/@rustrak/client?style=flat-square&label=bundle" alt="bundle size" />
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://github.com/AbianS/rustrak/blob/main/LICENSE">
|
|
19
|
+
<img src="https://img.shields.io/npm/l/@rustrak/client?style=flat-square" alt="license" />
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://github.com/AbianS/rustrak/actions/workflows/ci.yml">
|
|
22
|
+
<img src="https://img.shields.io/github/actions/workflow/status/AbianS/rustrak/ci.yml?style=flat-square&label=CI" alt="CI" />
|
|
23
|
+
</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<p>
|
|
27
|
+
<a href="https://abians.github.io/rustrak/sdks/client">Documentation</a>
|
|
28
|
+
·
|
|
29
|
+
<a href="https://github.com/AbianS/rustrak">GitHub</a>
|
|
30
|
+
·
|
|
31
|
+
<a href="https://github.com/AbianS/rustrak/issues">Report a Bug</a>
|
|
32
|
+
</p>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
`@rustrak/client` is the official TypeScript client for [Rustrak](https://abians.github.io/rustrak) — an ultra-lightweight, self-hosted error tracking system compatible with any Sentry SDK. This package wraps the Rustrak REST API with full type safety, runtime validation via Zod, built-in retry logic, and structured error handling. Total bundle size: ~28 KB.
|
|
12
38
|
|
|
13
39
|
## Installation
|
|
14
40
|
|
|
15
41
|
```bash
|
|
42
|
+
npm install @rustrak/client
|
|
43
|
+
# or
|
|
16
44
|
pnpm add @rustrak/client
|
|
45
|
+
# or
|
|
46
|
+
yarn add @rustrak/client
|
|
17
47
|
```
|
|
18
48
|
|
|
49
|
+
**Requirements**: Node.js ≥ 18, TypeScript ≥ 5
|
|
50
|
+
|
|
19
51
|
## Quick Start
|
|
20
52
|
|
|
21
53
|
```typescript
|
|
22
54
|
import { RustrakClient } from '@rustrak/client';
|
|
23
55
|
|
|
24
56
|
const client = new RustrakClient({
|
|
25
|
-
baseUrl: '
|
|
26
|
-
token:
|
|
57
|
+
baseUrl: 'https://your-rustrak-instance.example.com',
|
|
58
|
+
token: process.env.RUSTRAK_API_TOKEN!,
|
|
27
59
|
});
|
|
28
60
|
|
|
29
61
|
// List all projects
|
|
30
62
|
const projects = await client.projects.list();
|
|
31
63
|
|
|
32
|
-
//
|
|
33
|
-
const { items, next_cursor, has_more } = await client.issues.list(1
|
|
64
|
+
// Paginate through open issues
|
|
65
|
+
const { items, next_cursor, has_more } = await client.issues.list(1, {
|
|
66
|
+
sort: 'last_seen',
|
|
67
|
+
order: 'desc',
|
|
68
|
+
});
|
|
34
69
|
|
|
35
|
-
//
|
|
36
|
-
|
|
70
|
+
// Resolve an issue
|
|
71
|
+
await client.issues.updateState(1, 'issue-id', { is_resolved: true });
|
|
37
72
|
```
|
|
38
73
|
|
|
39
|
-
|
|
74
|
+
**[Full documentation →](https://abians.github.io/rustrak/sdks/client)**
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- **Type-safe** — All API responses validated at runtime with Zod; types are inferred from schemas
|
|
79
|
+
- **Lightweight** — ~28 KB total (ky 3 KB + zod 10 KB + client 15 KB)
|
|
80
|
+
- **Automatic retry** — Exponential backoff on transient failures (408, 429, 5xx)
|
|
81
|
+
- **Structured errors** — Typed error classes for every HTTP status and failure mode
|
|
82
|
+
- **Cursor pagination** — First-class support for paginated responses across all list endpoints
|
|
83
|
+
- **97% test coverage** — 133 tests (unit + integration with MSW)
|
|
84
|
+
|
|
85
|
+
## API Reference
|
|
40
86
|
|
|
41
87
|
### Configuration
|
|
42
88
|
|
|
43
89
|
```typescript
|
|
44
|
-
import { RustrakClient } from '@rustrak/client';
|
|
45
|
-
|
|
46
90
|
const client = new RustrakClient({
|
|
47
|
-
baseUrl: 'https://rustrak.example.com',
|
|
48
|
-
token: 'your-bearer-token',
|
|
49
|
-
timeout: 30000,
|
|
50
|
-
maxRetries: 2,
|
|
51
|
-
headers: {
|
|
52
|
-
// Optional: custom headers
|
|
53
|
-
'X-Custom-Header': 'value',
|
|
54
|
-
},
|
|
91
|
+
baseUrl: 'https://rustrak.example.com', // required
|
|
92
|
+
token: 'your-bearer-token', // required
|
|
93
|
+
timeout: 30000, // optional, ms (default: 30000)
|
|
94
|
+
maxRetries: 2, // optional (default: 2)
|
|
95
|
+
headers: {}, // optional custom headers
|
|
55
96
|
});
|
|
56
97
|
```
|
|
57
98
|
|
|
58
99
|
### Projects
|
|
59
100
|
|
|
60
101
|
```typescript
|
|
61
|
-
// List all projects
|
|
62
102
|
const projects = await client.projects.list();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
// Create a project
|
|
68
|
-
const newProject = await client.projects.create({
|
|
69
|
-
name: 'My App',
|
|
70
|
-
slug: 'my-app', // Optional
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Update a project
|
|
74
|
-
const updated = await client.projects.update(1, {
|
|
75
|
-
name: 'Updated Name',
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Delete a project
|
|
103
|
+
const project = await client.projects.get(1);
|
|
104
|
+
const created = await client.projects.create({ name: 'My App', slug: 'my-app' });
|
|
105
|
+
const updated = await client.projects.update(1, { name: 'New Name' });
|
|
79
106
|
await client.projects.delete(1);
|
|
80
107
|
```
|
|
81
108
|
|
|
82
109
|
### Issues
|
|
83
110
|
|
|
84
111
|
```typescript
|
|
85
|
-
// List
|
|
86
|
-
const
|
|
87
|
-
sort: 'last_seen',
|
|
88
|
-
order: 'desc',
|
|
112
|
+
// List with filters and cursor pagination
|
|
113
|
+
const { items, next_cursor, has_more } = await client.issues.list(projectId, {
|
|
114
|
+
sort: 'last_seen', // 'digest_order' | 'last_seen'
|
|
115
|
+
order: 'desc', // 'asc' | 'desc'
|
|
89
116
|
include_resolved: false,
|
|
90
|
-
cursor: 'eyJzb3J0...',
|
|
117
|
+
cursor: 'eyJzb3J0...', // from previous response
|
|
91
118
|
});
|
|
92
119
|
|
|
93
|
-
// Paginate through all issues
|
|
94
|
-
let cursor: string | undefined;
|
|
95
|
-
do {
|
|
96
|
-
const { items, next_cursor, has_more } = await client.issues.list(projectId, {
|
|
97
|
-
cursor,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Process items...
|
|
101
|
-
cursor = next_cursor;
|
|
102
|
-
} while (cursor);
|
|
103
|
-
|
|
104
|
-
// Get a single issue
|
|
105
120
|
const issue = await client.issues.get(projectId, issueId);
|
|
106
|
-
|
|
107
|
-
// Update issue state
|
|
108
|
-
const resolved = await client.issues.updateState(projectId, issueId, {
|
|
109
|
-
is_resolved: true,
|
|
110
|
-
is_muted: false,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Delete an issue
|
|
121
|
+
await client.issues.updateState(projectId, issueId, { is_resolved: true });
|
|
114
122
|
await client.issues.delete(projectId, issueId);
|
|
115
123
|
```
|
|
116
124
|
|
|
117
125
|
### Events
|
|
118
126
|
|
|
119
127
|
```typescript
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
cursor: 'optional-cursor',
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// Get event details
|
|
127
|
-
const event = await client.events.get(projectId, issueId, eventId);
|
|
128
|
-
|
|
129
|
-
// Access full Sentry event data
|
|
130
|
-
console.log(event.data); // Full JSON payload
|
|
128
|
+
const { items } = await client.events.list(projectId, issueId, { order: 'desc' });
|
|
129
|
+
const event = await client.events.get(projectId, issueId, eventId);
|
|
130
|
+
console.log(event.data); // Full Sentry event payload
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
### Auth Tokens
|
|
134
134
|
|
|
135
135
|
```typescript
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
// Get a single token (masked)
|
|
140
|
-
const token = await client.tokens.get(1);
|
|
141
|
-
|
|
142
|
-
// Create a token (full token only shown once!)
|
|
143
|
-
const created = await client.tokens.create({
|
|
144
|
-
description: 'CI/CD token',
|
|
145
|
-
});
|
|
146
|
-
console.log(created.token); // Save this! Won't be shown again
|
|
147
|
-
|
|
148
|
-
// Delete a token
|
|
136
|
+
const tokens = await client.tokens.list();
|
|
137
|
+
const created = await client.tokens.create({ description: 'CI token' });
|
|
138
|
+
console.log(created.token); // Save this — shown only once
|
|
149
139
|
await client.tokens.delete(1);
|
|
150
140
|
```
|
|
151
141
|
|
|
152
142
|
## Error Handling
|
|
153
143
|
|
|
154
|
-
The client throws structured error classes for different scenarios:
|
|
155
|
-
|
|
156
144
|
```typescript
|
|
157
145
|
import {
|
|
158
|
-
RustrakError,
|
|
159
|
-
NetworkError,
|
|
160
146
|
AuthenticationError,
|
|
161
|
-
|
|
147
|
+
AuthorizationError,
|
|
162
148
|
NotFoundError,
|
|
149
|
+
RateLimitError,
|
|
150
|
+
NetworkError,
|
|
151
|
+
ServerError,
|
|
163
152
|
ValidationError,
|
|
164
153
|
} from '@rustrak/client';
|
|
165
154
|
|
|
166
155
|
try {
|
|
167
156
|
await client.projects.list();
|
|
168
157
|
} catch (error) {
|
|
169
|
-
if (error instanceof RateLimitError) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
console.log('
|
|
173
|
-
|
|
174
|
-
console.log('Resource not found');
|
|
175
|
-
} else if (error instanceof NetworkError) {
|
|
176
|
-
console.log('Network error - will retry automatically');
|
|
177
|
-
} else if (error instanceof ValidationError) {
|
|
178
|
-
console.log('API response validation failed');
|
|
179
|
-
console.log(error.getValidationDetails());
|
|
180
|
-
}
|
|
158
|
+
if (error instanceof RateLimitError) console.log(`Retry after ${error.retryAfter}s`);
|
|
159
|
+
else if (error instanceof AuthenticationError) redirect('/login');
|
|
160
|
+
else if (error instanceof NotFoundError) console.log('Not found');
|
|
161
|
+
else if (error instanceof NetworkError) console.log('Will retry automatically');
|
|
162
|
+
else if (error instanceof ValidationError) console.log(error.getValidationDetails());
|
|
181
163
|
}
|
|
182
164
|
```
|
|
183
165
|
|
|
184
|
-
|
|
166
|
+
| Error Class | HTTP | Retryable |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `NetworkError` | — | ✅ |
|
|
169
|
+
| `AuthenticationError` | 401 | ❌ |
|
|
170
|
+
| `AuthorizationError` | 403 | ❌ |
|
|
171
|
+
| `NotFoundError` | 404 | ❌ |
|
|
172
|
+
| `BadRequestError` | 400 | ❌ |
|
|
173
|
+
| `RateLimitError` | 429 | ✅ |
|
|
174
|
+
| `ServerError` | 500+ | ✅ |
|
|
175
|
+
| `ValidationError` | — | ❌ |
|
|
185
176
|
|
|
186
|
-
|
|
187
|
-
|-------------|-------------|-----------|----------|
|
|
188
|
-
| `NetworkError` | - | ✅ | Connection issues, timeouts |
|
|
189
|
-
| `AuthenticationError` | 401 | ❌ | Invalid credentials |
|
|
190
|
-
| `AuthorizationError` | 403 | ❌ | Insufficient permissions |
|
|
191
|
-
| `NotFoundError` | 404 | ❌ | Resource doesn't exist |
|
|
192
|
-
| `BadRequestError` | 400 | ❌ | Invalid request payload |
|
|
193
|
-
| `RateLimitError` | 429 | ✅ | Rate limit exceeded |
|
|
194
|
-
| `ServerError` | 500+ | ✅ | Server-side errors |
|
|
195
|
-
| `ValidationError` | - | ❌ | Response schema mismatch |
|
|
196
|
-
|
|
197
|
-
## Usage with Next.js
|
|
177
|
+
## Next.js Integration
|
|
198
178
|
|
|
199
179
|
### Server Component
|
|
200
180
|
|
|
@@ -206,48 +186,8 @@ export default async function ProjectsPage() {
|
|
|
206
186
|
baseUrl: process.env.RUSTRAK_API_URL!,
|
|
207
187
|
token: process.env.RUSTRAK_API_TOKEN!,
|
|
208
188
|
});
|
|
209
|
-
|
|
210
189
|
const projects = await client.projects.list();
|
|
211
|
-
|
|
212
|
-
return (
|
|
213
|
-
<div>
|
|
214
|
-
{projects.map((project) => (
|
|
215
|
-
<div key={project.id}>{project.name}</div>
|
|
216
|
-
))}
|
|
217
|
-
</div>
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Client Component with SWR
|
|
223
|
-
|
|
224
|
-
```typescript
|
|
225
|
-
'use client';
|
|
226
|
-
|
|
227
|
-
import useSWR from 'swr';
|
|
228
|
-
import { RustrakClient } from '@rustrak/client';
|
|
229
|
-
|
|
230
|
-
const client = new RustrakClient({
|
|
231
|
-
baseUrl: process.env.NEXT_PUBLIC_RUSTRAK_API_URL!,
|
|
232
|
-
token: process.env.NEXT_PUBLIC_RUSTRAK_API_TOKEN!,
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
export function IssuesList({ projectId }: { projectId: number }) {
|
|
236
|
-
const { data, error, isLoading } = useSWR(
|
|
237
|
-
['issues', projectId],
|
|
238
|
-
() => client.issues.list(projectId)
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
if (error) return <div>Error: {error.message}</div>;
|
|
242
|
-
if (isLoading) return <div>Loading...</div>;
|
|
243
|
-
|
|
244
|
-
return (
|
|
245
|
-
<div>
|
|
246
|
-
{data?.items.map((issue) => (
|
|
247
|
-
<div key={issue.id}>{issue.title}</div>
|
|
248
|
-
))}
|
|
249
|
-
</div>
|
|
250
|
-
);
|
|
190
|
+
return <ProjectsList projects={projects} />;
|
|
251
191
|
}
|
|
252
192
|
```
|
|
253
193
|
|
|
@@ -255,7 +195,6 @@ export function IssuesList({ projectId }: { projectId: number }) {
|
|
|
255
195
|
|
|
256
196
|
```typescript
|
|
257
197
|
'use server';
|
|
258
|
-
|
|
259
198
|
import { RustrakClient } from '@rustrak/client';
|
|
260
199
|
|
|
261
200
|
export async function resolveIssue(projectId: number, issueId: string) {
|
|
@@ -263,16 +202,13 @@ export async function resolveIssue(projectId: number, issueId: string) {
|
|
|
263
202
|
baseUrl: process.env.RUSTRAK_API_URL!,
|
|
264
203
|
token: process.env.RUSTRAK_API_TOKEN!,
|
|
265
204
|
});
|
|
266
|
-
|
|
267
|
-
return await client.issues.updateState(projectId, issueId, {
|
|
268
|
-
is_resolved: true,
|
|
269
|
-
});
|
|
205
|
+
return client.issues.updateState(projectId, issueId, { is_resolved: true });
|
|
270
206
|
}
|
|
271
207
|
```
|
|
272
208
|
|
|
273
209
|
## TypeScript
|
|
274
210
|
|
|
275
|
-
|
|
211
|
+
All types are exported and inferred from Zod schemas — single source of truth:
|
|
276
212
|
|
|
277
213
|
```typescript
|
|
278
214
|
import type {
|
|
@@ -280,37 +216,28 @@ import type {
|
|
|
280
216
|
Issue,
|
|
281
217
|
Event,
|
|
282
218
|
EventDetail,
|
|
219
|
+
AuthToken,
|
|
283
220
|
PaginatedResponse,
|
|
284
221
|
CreateProject,
|
|
285
222
|
UpdateIssueState,
|
|
286
223
|
} from '@rustrak/client';
|
|
287
|
-
|
|
288
|
-
const project: Project = await client.projects.get(1);
|
|
289
|
-
const issues: PaginatedResponse<Issue> = await client.issues.list(1);
|
|
290
224
|
```
|
|
291
225
|
|
|
292
|
-
##
|
|
226
|
+
## Related Packages
|
|
293
227
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
228
|
+
| Package | Description |
|
|
229
|
+
|---|---|
|
|
230
|
+
| [`@rustrak/mcp`](https://www.npmjs.com/package/@rustrak/mcp) | MCP server — gives Claude Desktop, Cursor, and Continue direct access to your Rustrak instance via 18 tools |
|
|
297
231
|
|
|
298
|
-
|
|
299
|
-
pnpm build
|
|
232
|
+
## What is Rustrak?
|
|
300
233
|
|
|
301
|
-
|
|
302
|
-
pnpm check-types
|
|
234
|
+
[Rustrak](https://abians.github.io/rustrak) is a self-hosted error tracking server written in Rust that is fully compatible with any Sentry SDK. Drop-in replacement for Sentry — no code changes needed. Runs on ~50 MB of memory as a single binary or Docker image.
|
|
303
235
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
pnpm test:watch
|
|
309
|
-
|
|
310
|
-
# Generate coverage
|
|
311
|
-
pnpm test:coverage
|
|
312
|
-
```
|
|
236
|
+
- [Getting Started](https://abians.github.io/rustrak/getting-started/overview)
|
|
237
|
+
- [Self-Hosting Guide](https://abians.github.io/rustrak/configuration/production)
|
|
238
|
+
- [API Reference](https://abians.github.io/rustrak/api-reference)
|
|
239
|
+
- [GitHub](https://github.com/AbianS/rustrak)
|
|
313
240
|
|
|
314
241
|
## License
|
|
315
242
|
|
|
316
|
-
GPL-3.0
|
|
243
|
+
[GPL-3.0](https://github.com/AbianS/rustrak/blob/main/LICENSE)
|
package/dist/index.cjs
CHANGED
|
@@ -477,6 +477,30 @@ var createProjectSchema = zod.z.object({
|
|
|
477
477
|
var updateProjectSchema = zod.z.object({
|
|
478
478
|
name: zod.z.string().min(1).optional()
|
|
479
479
|
});
|
|
480
|
+
var chunkUploadCapabilitySchema = zod.z.object({
|
|
481
|
+
url: zod.z.string(),
|
|
482
|
+
chunkSize: zod.z.number().int(),
|
|
483
|
+
chunksPerRequest: zod.z.number().int(),
|
|
484
|
+
maxRequestSize: zod.z.number().int(),
|
|
485
|
+
hashAlgorithm: zod.z.string(),
|
|
486
|
+
accept: zod.z.array(zod.z.string()),
|
|
487
|
+
concurrency: zod.z.number().int().optional()
|
|
488
|
+
});
|
|
489
|
+
var assembleResponseSchema = zod.z.object({
|
|
490
|
+
state: zod.z.string(),
|
|
491
|
+
missingChunks: zod.z.array(zod.z.string()),
|
|
492
|
+
detail: zod.z.string().optional()
|
|
493
|
+
});
|
|
494
|
+
var sourceMapFileSchema = zod.z.object({
|
|
495
|
+
debugId: zod.z.string(),
|
|
496
|
+
fileType: zod.z.string(),
|
|
497
|
+
size: zod.z.number().int(),
|
|
498
|
+
timesUsed: zod.z.number().int(),
|
|
499
|
+
dateUploaded: zod.z.string()
|
|
500
|
+
});
|
|
501
|
+
var listSourceMapsResponseSchema = zod.z.object({
|
|
502
|
+
data: zod.z.array(sourceMapFileSchema)
|
|
503
|
+
});
|
|
480
504
|
var authTokenSchema = zod.z.object({
|
|
481
505
|
id: zod.z.number().int(),
|
|
482
506
|
token_prefix: zod.z.string(),
|
|
@@ -623,6 +647,58 @@ var ProjectsResource = class extends BaseResource {
|
|
|
623
647
|
}
|
|
624
648
|
};
|
|
625
649
|
|
|
650
|
+
// src/resources/sourcemaps.ts
|
|
651
|
+
var SourceMapsResource = class extends BaseResource {
|
|
652
|
+
/**
|
|
653
|
+
* Get chunk upload capabilities for an organization.
|
|
654
|
+
* Returns the upload URL, chunk size limits, and accepted artifact types.
|
|
655
|
+
*/
|
|
656
|
+
async getChunkUploadCapability(orgSlug) {
|
|
657
|
+
const data = await this.http.get(`api/0/organizations/${orgSlug}/chunk-upload/`).json();
|
|
658
|
+
return this.validate(data, chunkUploadCapabilitySchema);
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Upload chunks as multipart/form-data, batching by `chunksPerRequest` (default 64).
|
|
662
|
+
* Each part's field name must be the pre-computed SHA-1 hash of its content — the server
|
|
663
|
+
* rejects mismatches with 400. Callers must supply the hash (also needed for assembleBundle).
|
|
664
|
+
*/
|
|
665
|
+
async uploadChunks(orgSlug, chunks, chunksPerRequest = 64) {
|
|
666
|
+
if (!Number.isInteger(chunksPerRequest) || chunksPerRequest <= 0) {
|
|
667
|
+
throw new Error("chunksPerRequest must be a positive integer");
|
|
668
|
+
}
|
|
669
|
+
for (let i = 0; i < chunks.length; i += chunksPerRequest) {
|
|
670
|
+
const batch = chunks.slice(i, i + chunksPerRequest);
|
|
671
|
+
const form = new FormData();
|
|
672
|
+
for (const chunk of batch) {
|
|
673
|
+
form.append(chunk.hash, chunk.data);
|
|
674
|
+
}
|
|
675
|
+
await this.http.post(`api/0/organizations/${orgSlug}/chunk-upload/`, {
|
|
676
|
+
body: form
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Trigger assembly of a previously uploaded artifact bundle.
|
|
682
|
+
*
|
|
683
|
+
* @returns The assembly state. Poll until `state === "ok"` or `state === "error"`.
|
|
684
|
+
* When `state === "not_found"` the `missingChunks` array lists what
|
|
685
|
+
* still needs uploading via `uploadChunks`.
|
|
686
|
+
*/
|
|
687
|
+
async assembleBundle(orgSlug, input) {
|
|
688
|
+
const data = await this.http.post(`api/0/organizations/${orgSlug}/artifactbundle/assemble/`, {
|
|
689
|
+
json: input
|
|
690
|
+
}).json();
|
|
691
|
+
return this.validate(data, assembleResponseSchema);
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* List all source map files uploaded for a project.
|
|
695
|
+
*/
|
|
696
|
+
async list(orgSlug, projectSlug) {
|
|
697
|
+
const data = await this.http.get(`api/0/projects/${orgSlug}/${projectSlug}/files/source-maps/`).json();
|
|
698
|
+
return this.validate(data, listSourceMapsResponseSchema);
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
|
|
626
702
|
// src/resources/tokens.ts
|
|
627
703
|
var TokensResource = class extends BaseResource {
|
|
628
704
|
/**
|
|
@@ -750,6 +826,10 @@ var RustrakClient = class {
|
|
|
750
826
|
* Alert Rules API resource (per-project alert configuration)
|
|
751
827
|
*/
|
|
752
828
|
alertRules;
|
|
829
|
+
/**
|
|
830
|
+
* Source Maps API resource (sentry-cli artifact bundle upload protocol)
|
|
831
|
+
*/
|
|
832
|
+
sourceMaps;
|
|
753
833
|
/**
|
|
754
834
|
* Create a new Rustrak API client
|
|
755
835
|
*
|
|
@@ -764,6 +844,7 @@ var RustrakClient = class {
|
|
|
764
844
|
this.tokens = new TokensResource(this.http);
|
|
765
845
|
this.alertChannels = new AlertChannelsResource(this.http);
|
|
766
846
|
this.alertRules = new AlertRulesResource(this.http);
|
|
847
|
+
this.sourceMaps = new SourceMapsResource(this.http);
|
|
767
848
|
}
|
|
768
849
|
};
|
|
769
850
|
|