@rustrak/client 0.1.2
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/LICENSE +22 -0
- package/README.md +316 -0
- package/dist/index.cjs +781 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +433 -0
- package/dist/index.d.ts +433 -0
- package/dist/index.js +766 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
var ky = require('ky');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var ky__default = /*#__PURE__*/_interopDefault(ky);
|
|
9
|
+
|
|
10
|
+
// src/resources/alert-channels.ts
|
|
11
|
+
var paginatedResponseSchema = (itemSchema) => zod.z.object({
|
|
12
|
+
items: zod.z.array(itemSchema),
|
|
13
|
+
next_cursor: zod.z.string().optional(),
|
|
14
|
+
has_more: zod.z.boolean()
|
|
15
|
+
});
|
|
16
|
+
var offsetPaginatedResponseSchema = (itemSchema) => zod.z.object({
|
|
17
|
+
items: zod.z.array(itemSchema),
|
|
18
|
+
total_count: zod.z.number().int(),
|
|
19
|
+
page: zod.z.number().int(),
|
|
20
|
+
per_page: zod.z.number().int(),
|
|
21
|
+
total_pages: zod.z.number().int()
|
|
22
|
+
});
|
|
23
|
+
zod.z.enum(["asc", "desc"]);
|
|
24
|
+
zod.z.enum(["digest_order", "last_seen"]);
|
|
25
|
+
zod.z.enum(["open", "resolved", "muted", "all"]);
|
|
26
|
+
var dateTimeSchema = zod.z.string().datetime();
|
|
27
|
+
var uuidSchema = zod.z.string().uuid();
|
|
28
|
+
zod.z.object({
|
|
29
|
+
error: zod.z.string(),
|
|
30
|
+
message: zod.z.string().optional()
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// src/schemas/alert.ts
|
|
34
|
+
var channelTypeSchema = zod.z.enum(["webhook", "email", "slack"]);
|
|
35
|
+
var alertTypeSchema = zod.z.enum(["new_issue", "regression", "unmute"]);
|
|
36
|
+
var alertStatusSchema = zod.z.enum([
|
|
37
|
+
"pending",
|
|
38
|
+
"sent",
|
|
39
|
+
"failed",
|
|
40
|
+
"skipped"
|
|
41
|
+
]);
|
|
42
|
+
var notificationChannelSchema = zod.z.object({
|
|
43
|
+
id: zod.z.number().int(),
|
|
44
|
+
name: zod.z.string(),
|
|
45
|
+
channel_type: channelTypeSchema,
|
|
46
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
47
|
+
is_enabled: zod.z.boolean(),
|
|
48
|
+
failure_count: zod.z.number().int(),
|
|
49
|
+
last_failure_at: dateTimeSchema.nullable(),
|
|
50
|
+
last_failure_message: zod.z.string().nullable(),
|
|
51
|
+
last_success_at: dateTimeSchema.nullable(),
|
|
52
|
+
created_at: dateTimeSchema,
|
|
53
|
+
updated_at: dateTimeSchema
|
|
54
|
+
});
|
|
55
|
+
var createNotificationChannelSchema = zod.z.object({
|
|
56
|
+
name: zod.z.string().min(1),
|
|
57
|
+
channel_type: channelTypeSchema,
|
|
58
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
59
|
+
is_enabled: zod.z.boolean().optional()
|
|
60
|
+
});
|
|
61
|
+
var updateNotificationChannelSchema = zod.z.object({
|
|
62
|
+
name: zod.z.string().min(1).optional(),
|
|
63
|
+
config: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
64
|
+
is_enabled: zod.z.boolean().optional()
|
|
65
|
+
});
|
|
66
|
+
var alertRuleSchema = zod.z.object({
|
|
67
|
+
id: zod.z.number().int(),
|
|
68
|
+
project_id: zod.z.number().int(),
|
|
69
|
+
name: zod.z.string(),
|
|
70
|
+
alert_type: alertTypeSchema,
|
|
71
|
+
is_enabled: zod.z.boolean(),
|
|
72
|
+
conditions: zod.z.record(zod.z.string(), zod.z.unknown()),
|
|
73
|
+
cooldown_minutes: zod.z.number().int(),
|
|
74
|
+
last_triggered_at: dateTimeSchema.nullable(),
|
|
75
|
+
created_at: dateTimeSchema,
|
|
76
|
+
updated_at: dateTimeSchema,
|
|
77
|
+
channel_ids: zod.z.array(zod.z.number().int())
|
|
78
|
+
});
|
|
79
|
+
var createAlertRuleSchema = zod.z.object({
|
|
80
|
+
name: zod.z.string().min(1),
|
|
81
|
+
alert_type: alertTypeSchema,
|
|
82
|
+
channel_ids: zod.z.array(zod.z.number().int()).min(1),
|
|
83
|
+
is_enabled: zod.z.boolean().optional(),
|
|
84
|
+
conditions: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
85
|
+
cooldown_minutes: zod.z.number().int().min(0).optional()
|
|
86
|
+
});
|
|
87
|
+
var updateAlertRuleSchema = zod.z.object({
|
|
88
|
+
name: zod.z.string().min(1).optional(),
|
|
89
|
+
is_enabled: zod.z.boolean().optional(),
|
|
90
|
+
conditions: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
|
|
91
|
+
cooldown_minutes: zod.z.number().int().min(0).optional(),
|
|
92
|
+
channel_ids: zod.z.array(zod.z.number().int()).optional()
|
|
93
|
+
});
|
|
94
|
+
var alertHistorySchema = zod.z.object({
|
|
95
|
+
id: zod.z.number().int(),
|
|
96
|
+
alert_rule_id: zod.z.number().int().nullable(),
|
|
97
|
+
channel_id: zod.z.number().int().nullable(),
|
|
98
|
+
issue_id: zod.z.string().uuid().nullable(),
|
|
99
|
+
project_id: zod.z.number().int().nullable(),
|
|
100
|
+
alert_type: zod.z.string(),
|
|
101
|
+
channel_type: zod.z.string(),
|
|
102
|
+
channel_name: zod.z.string(),
|
|
103
|
+
status: alertStatusSchema,
|
|
104
|
+
attempt_count: zod.z.number().int(),
|
|
105
|
+
next_retry_at: dateTimeSchema.nullable(),
|
|
106
|
+
error_message: zod.z.string().nullable(),
|
|
107
|
+
http_status_code: zod.z.number().int().nullable(),
|
|
108
|
+
idempotency_key: zod.z.string(),
|
|
109
|
+
created_at: dateTimeSchema,
|
|
110
|
+
sent_at: dateTimeSchema.nullable()
|
|
111
|
+
});
|
|
112
|
+
var testChannelResponseSchema = zod.z.object({
|
|
113
|
+
success: zod.z.boolean(),
|
|
114
|
+
message: zod.z.string()
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// src/errors/base.ts
|
|
118
|
+
var RustrakError = class extends Error {
|
|
119
|
+
/**
|
|
120
|
+
* Whether this error is safe to retry
|
|
121
|
+
*/
|
|
122
|
+
retryable;
|
|
123
|
+
/**
|
|
124
|
+
* HTTP status code if applicable
|
|
125
|
+
*/
|
|
126
|
+
statusCode;
|
|
127
|
+
/**
|
|
128
|
+
* Original error cause
|
|
129
|
+
*/
|
|
130
|
+
cause;
|
|
131
|
+
constructor(message, options) {
|
|
132
|
+
super(message);
|
|
133
|
+
this.name = this.constructor.name;
|
|
134
|
+
this.retryable = options?.retryable ?? false;
|
|
135
|
+
this.statusCode = options?.statusCode;
|
|
136
|
+
this.cause = options?.cause;
|
|
137
|
+
if (Error.captureStackTrace) {
|
|
138
|
+
Error.captureStackTrace(this, this.constructor);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// src/errors/http.ts
|
|
144
|
+
var NetworkError = class extends RustrakError {
|
|
145
|
+
constructor(message, cause) {
|
|
146
|
+
super(message, { retryable: true, cause });
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
var AuthenticationError = class extends RustrakError {
|
|
150
|
+
constructor(message = "Authentication failed") {
|
|
151
|
+
super(message, { retryable: false, statusCode: 401 });
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
var AuthorizationError = class extends RustrakError {
|
|
155
|
+
constructor(message = "Insufficient permissions") {
|
|
156
|
+
super(message, { retryable: false, statusCode: 403 });
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
var NotFoundError = class extends RustrakError {
|
|
160
|
+
constructor(resource) {
|
|
161
|
+
super(`Resource not found: ${resource}`, {
|
|
162
|
+
retryable: false,
|
|
163
|
+
statusCode: 404
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var RateLimitError = class extends RustrakError {
|
|
168
|
+
/**
|
|
169
|
+
* Number of seconds to wait before retrying (from Retry-After header)
|
|
170
|
+
*/
|
|
171
|
+
retryAfter;
|
|
172
|
+
constructor(message = "Rate limit exceeded", retryAfter) {
|
|
173
|
+
super(message, { retryable: true, statusCode: 429 });
|
|
174
|
+
if (retryAfter !== void 0) {
|
|
175
|
+
this.retryAfter = typeof retryAfter === "string" ? parseInt(retryAfter, 10) : retryAfter;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
var ServerError = class extends RustrakError {
|
|
180
|
+
constructor(message, statusCode = 500) {
|
|
181
|
+
super(message, { retryable: true, statusCode });
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
var BadRequestError = class extends RustrakError {
|
|
185
|
+
constructor(message) {
|
|
186
|
+
super(message, { retryable: false, statusCode: 400 });
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// src/errors/validation.ts
|
|
191
|
+
var ValidationError = class extends RustrakError {
|
|
192
|
+
/**
|
|
193
|
+
* Zod validation errors
|
|
194
|
+
*/
|
|
195
|
+
validationErrors;
|
|
196
|
+
constructor(message, validationErrors) {
|
|
197
|
+
super(message, { retryable: false });
|
|
198
|
+
this.validationErrors = validationErrors;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get a formatted string of validation errors
|
|
202
|
+
*/
|
|
203
|
+
getValidationDetails() {
|
|
204
|
+
if (!this.validationErrors) {
|
|
205
|
+
return this.message;
|
|
206
|
+
}
|
|
207
|
+
const errors = this.validationErrors.issues.map((err) => `${err.path.map(String).join(".")}: ${err.message}`).join(", ");
|
|
208
|
+
return `${this.message} - ${errors}`;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// src/resources/base.ts
|
|
213
|
+
var BaseResource = class {
|
|
214
|
+
http;
|
|
215
|
+
constructor(http) {
|
|
216
|
+
this.http = http;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Validate API response against Zod schema
|
|
220
|
+
* @throws {ValidationError} if validation fails
|
|
221
|
+
*/
|
|
222
|
+
validate(data, schema) {
|
|
223
|
+
const result = schema.safeParse(data);
|
|
224
|
+
if (!result.success) {
|
|
225
|
+
throw new ValidationError("API response validation failed", result.error);
|
|
226
|
+
}
|
|
227
|
+
return result.data;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// src/resources/alert-channels.ts
|
|
232
|
+
var AlertChannelsResource = class extends BaseResource {
|
|
233
|
+
/**
|
|
234
|
+
* List all notification channels
|
|
235
|
+
*/
|
|
236
|
+
async list() {
|
|
237
|
+
const data = await this.http.get("api/alert-channels").json();
|
|
238
|
+
return this.validate(data, zod.z.array(notificationChannelSchema));
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get a single notification channel by ID
|
|
242
|
+
*/
|
|
243
|
+
async get(id) {
|
|
244
|
+
const data = await this.http.get(`api/alert-channels/${id}`).json();
|
|
245
|
+
return this.validate(data, notificationChannelSchema);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Create a new notification channel
|
|
249
|
+
*/
|
|
250
|
+
async create(input) {
|
|
251
|
+
const validatedInput = this.validate(
|
|
252
|
+
input,
|
|
253
|
+
createNotificationChannelSchema
|
|
254
|
+
);
|
|
255
|
+
const data = await this.http.post("api/alert-channels", { json: validatedInput }).json();
|
|
256
|
+
return this.validate(data, notificationChannelSchema);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Update an existing notification channel
|
|
260
|
+
*/
|
|
261
|
+
async update(id, input) {
|
|
262
|
+
const validatedInput = this.validate(
|
|
263
|
+
input,
|
|
264
|
+
updateNotificationChannelSchema
|
|
265
|
+
);
|
|
266
|
+
const data = await this.http.patch(`api/alert-channels/${id}`, { json: validatedInput }).json();
|
|
267
|
+
return this.validate(data, notificationChannelSchema);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Delete a notification channel
|
|
271
|
+
*/
|
|
272
|
+
async delete(id) {
|
|
273
|
+
await this.http.delete(`api/alert-channels/${id}`);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Send a test notification to verify channel configuration
|
|
277
|
+
*/
|
|
278
|
+
async test(id) {
|
|
279
|
+
const data = await this.http.post(`api/alert-channels/${id}/test`).json();
|
|
280
|
+
return this.validate(data, testChannelResponseSchema);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
var AlertRulesResource = class extends BaseResource {
|
|
284
|
+
/**
|
|
285
|
+
* List all alert rules for a project
|
|
286
|
+
*/
|
|
287
|
+
async list(projectId) {
|
|
288
|
+
const data = await this.http.get(`api/projects/${projectId}/alert-rules`).json();
|
|
289
|
+
return this.validate(data, zod.z.array(alertRuleSchema));
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Get a single alert rule by ID
|
|
293
|
+
*/
|
|
294
|
+
async get(projectId, ruleId) {
|
|
295
|
+
const data = await this.http.get(`api/projects/${projectId}/alert-rules/${ruleId}`).json();
|
|
296
|
+
return this.validate(data, alertRuleSchema);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Create a new alert rule for a project
|
|
300
|
+
*/
|
|
301
|
+
async create(projectId, input) {
|
|
302
|
+
const validatedInput = this.validate(input, createAlertRuleSchema);
|
|
303
|
+
const data = await this.http.post(`api/projects/${projectId}/alert-rules`, { json: validatedInput }).json();
|
|
304
|
+
return this.validate(data, alertRuleSchema);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Update an existing alert rule
|
|
308
|
+
*/
|
|
309
|
+
async update(projectId, ruleId, input) {
|
|
310
|
+
const validatedInput = this.validate(input, updateAlertRuleSchema);
|
|
311
|
+
const data = await this.http.patch(`api/projects/${projectId}/alert-rules/${ruleId}`, {
|
|
312
|
+
json: validatedInput
|
|
313
|
+
}).json();
|
|
314
|
+
return this.validate(data, alertRuleSchema);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Delete an alert rule
|
|
318
|
+
*/
|
|
319
|
+
async delete(projectId, ruleId) {
|
|
320
|
+
await this.http.delete(`api/projects/${projectId}/alert-rules/${ruleId}`);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* List alert history for a project
|
|
324
|
+
*/
|
|
325
|
+
async listHistory(projectId, options) {
|
|
326
|
+
const searchParams = new URLSearchParams();
|
|
327
|
+
if (options?.limit !== void 0) {
|
|
328
|
+
searchParams.set("limit", options.limit.toString());
|
|
329
|
+
}
|
|
330
|
+
const query = searchParams.toString();
|
|
331
|
+
const url = query ? `api/projects/${projectId}/alert-history?${query}` : `api/projects/${projectId}/alert-history`;
|
|
332
|
+
const data = await this.http.get(url).json();
|
|
333
|
+
return this.validate(data, zod.z.array(alertHistorySchema));
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
var userSchema = zod.z.object({
|
|
337
|
+
id: zod.z.number().int().positive(),
|
|
338
|
+
email: zod.z.string().email(),
|
|
339
|
+
is_admin: zod.z.boolean()
|
|
340
|
+
});
|
|
341
|
+
var authResponseSchema = zod.z.object({
|
|
342
|
+
user: userSchema
|
|
343
|
+
});
|
|
344
|
+
zod.z.object({
|
|
345
|
+
user: userSchema,
|
|
346
|
+
cookies: zod.z.array(zod.z.string())
|
|
347
|
+
});
|
|
348
|
+
var loginRequestSchema = zod.z.object({
|
|
349
|
+
email: zod.z.string().email(),
|
|
350
|
+
password: zod.z.string().min(8)
|
|
351
|
+
});
|
|
352
|
+
var registerRequestSchema = zod.z.object({
|
|
353
|
+
email: zod.z.string().email(),
|
|
354
|
+
password: zod.z.string().min(8)
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// src/resources/auth.ts
|
|
358
|
+
var AuthResource = class extends BaseResource {
|
|
359
|
+
/**
|
|
360
|
+
* Register a new user account
|
|
361
|
+
* Creates a new user and automatically logs them in (sets session cookie)
|
|
362
|
+
* @param credentials - Email and password for the new account
|
|
363
|
+
* @returns LoginResult with user information and session cookies
|
|
364
|
+
*/
|
|
365
|
+
async register(credentials) {
|
|
366
|
+
const validatedInput = this.validate(credentials, registerRequestSchema);
|
|
367
|
+
const response = await this.http.post("auth/register", {
|
|
368
|
+
json: validatedInput
|
|
369
|
+
});
|
|
370
|
+
const cookies = response.headers.getSetCookie();
|
|
371
|
+
const data = await response.json();
|
|
372
|
+
const authResponse = this.validate(data, authResponseSchema);
|
|
373
|
+
return {
|
|
374
|
+
user: authResponse.user,
|
|
375
|
+
cookies
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Login with email and password
|
|
380
|
+
* Authenticates the user and sets a session cookie
|
|
381
|
+
* @param credentials - Email and password
|
|
382
|
+
* @returns LoginResult with user information and session cookies
|
|
383
|
+
*/
|
|
384
|
+
async login(credentials) {
|
|
385
|
+
const validatedInput = this.validate(credentials, loginRequestSchema);
|
|
386
|
+
const response = await this.http.post("auth/login", {
|
|
387
|
+
json: validatedInput
|
|
388
|
+
});
|
|
389
|
+
const cookies = response.headers.getSetCookie();
|
|
390
|
+
const data = await response.json();
|
|
391
|
+
const authResponse = this.validate(data, authResponseSchema);
|
|
392
|
+
return {
|
|
393
|
+
user: authResponse.user,
|
|
394
|
+
cookies
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Logout the current user
|
|
399
|
+
* Clears the session cookie
|
|
400
|
+
* @returns Array of Set-Cookie headers (typically clearing cookies)
|
|
401
|
+
*/
|
|
402
|
+
async logout() {
|
|
403
|
+
const response = await this.http.post("auth/logout");
|
|
404
|
+
return response.headers.getSetCookie();
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Get current authenticated user
|
|
408
|
+
* Requires a valid session cookie
|
|
409
|
+
* @returns User information
|
|
410
|
+
*/
|
|
411
|
+
async getCurrentUser() {
|
|
412
|
+
const data = await this.http.get("auth/me").json();
|
|
413
|
+
return this.validate(data, userSchema);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
var eventSchema = zod.z.object({
|
|
417
|
+
id: uuidSchema,
|
|
418
|
+
event_id: uuidSchema,
|
|
419
|
+
issue_id: uuidSchema,
|
|
420
|
+
title: zod.z.string(),
|
|
421
|
+
timestamp: dateTimeSchema,
|
|
422
|
+
level: zod.z.string(),
|
|
423
|
+
platform: zod.z.string(),
|
|
424
|
+
release: zod.z.string(),
|
|
425
|
+
environment: zod.z.string()
|
|
426
|
+
});
|
|
427
|
+
var eventDetailSchema = zod.z.object({
|
|
428
|
+
id: uuidSchema,
|
|
429
|
+
event_id: uuidSchema,
|
|
430
|
+
issue_id: uuidSchema,
|
|
431
|
+
title: zod.z.string(),
|
|
432
|
+
timestamp: dateTimeSchema,
|
|
433
|
+
ingested_at: dateTimeSchema,
|
|
434
|
+
level: zod.z.string(),
|
|
435
|
+
platform: zod.z.string(),
|
|
436
|
+
release: zod.z.string(),
|
|
437
|
+
environment: zod.z.string(),
|
|
438
|
+
server_name: zod.z.string(),
|
|
439
|
+
sdk_name: zod.z.string(),
|
|
440
|
+
sdk_version: zod.z.string(),
|
|
441
|
+
data: zod.z.record(zod.z.string(), zod.z.any())
|
|
442
|
+
// Full Sentry event JSON
|
|
443
|
+
});
|
|
444
|
+
var issueSchema = zod.z.object({
|
|
445
|
+
id: uuidSchema,
|
|
446
|
+
project_id: zod.z.number().int(),
|
|
447
|
+
short_id: zod.z.string(),
|
|
448
|
+
title: zod.z.string(),
|
|
449
|
+
value: zod.z.string(),
|
|
450
|
+
first_seen: dateTimeSchema,
|
|
451
|
+
last_seen: dateTimeSchema,
|
|
452
|
+
event_count: zod.z.number().int(),
|
|
453
|
+
level: zod.z.string().nullable(),
|
|
454
|
+
platform: zod.z.string().nullable(),
|
|
455
|
+
is_resolved: zod.z.boolean(),
|
|
456
|
+
is_muted: zod.z.boolean()
|
|
457
|
+
});
|
|
458
|
+
var updateIssueStateSchema = zod.z.object({
|
|
459
|
+
is_resolved: zod.z.boolean().optional(),
|
|
460
|
+
is_muted: zod.z.boolean().optional()
|
|
461
|
+
});
|
|
462
|
+
var projectSchema = zod.z.object({
|
|
463
|
+
id: zod.z.number().int(),
|
|
464
|
+
name: zod.z.string(),
|
|
465
|
+
slug: zod.z.string(),
|
|
466
|
+
sentry_key: uuidSchema,
|
|
467
|
+
dsn: zod.z.string(),
|
|
468
|
+
stored_event_count: zod.z.number().int(),
|
|
469
|
+
digested_event_count: zod.z.number().int(),
|
|
470
|
+
created_at: dateTimeSchema,
|
|
471
|
+
updated_at: dateTimeSchema
|
|
472
|
+
});
|
|
473
|
+
var createProjectSchema = zod.z.object({
|
|
474
|
+
name: zod.z.string().min(1),
|
|
475
|
+
slug: zod.z.string().optional()
|
|
476
|
+
});
|
|
477
|
+
var updateProjectSchema = zod.z.object({
|
|
478
|
+
name: zod.z.string().min(1).optional()
|
|
479
|
+
});
|
|
480
|
+
var authTokenSchema = zod.z.object({
|
|
481
|
+
id: zod.z.number().int(),
|
|
482
|
+
token_prefix: zod.z.string(),
|
|
483
|
+
description: zod.z.string().nullable(),
|
|
484
|
+
created_at: dateTimeSchema,
|
|
485
|
+
last_used_at: dateTimeSchema.nullable()
|
|
486
|
+
});
|
|
487
|
+
var authTokenCreatedSchema = zod.z.object({
|
|
488
|
+
id: zod.z.number().int(),
|
|
489
|
+
token: zod.z.string(),
|
|
490
|
+
description: zod.z.string().nullable(),
|
|
491
|
+
created_at: dateTimeSchema
|
|
492
|
+
});
|
|
493
|
+
var createAuthTokenSchema = zod.z.object({
|
|
494
|
+
description: zod.z.string().optional()
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// src/resources/events.ts
|
|
498
|
+
var EventsResource = class extends BaseResource {
|
|
499
|
+
/**
|
|
500
|
+
* List events for an issue with pagination
|
|
501
|
+
*/
|
|
502
|
+
async list(projectId, issueId, options) {
|
|
503
|
+
const searchParams = {};
|
|
504
|
+
if (options?.order) {
|
|
505
|
+
searchParams.order = options.order;
|
|
506
|
+
}
|
|
507
|
+
if (options?.cursor) {
|
|
508
|
+
searchParams.cursor = options.cursor;
|
|
509
|
+
}
|
|
510
|
+
const data = await this.http.get(`api/projects/${projectId}/issues/${issueId}/events`, {
|
|
511
|
+
searchParams
|
|
512
|
+
}).json();
|
|
513
|
+
return this.validate(data, paginatedResponseSchema(eventSchema));
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Get a single event by ID with full details
|
|
517
|
+
*/
|
|
518
|
+
async get(projectId, issueId, eventId) {
|
|
519
|
+
const data = await this.http.get(`api/projects/${projectId}/issues/${issueId}/events/${eventId}`).json();
|
|
520
|
+
return this.validate(data, eventDetailSchema);
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
// src/resources/issues.ts
|
|
525
|
+
var IssuesResource = class extends BaseResource {
|
|
526
|
+
/**
|
|
527
|
+
* List issues for a project with offset-based pagination
|
|
528
|
+
*/
|
|
529
|
+
async list(projectId, options) {
|
|
530
|
+
const searchParams = {};
|
|
531
|
+
if (options?.page !== void 0) {
|
|
532
|
+
searchParams.page = options.page.toString();
|
|
533
|
+
}
|
|
534
|
+
if (options?.per_page !== void 0) {
|
|
535
|
+
searchParams.per_page = options.per_page.toString();
|
|
536
|
+
}
|
|
537
|
+
if (options?.sort) {
|
|
538
|
+
searchParams.sort = options.sort;
|
|
539
|
+
}
|
|
540
|
+
if (options?.order) {
|
|
541
|
+
searchParams.order = options.order;
|
|
542
|
+
}
|
|
543
|
+
if (options?.filter) {
|
|
544
|
+
searchParams.filter = options.filter;
|
|
545
|
+
}
|
|
546
|
+
const data = await this.http.get(`api/projects/${projectId}/issues`, { searchParams }).json();
|
|
547
|
+
return this.validate(data, offsetPaginatedResponseSchema(issueSchema));
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Get a single issue by ID
|
|
551
|
+
*/
|
|
552
|
+
async get(projectId, issueId) {
|
|
553
|
+
const data = await this.http.get(`api/projects/${projectId}/issues/${issueId}`).json();
|
|
554
|
+
return this.validate(data, issueSchema);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Update issue state (resolve, mute, etc.)
|
|
558
|
+
*/
|
|
559
|
+
async updateState(projectId, issueId, input) {
|
|
560
|
+
const validatedInput = this.validate(input, updateIssueStateSchema);
|
|
561
|
+
const data = await this.http.patch(`api/projects/${projectId}/issues/${issueId}`, {
|
|
562
|
+
json: validatedInput
|
|
563
|
+
}).json();
|
|
564
|
+
return this.validate(data, issueSchema);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Delete an issue
|
|
568
|
+
*/
|
|
569
|
+
async delete(projectId, issueId) {
|
|
570
|
+
await this.http.delete(`api/projects/${projectId}/issues/${issueId}`);
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
// src/resources/projects.ts
|
|
575
|
+
var ProjectsResource = class extends BaseResource {
|
|
576
|
+
/**
|
|
577
|
+
* List projects with pagination
|
|
578
|
+
*/
|
|
579
|
+
async list(options) {
|
|
580
|
+
const searchParams = new URLSearchParams();
|
|
581
|
+
if (options?.page !== void 0) {
|
|
582
|
+
searchParams.set("page", options.page.toString());
|
|
583
|
+
}
|
|
584
|
+
if (options?.per_page !== void 0) {
|
|
585
|
+
searchParams.set("per_page", options.per_page.toString());
|
|
586
|
+
}
|
|
587
|
+
if (options?.order) {
|
|
588
|
+
searchParams.set("order", options.order);
|
|
589
|
+
}
|
|
590
|
+
const query = searchParams.toString();
|
|
591
|
+
const url = query ? `api/projects?${query}` : "api/projects";
|
|
592
|
+
const data = await this.http.get(url).json();
|
|
593
|
+
return this.validate(data, offsetPaginatedResponseSchema(projectSchema));
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Get a single project by ID
|
|
597
|
+
*/
|
|
598
|
+
async get(id) {
|
|
599
|
+
const data = await this.http.get(`api/projects/${id}`).json();
|
|
600
|
+
return this.validate(data, projectSchema);
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Create a new project
|
|
604
|
+
*/
|
|
605
|
+
async create(input) {
|
|
606
|
+
const validatedInput = this.validate(input, createProjectSchema);
|
|
607
|
+
const data = await this.http.post("api/projects", { json: validatedInput }).json();
|
|
608
|
+
return this.validate(data, projectSchema);
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Update an existing project
|
|
612
|
+
*/
|
|
613
|
+
async update(id, input) {
|
|
614
|
+
const validatedInput = this.validate(input, updateProjectSchema);
|
|
615
|
+
const data = await this.http.patch(`api/projects/${id}`, { json: validatedInput }).json();
|
|
616
|
+
return this.validate(data, projectSchema);
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Delete a project
|
|
620
|
+
*/
|
|
621
|
+
async delete(id) {
|
|
622
|
+
await this.http.delete(`api/projects/${id}`);
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
// src/resources/tokens.ts
|
|
627
|
+
var TokensResource = class extends BaseResource {
|
|
628
|
+
/**
|
|
629
|
+
* List all auth tokens (masked)
|
|
630
|
+
*/
|
|
631
|
+
async list() {
|
|
632
|
+
const data = await this.http.get("api/tokens").json();
|
|
633
|
+
return this.validate(data, authTokenSchema.array());
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Get a single auth token by ID (masked)
|
|
637
|
+
*/
|
|
638
|
+
async get(id) {
|
|
639
|
+
const data = await this.http.get(`api/tokens/${id}`).json();
|
|
640
|
+
return this.validate(data, authTokenSchema);
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Create a new auth token
|
|
644
|
+
* Note: The full token is only returned once during creation
|
|
645
|
+
*/
|
|
646
|
+
async create(input) {
|
|
647
|
+
const validatedInput = this.validate(input, createAuthTokenSchema);
|
|
648
|
+
const data = await this.http.post("api/tokens", { json: validatedInput }).json();
|
|
649
|
+
return this.validate(data, authTokenCreatedSchema);
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Delete an auth token
|
|
653
|
+
*/
|
|
654
|
+
async delete(id) {
|
|
655
|
+
await this.http.delete(`api/tokens/${id}`);
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
function transformHttpError(error) {
|
|
659
|
+
const { response } = error;
|
|
660
|
+
const status = response.status;
|
|
661
|
+
let errorMessage = `HTTP ${status} error`;
|
|
662
|
+
const body = error.data;
|
|
663
|
+
if (body) {
|
|
664
|
+
errorMessage = body.error || body.message || errorMessage;
|
|
665
|
+
}
|
|
666
|
+
switch (status) {
|
|
667
|
+
case 400:
|
|
668
|
+
return new BadRequestError(errorMessage);
|
|
669
|
+
case 401:
|
|
670
|
+
return new AuthenticationError(errorMessage);
|
|
671
|
+
case 403:
|
|
672
|
+
return new AuthorizationError(errorMessage);
|
|
673
|
+
case 404:
|
|
674
|
+
return new NotFoundError(errorMessage);
|
|
675
|
+
case 429: {
|
|
676
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
677
|
+
return new RateLimitError(errorMessage, retryAfter ?? void 0);
|
|
678
|
+
}
|
|
679
|
+
case 500:
|
|
680
|
+
case 502:
|
|
681
|
+
case 503:
|
|
682
|
+
case 504:
|
|
683
|
+
return new ServerError(errorMessage, status);
|
|
684
|
+
default:
|
|
685
|
+
return new RustrakError(errorMessage, { statusCode: status });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
function createKyInstance(config) {
|
|
689
|
+
const headers = {
|
|
690
|
+
"Content-Type": "application/json",
|
|
691
|
+
...config.headers
|
|
692
|
+
};
|
|
693
|
+
if (config.token) {
|
|
694
|
+
headers.Authorization = `Bearer ${config.token}`;
|
|
695
|
+
}
|
|
696
|
+
return ky__default.default.create({
|
|
697
|
+
prefix: config.baseUrl,
|
|
698
|
+
timeout: config.timeout ?? 3e4,
|
|
699
|
+
credentials: "include",
|
|
700
|
+
retry: {
|
|
701
|
+
limit: config.maxRetries ?? 2,
|
|
702
|
+
statusCodes: [408, 500, 502, 503, 504],
|
|
703
|
+
methods: ["get", "post", "put", "patch", "delete"]
|
|
704
|
+
},
|
|
705
|
+
headers,
|
|
706
|
+
hooks: {
|
|
707
|
+
beforeError: [
|
|
708
|
+
({ error }) => {
|
|
709
|
+
if (error.name === "TimeoutError") {
|
|
710
|
+
throw new NetworkError("Request timed out", error);
|
|
711
|
+
}
|
|
712
|
+
if (ky.isHTTPError(error)) {
|
|
713
|
+
throw transformHttpError(error);
|
|
714
|
+
}
|
|
715
|
+
throw new NetworkError(error.message, error);
|
|
716
|
+
}
|
|
717
|
+
]
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// src/client.ts
|
|
723
|
+
var RustrakClient = class {
|
|
724
|
+
http;
|
|
725
|
+
/**
|
|
726
|
+
* Authentication API resource
|
|
727
|
+
*/
|
|
728
|
+
auth;
|
|
729
|
+
/**
|
|
730
|
+
* Projects API resource
|
|
731
|
+
*/
|
|
732
|
+
projects;
|
|
733
|
+
/**
|
|
734
|
+
* Issues API resource
|
|
735
|
+
*/
|
|
736
|
+
issues;
|
|
737
|
+
/**
|
|
738
|
+
* Events API resource
|
|
739
|
+
*/
|
|
740
|
+
events;
|
|
741
|
+
/**
|
|
742
|
+
* Auth Tokens API resource
|
|
743
|
+
*/
|
|
744
|
+
tokens;
|
|
745
|
+
/**
|
|
746
|
+
* Alert Channels API resource (global notification destinations)
|
|
747
|
+
*/
|
|
748
|
+
alertChannels;
|
|
749
|
+
/**
|
|
750
|
+
* Alert Rules API resource (per-project alert configuration)
|
|
751
|
+
*/
|
|
752
|
+
alertRules;
|
|
753
|
+
/**
|
|
754
|
+
* Create a new Rustrak API client
|
|
755
|
+
*
|
|
756
|
+
* @param config - Client configuration
|
|
757
|
+
*/
|
|
758
|
+
constructor(config) {
|
|
759
|
+
this.http = createKyInstance(config);
|
|
760
|
+
this.auth = new AuthResource(this.http);
|
|
761
|
+
this.projects = new ProjectsResource(this.http);
|
|
762
|
+
this.issues = new IssuesResource(this.http);
|
|
763
|
+
this.events = new EventsResource(this.http);
|
|
764
|
+
this.tokens = new TokensResource(this.http);
|
|
765
|
+
this.alertChannels = new AlertChannelsResource(this.http);
|
|
766
|
+
this.alertRules = new AlertRulesResource(this.http);
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
exports.AuthenticationError = AuthenticationError;
|
|
771
|
+
exports.AuthorizationError = AuthorizationError;
|
|
772
|
+
exports.BadRequestError = BadRequestError;
|
|
773
|
+
exports.NetworkError = NetworkError;
|
|
774
|
+
exports.NotFoundError = NotFoundError;
|
|
775
|
+
exports.RateLimitError = RateLimitError;
|
|
776
|
+
exports.RustrakClient = RustrakClient;
|
|
777
|
+
exports.RustrakError = RustrakError;
|
|
778
|
+
exports.ServerError = ServerError;
|
|
779
|
+
exports.ValidationError = ValidationError;
|
|
780
|
+
//# sourceMappingURL=index.cjs.map
|
|
781
|
+
//# sourceMappingURL=index.cjs.map
|