@rustrak/client 0.3.13 → 0.3.15

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/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import ky, { isHTTPError } from 'ky';
3
3
 
4
- // src/resources/alert-integrations.ts
4
+ // src/resources/agents.ts
5
5
  var paginatedResponseSchema = (itemSchema) => z.object({
6
6
  items: z.array(itemSchema),
7
7
  next_cursor: z.string().optional(),
@@ -32,7 +32,29 @@ z.object({
32
32
  message: z.string().optional()
33
33
  });
34
34
 
35
- // src/schemas/alert.ts
35
+ // src/schemas/agent.ts
36
+ var agentTimeseriesPointSchema = z.object({
37
+ bucket: dateTimeSchema,
38
+ value: z.number()
39
+ });
40
+ var agentDurationPointSchema = z.object({
41
+ bucket: dateTimeSchema,
42
+ avg_ms: z.number(),
43
+ p95_ms: z.number()
44
+ });
45
+ var genAiBreakdownRowSchema = z.object({
46
+ label: z.string(),
47
+ value: z.number()
48
+ });
49
+ var agentTraceSummarySchema = z.object({
50
+ trace_id: z.string(),
51
+ /** Every distinct agent that ran in this trace, earliest first. */
52
+ agent_names: z.array(z.string()),
53
+ duration_ms: z.number().nullable(),
54
+ total_tokens: z.number(),
55
+ tool_call_count: z.number().int(),
56
+ started_at: dateTimeSchema
57
+ });
36
58
  var providerTypeSchema = z.enum(["webhook", "email", "slack"]);
37
59
  var alertTypeSchema = z.enum(["new_issue", "regression", "unmute"]);
38
60
  var alertStatusSchema = z.enum([
@@ -56,443 +78,73 @@ var alertIntegrationSchema = z.object({
56
78
  });
57
79
  var createAlertIntegrationSchema = z.object({
58
80
  name: z.string().min(1),
59
- provider_type: providerTypeSchema,
60
- credentials: z.record(z.string(), z.unknown()),
61
- is_enabled: z.boolean().optional()
62
- });
63
- var updateAlertIntegrationSchema = z.object({
64
- name: z.string().min(1).optional(),
65
- credentials: z.record(z.string(), z.unknown()).optional(),
66
- is_enabled: z.boolean().optional()
67
- });
68
- var alertRuleChannelInputSchema = z.object({
69
- integration_id: z.number().int(),
70
- routing_override: z.record(z.string(), z.unknown()).default({})
71
- });
72
- var alertRuleSchema = z.object({
73
- id: z.number().int(),
74
- project_id: z.number().int(),
75
- name: z.string(),
76
- alert_type: alertTypeSchema,
77
- is_enabled: z.boolean(),
78
- conditions: z.record(z.string(), z.unknown()),
79
- cooldown_minutes: z.number().int(),
80
- last_triggered_at: dateTimeSchema.nullable(),
81
- created_at: dateTimeSchema,
82
- updated_at: dateTimeSchema,
83
- channels: z.array(alertRuleChannelInputSchema).default([]),
84
- integration_ids: z.array(z.number().int())
85
- });
86
- var createAlertRuleSchema = z.object({
87
- name: z.string().min(1),
88
- alert_type: alertTypeSchema,
89
- channels: z.array(alertRuleChannelInputSchema).default([]),
90
- is_enabled: z.boolean().optional(),
91
- conditions: z.record(z.string(), z.unknown()).optional(),
92
- cooldown_minutes: z.number().int().min(0).optional()
93
- });
94
- var updateAlertRuleSchema = z.object({
95
- name: z.string().min(1).optional(),
96
- is_enabled: z.boolean().optional(),
97
- conditions: z.record(z.string(), z.unknown()).optional(),
98
- cooldown_minutes: z.number().int().min(0).optional(),
99
- channels: z.array(alertRuleChannelInputSchema).optional()
100
- });
101
- var alertHistorySchema = z.object({
102
- id: z.number().int(),
103
- alert_rule_id: z.number().int().nullable(),
104
- integration_id: z.number().int().nullable(),
105
- issue_id: z.string().uuid().nullable(),
106
- project_id: z.number().int().nullable(),
107
- alert_type: z.string(),
108
- channel_type: z.string(),
109
- channel_name: z.string(),
110
- status: alertStatusSchema,
111
- attempt_count: z.number().int(),
112
- next_retry_at: dateTimeSchema.nullable(),
113
- error_message: z.string().nullable(),
114
- http_status_code: z.number().int().nullable(),
115
- idempotency_key: z.string(),
116
- created_at: dateTimeSchema,
117
- sent_at: dateTimeSchema.nullable()
118
- });
119
- var testChannelResponseSchema = z.object({
120
- success: z.boolean(),
121
- message: z.string()
122
- });
123
- var testIntegrationBodySchema = z.object({
124
- routing_override: z.record(z.string(), z.unknown()).optional()
125
- });
126
-
127
- // src/errors/base.ts
128
- var RustrakError = class extends Error {
129
- /**
130
- * Whether this error is safe to retry
131
- */
132
- retryable;
133
- /**
134
- * HTTP status code if applicable
135
- */
136
- statusCode;
137
- /**
138
- * Original error cause
139
- */
140
- cause;
141
- constructor(message, options) {
142
- super(message);
143
- this.name = this.constructor.name;
144
- this.retryable = options?.retryable ?? false;
145
- this.statusCode = options?.statusCode;
146
- this.cause = options?.cause;
147
- if (Error.captureStackTrace) {
148
- Error.captureStackTrace(this, this.constructor);
149
- }
150
- }
151
- };
152
-
153
- // src/errors/http.ts
154
- var NetworkError = class extends RustrakError {
155
- constructor(message, cause) {
156
- super(message, { retryable: true, cause });
157
- }
158
- };
159
- var AuthenticationError = class extends RustrakError {
160
- constructor(message = "Authentication failed") {
161
- super(message, { retryable: false, statusCode: 401 });
162
- }
163
- };
164
- var AuthorizationError = class extends RustrakError {
165
- constructor(message = "Insufficient permissions") {
166
- super(message, { retryable: false, statusCode: 403 });
167
- }
168
- };
169
- var NotFoundError = class extends RustrakError {
170
- constructor(resource) {
171
- super(`Resource not found: ${resource}`, {
172
- retryable: false,
173
- statusCode: 404
174
- });
175
- }
176
- };
177
- var RateLimitError = class extends RustrakError {
178
- /**
179
- * Number of seconds to wait before retrying (from Retry-After header)
180
- */
181
- retryAfter;
182
- constructor(message = "Rate limit exceeded", retryAfter) {
183
- super(message, { retryable: true, statusCode: 429 });
184
- if (retryAfter !== void 0) {
185
- this.retryAfter = typeof retryAfter === "string" ? parseInt(retryAfter, 10) : retryAfter;
186
- }
187
- }
188
- };
189
- var ServerError = class extends RustrakError {
190
- constructor(message, statusCode = 500) {
191
- super(message, { retryable: true, statusCode });
192
- }
193
- };
194
- var BadRequestError = class extends RustrakError {
195
- constructor(message) {
196
- super(message, { retryable: false, statusCode: 400 });
197
- }
198
- };
199
-
200
- // src/errors/validation.ts
201
- var ValidationError = class extends RustrakError {
202
- /**
203
- * Zod validation errors
204
- */
205
- validationErrors;
206
- constructor(message, validationErrors) {
207
- super(message, { retryable: false });
208
- this.validationErrors = validationErrors;
209
- }
210
- /**
211
- * Get a formatted string of validation errors
212
- */
213
- getValidationDetails() {
214
- if (!this.validationErrors) {
215
- return this.message;
216
- }
217
- const errors = this.validationErrors.issues.map((err) => `${err.path.map(String).join(".")}: ${err.message}`).join(", ");
218
- return `${this.message} - ${errors}`;
219
- }
220
- };
221
-
222
- // src/resources/base.ts
223
- var BaseResource = class {
224
- http;
225
- constructor(http) {
226
- this.http = http;
227
- }
228
- /**
229
- * Validate API response against Zod schema
230
- * @throws {ValidationError} if validation fails
231
- */
232
- validate(data, schema) {
233
- const result = schema.safeParse(data);
234
- if (!result.success) {
235
- throw new ValidationError("API response validation failed", result.error);
236
- }
237
- return result.data;
238
- }
239
- };
240
-
241
- // src/resources/alert-integrations.ts
242
- var AlertIntegrationsResource = class extends BaseResource {
243
- /**
244
- * List all alert integrations
245
- */
246
- async list() {
247
- const data = await this.http.get("api/integrations").json();
248
- return this.validate(data, z.array(alertIntegrationSchema));
249
- }
250
- /**
251
- * Get a single alert integration by ID
252
- */
253
- async get(id) {
254
- const data = await this.http.get(`api/integrations/${id}`).json();
255
- return this.validate(data, alertIntegrationSchema);
256
- }
257
- /**
258
- * Create a new alert integration
259
- */
260
- async create(input) {
261
- const validatedInput = this.validate(input, createAlertIntegrationSchema);
262
- const data = await this.http.post("api/integrations", { json: validatedInput }).json();
263
- return this.validate(data, alertIntegrationSchema);
264
- }
265
- /**
266
- * Update an existing alert integration
267
- */
268
- async update(id, input) {
269
- const validatedInput = this.validate(input, updateAlertIntegrationSchema);
270
- const data = await this.http.patch(`api/integrations/${id}`, { json: validatedInput }).json();
271
- return this.validate(data, alertIntegrationSchema);
272
- }
273
- /**
274
- * Delete an alert integration
275
- */
276
- async delete(id) {
277
- await this.http.delete(`api/integrations/${id}`);
278
- }
279
- /**
280
- * Send a test notification to verify integration configuration.
281
- * For Slack bot_token integrations, routingOverride must include `channel`.
282
- */
283
- async test(id, routingOverride) {
284
- const body = routingOverride !== void 0 ? this.validate(
285
- { routing_override: routingOverride },
286
- testIntegrationBodySchema
287
- ) : void 0;
288
- const data = await this.http.post(
289
- `api/integrations/${id}/test`,
290
- body !== void 0 ? { json: body } : void 0
291
- ).json();
292
- return this.validate(data, testChannelResponseSchema);
293
- }
294
- };
295
- var AlertRulesResource = class extends BaseResource {
296
- /**
297
- * List all alert rules for a project
298
- */
299
- async list(projectId) {
300
- const data = await this.http.get(`api/projects/${projectId}/alert-rules`).json();
301
- return this.validate(data, z.array(alertRuleSchema));
302
- }
303
- /**
304
- * Get a single alert rule by ID
305
- */
306
- async get(projectId, ruleId) {
307
- const data = await this.http.get(`api/projects/${projectId}/alert-rules/${ruleId}`).json();
308
- return this.validate(data, alertRuleSchema);
309
- }
310
- /**
311
- * Create a new alert rule for a project
312
- */
313
- async create(projectId, input) {
314
- const validatedInput = this.validate(input, createAlertRuleSchema);
315
- const data = await this.http.post(`api/projects/${projectId}/alert-rules`, { json: validatedInput }).json();
316
- return this.validate(data, alertRuleSchema);
317
- }
318
- /**
319
- * Update an existing alert rule
320
- */
321
- async update(projectId, ruleId, input) {
322
- const validatedInput = this.validate(input, updateAlertRuleSchema);
323
- const data = await this.http.patch(`api/projects/${projectId}/alert-rules/${ruleId}`, {
324
- json: validatedInput
325
- }).json();
326
- return this.validate(data, alertRuleSchema);
327
- }
328
- /**
329
- * Delete an alert rule
330
- */
331
- async delete(projectId, ruleId) {
332
- await this.http.delete(`api/projects/${projectId}/alert-rules/${ruleId}`);
333
- }
334
- /**
335
- * List alert history for a project
336
- */
337
- async listHistory(projectId, options) {
338
- const searchParams = new URLSearchParams();
339
- if (options?.limit !== void 0) {
340
- searchParams.set("limit", options.limit.toString());
341
- }
342
- const query = searchParams.toString();
343
- const url = query ? `api/projects/${projectId}/alert-history?${query}` : `api/projects/${projectId}/alert-history`;
344
- const data = await this.http.get(url).json();
345
- return this.validate(data, z.array(alertHistorySchema));
346
- }
347
- };
348
- var globalRoleSchema = z.enum(["admin", "member"]);
349
- var teamMemberSchema = z.object({
350
- id: z.number().int(),
351
- email: z.string().email(),
352
- role: globalRoleSchema,
353
- is_active: z.boolean(),
354
- /** True for the first-registered account, which cannot be demoted or deleted. */
355
- is_primary: z.boolean().optional(),
356
- created_at: dateTimeSchema,
357
- last_login: dateTimeSchema.nullable().optional()
358
- });
359
- var updateUserRoleSchema = z.object({
360
- role: globalRoleSchema
361
- });
362
-
363
- // src/schemas/invitation.ts
364
- var invitationStatusSchema = z.string();
365
- var invitationSchema = z.object({
366
- token: z.string(),
367
- email: z.string().email(),
368
- role: globalRoleSchema,
369
- status: invitationStatusSchema,
370
- expires_at: dateTimeSchema,
371
- created_at: dateTimeSchema
372
- });
373
- var invitationInfoSchema = z.object({
374
- email: z.string().email(),
375
- role: globalRoleSchema,
376
- status: invitationStatusSchema,
377
- expires_at: dateTimeSchema
378
- });
379
- var createInvitationSchema = z.object({
380
- email: z.string().email(),
381
- role: globalRoleSchema
382
- });
383
- var acceptInvitationSchema = z.object({
384
- token: z.string().min(1),
385
- password: z.string().min(1)
386
- });
387
- var userSchema = z.object({
388
- id: z.number().int().positive(),
389
- email: z.string().email(),
390
- role: globalRoleSchema,
391
- is_admin: z.boolean()
392
- });
393
- var authResponseSchema = z.object({
394
- user: userSchema
395
- });
396
- z.object({
397
- user: userSchema,
398
- cookies: z.array(z.string())
399
- });
400
- var loginRequestSchema = z.object({
401
- email: z.string().email(),
402
- password: z.string().min(1)
403
- });
404
- var registerRequestSchema = z.object({
405
- email: z.string().email(),
406
- password: z.string().min(1)
407
- });
408
-
409
- // src/resources/auth.ts
410
- var AuthResource = class extends BaseResource {
411
- /**
412
- * Register a new user account
413
- * Creates a new user and automatically logs them in (sets session cookie)
414
- * @param credentials - Email and password for the new account
415
- * @returns LoginResult with user information and session cookies
416
- */
417
- async register(credentials) {
418
- const validatedInput = this.validate(credentials, registerRequestSchema);
419
- const response = await this.http.post("auth/register", {
420
- json: validatedInput
421
- });
422
- const cookies = response.headers.getSetCookie();
423
- const data = await response.json();
424
- const authResponse = this.validate(data, authResponseSchema);
425
- return {
426
- user: authResponse.user,
427
- cookies
428
- };
429
- }
430
- /**
431
- * Login with email and password
432
- * Authenticates the user and sets a session cookie
433
- * @param credentials - Email and password
434
- * @returns LoginResult with user information and session cookies
435
- */
436
- async login(credentials) {
437
- const validatedInput = this.validate(credentials, loginRequestSchema);
438
- const response = await this.http.post("auth/login", {
439
- json: validatedInput
440
- });
441
- const cookies = response.headers.getSetCookie();
442
- const data = await response.json();
443
- const authResponse = this.validate(data, authResponseSchema);
444
- return {
445
- user: authResponse.user,
446
- cookies
447
- };
448
- }
449
- /**
450
- * Logout the current user
451
- * Clears the session cookie
452
- * @returns Array of Set-Cookie headers (typically clearing cookies)
453
- */
454
- async logout() {
455
- const response = await this.http.post("auth/logout");
456
- return response.headers.getSetCookie();
457
- }
458
- /**
459
- * Get current authenticated user
460
- * Requires a valid session cookie
461
- * @returns User information
462
- */
463
- async getCurrentUser() {
464
- const data = await this.http.get("auth/me").json();
465
- return this.validate(data, userSchema);
466
- }
467
- /**
468
- * Get the details of a pending invitation by its token (public endpoint)
469
- * Used by the accept-invitation page before the user has an account
470
- * @param token - Invitation token
471
- * @returns Invitation info (email, role, status, expiry)
472
- */
473
- async getInvitation(token) {
474
- const data = await this.http.get(`auth/invitation/${token}`).json();
475
- return this.validate(data, invitationInfoSchema);
476
- }
477
- /**
478
- * Accept a pending invitation, creating the user account and logging in
479
- * @param input - Invitation token and the new account's password
480
- * @returns LoginResult with user information and session cookies
481
- */
482
- async acceptInvitation(input) {
483
- const validatedInput = this.validate(input, acceptInvitationSchema);
484
- const response = await this.http.post("auth/accept-invitation", {
485
- json: validatedInput
486
- });
487
- const cookies = response.headers.getSetCookie();
488
- const data = await response.json();
489
- const authResponse = this.validate(data, authResponseSchema);
490
- return {
491
- user: authResponse.user,
492
- cookies
493
- };
494
- }
495
- };
81
+ provider_type: providerTypeSchema,
82
+ credentials: z.record(z.string(), z.unknown()),
83
+ is_enabled: z.boolean().optional()
84
+ });
85
+ var updateAlertIntegrationSchema = z.object({
86
+ name: z.string().min(1).optional(),
87
+ credentials: z.record(z.string(), z.unknown()).optional(),
88
+ is_enabled: z.boolean().optional()
89
+ });
90
+ var alertRuleChannelInputSchema = z.object({
91
+ integration_id: z.number().int(),
92
+ routing_override: z.record(z.string(), z.unknown()).default({})
93
+ });
94
+ var alertRuleSchema = z.object({
95
+ id: z.number().int(),
96
+ project_id: z.number().int(),
97
+ name: z.string(),
98
+ alert_type: alertTypeSchema,
99
+ is_enabled: z.boolean(),
100
+ conditions: z.record(z.string(), z.unknown()),
101
+ cooldown_minutes: z.number().int(),
102
+ last_triggered_at: dateTimeSchema.nullable(),
103
+ created_at: dateTimeSchema,
104
+ updated_at: dateTimeSchema,
105
+ channels: z.array(alertRuleChannelInputSchema).default([]),
106
+ integration_ids: z.array(z.number().int())
107
+ });
108
+ var createAlertRuleSchema = z.object({
109
+ name: z.string().min(1),
110
+ alert_type: alertTypeSchema,
111
+ channels: z.array(alertRuleChannelInputSchema).default([]),
112
+ is_enabled: z.boolean().optional(),
113
+ conditions: z.record(z.string(), z.unknown()).optional(),
114
+ cooldown_minutes: z.number().int().min(0).optional()
115
+ });
116
+ var updateAlertRuleSchema = z.object({
117
+ name: z.string().min(1).optional(),
118
+ is_enabled: z.boolean().optional(),
119
+ conditions: z.record(z.string(), z.unknown()).optional(),
120
+ cooldown_minutes: z.number().int().min(0).optional(),
121
+ channels: z.array(alertRuleChannelInputSchema).optional()
122
+ });
123
+ var alertHistorySchema = z.object({
124
+ id: z.number().int(),
125
+ alert_rule_id: z.number().int().nullable(),
126
+ integration_id: z.number().int().nullable(),
127
+ issue_id: z.string().uuid().nullable(),
128
+ project_id: z.number().int().nullable(),
129
+ alert_type: z.string(),
130
+ channel_type: z.string(),
131
+ channel_name: z.string(),
132
+ status: alertStatusSchema,
133
+ attempt_count: z.number().int(),
134
+ next_retry_at: dateTimeSchema.nullable(),
135
+ error_message: z.string().nullable(),
136
+ http_status_code: z.number().int().nullable(),
137
+ idempotency_key: z.string(),
138
+ created_at: dateTimeSchema,
139
+ sent_at: dateTimeSchema.nullable()
140
+ });
141
+ var testChannelResponseSchema = z.object({
142
+ success: z.boolean(),
143
+ message: z.string()
144
+ });
145
+ var testIntegrationBodySchema = z.object({
146
+ routing_override: z.record(z.string(), z.unknown()).optional()
147
+ });
496
148
  var eventSchema = z.object({
497
149
  id: uuidSchema,
498
150
  event_id: eventIdSchema,
@@ -523,6 +175,45 @@ var eventDetailSchema = z.object({
523
175
  data: z.record(z.string(), z.any())
524
176
  // Full Sentry event JSON
525
177
  });
178
+ var globalRoleSchema = z.enum(["admin", "member"]);
179
+ var teamMemberSchema = z.object({
180
+ id: z.number().int(),
181
+ email: z.string().email(),
182
+ role: globalRoleSchema,
183
+ is_active: z.boolean(),
184
+ /** True for the first-registered account, which cannot be demoted or deleted. */
185
+ is_primary: z.boolean().optional(),
186
+ created_at: dateTimeSchema,
187
+ last_login: dateTimeSchema.nullable().optional()
188
+ });
189
+ var updateUserRoleSchema = z.object({
190
+ role: globalRoleSchema
191
+ });
192
+
193
+ // src/schemas/invitation.ts
194
+ var invitationStatusSchema = z.string();
195
+ var invitationSchema = z.object({
196
+ token: z.string(),
197
+ email: z.string().email(),
198
+ role: globalRoleSchema,
199
+ status: invitationStatusSchema,
200
+ expires_at: dateTimeSchema,
201
+ created_at: dateTimeSchema
202
+ });
203
+ var invitationInfoSchema = z.object({
204
+ email: z.string().email(),
205
+ role: globalRoleSchema,
206
+ status: invitationStatusSchema,
207
+ expires_at: dateTimeSchema
208
+ });
209
+ var createInvitationSchema = z.object({
210
+ email: z.string().email(),
211
+ role: globalRoleSchema
212
+ });
213
+ var acceptInvitationSchema = z.object({
214
+ token: z.string().min(1),
215
+ password: z.string().min(1)
216
+ });
526
217
  var issueStatusSchema = z.enum(["unresolved", "resolved", "ignored"]);
527
218
  var issuePrioritySchema = z.enum(["low", "medium", "high"]);
528
219
  var issueSchema = z.object({
@@ -643,9 +334,6 @@ var bulkUpdateIssuesSchema = z.object({
643
334
  var bulkDeleteIssuesSchema = z.object({
644
335
  ids: z.array(uuidSchema)
645
336
  });
646
- var createDeploySchema = z.object({
647
- version: z.string()
648
- });
649
337
  var logSchema = z.object({
650
338
  id: uuidSchema,
651
339
  trace_id: z.string().nullable(),
@@ -826,6 +514,8 @@ var transactionDetailSchema = z.object({
826
514
  });
827
515
  var spanSchema = z.object({
828
516
  id: uuidSchema,
517
+ /** Parent transaction, if this span was extracted from one. `null` for a standalone span. */
518
+ transaction_id: uuidSchema.nullable(),
829
519
  span_id: z.string().nullable(),
830
520
  trace_id: z.string().nullable(),
831
521
  parent_span_id: z.string().nullable(),
@@ -837,7 +527,21 @@ var spanSchema = z.object({
837
527
  duration_ms: z.number().nullable(),
838
528
  exclusive_time_ms: z.number().nullable(),
839
529
  is_segment: z.boolean(),
840
- segment_id: z.string().nullable()
530
+ segment_id: z.string().nullable(),
531
+ /** Only ever set for standalone spans — a transaction-embedded span has no parent row to inherit these from. */
532
+ platform: z.string().nullable(),
533
+ release: z.string().nullable(),
534
+ environment: z.string().nullable(),
535
+ /** gen_ai.* denormalized fields — all null unless recognized as an AI span. */
536
+ gen_ai_operation_type: z.string().nullable(),
537
+ gen_ai_agent_name: z.string().nullable(),
538
+ gen_ai_request_model: z.string().nullable(),
539
+ gen_ai_response_model: z.string().nullable(),
540
+ gen_ai_tool_name: z.string().nullable(),
541
+ gen_ai_conversation_id: z.string().nullable(),
542
+ gen_ai_usage_input_tokens: z.number().nullable(),
543
+ gen_ai_usage_output_tokens: z.number().nullable(),
544
+ gen_ai_usage_total_tokens: z.number().nullable()
841
545
  });
842
546
  var transactionStatsSchema = z.object({
843
547
  transaction_name: z.string(),
@@ -848,6 +552,422 @@ var transactionStatsSchema = z.object({
848
552
  p99_ms: z.number(),
849
553
  failure_rate: z.number()
850
554
  });
555
+ var userSchema = z.object({
556
+ id: z.number().int().positive(),
557
+ email: z.string().email(),
558
+ role: globalRoleSchema,
559
+ is_admin: z.boolean()
560
+ });
561
+ var authResponseSchema = z.object({
562
+ user: userSchema
563
+ });
564
+ z.object({
565
+ user: userSchema,
566
+ cookies: z.array(z.string())
567
+ });
568
+ var loginRequestSchema = z.object({
569
+ email: z.string().email(),
570
+ password: z.string().min(1)
571
+ });
572
+ var registerRequestSchema = z.object({
573
+ email: z.string().email(),
574
+ password: z.string().min(1)
575
+ });
576
+
577
+ // src/errors/base.ts
578
+ var RustrakError = class extends Error {
579
+ /**
580
+ * Whether this error is safe to retry
581
+ */
582
+ retryable;
583
+ /**
584
+ * HTTP status code if applicable
585
+ */
586
+ statusCode;
587
+ /**
588
+ * Original error cause
589
+ */
590
+ cause;
591
+ constructor(message, options) {
592
+ super(message);
593
+ this.name = this.constructor.name;
594
+ this.retryable = options?.retryable ?? false;
595
+ this.statusCode = options?.statusCode;
596
+ this.cause = options?.cause;
597
+ if (Error.captureStackTrace) {
598
+ Error.captureStackTrace(this, this.constructor);
599
+ }
600
+ }
601
+ };
602
+
603
+ // src/errors/http.ts
604
+ var NetworkError = class extends RustrakError {
605
+ constructor(message, cause) {
606
+ super(message, { retryable: true, cause });
607
+ }
608
+ };
609
+ var AuthenticationError = class extends RustrakError {
610
+ constructor(message = "Authentication failed") {
611
+ super(message, { retryable: false, statusCode: 401 });
612
+ }
613
+ };
614
+ var AuthorizationError = class extends RustrakError {
615
+ constructor(message = "Insufficient permissions") {
616
+ super(message, { retryable: false, statusCode: 403 });
617
+ }
618
+ };
619
+ var NotFoundError = class extends RustrakError {
620
+ constructor(resource) {
621
+ super(`Resource not found: ${resource}`, {
622
+ retryable: false,
623
+ statusCode: 404
624
+ });
625
+ }
626
+ };
627
+ var RateLimitError = class extends RustrakError {
628
+ /**
629
+ * Number of seconds to wait before retrying (from Retry-After header)
630
+ */
631
+ retryAfter;
632
+ constructor(message = "Rate limit exceeded", retryAfter) {
633
+ super(message, { retryable: true, statusCode: 429 });
634
+ if (retryAfter !== void 0) {
635
+ this.retryAfter = typeof retryAfter === "string" ? parseInt(retryAfter, 10) : retryAfter;
636
+ }
637
+ }
638
+ };
639
+ var ServerError = class extends RustrakError {
640
+ constructor(message, statusCode = 500) {
641
+ super(message, { retryable: true, statusCode });
642
+ }
643
+ };
644
+ var BadRequestError = class extends RustrakError {
645
+ constructor(message) {
646
+ super(message, { retryable: false, statusCode: 400 });
647
+ }
648
+ };
649
+
650
+ // src/errors/validation.ts
651
+ var ValidationError = class extends RustrakError {
652
+ /**
653
+ * Zod validation errors
654
+ */
655
+ validationErrors;
656
+ constructor(message, validationErrors) {
657
+ super(message, { retryable: false });
658
+ this.validationErrors = validationErrors;
659
+ }
660
+ /**
661
+ * Get a formatted string of validation errors
662
+ */
663
+ getValidationDetails() {
664
+ if (!this.validationErrors) {
665
+ return this.message;
666
+ }
667
+ const errors = this.validationErrors.issues.map((err) => `${err.path.map(String).join(".")}: ${err.message}`).join(", ");
668
+ return `${this.message} - ${errors}`;
669
+ }
670
+ };
671
+
672
+ // src/resources/base.ts
673
+ var BaseResource = class {
674
+ http;
675
+ constructor(http) {
676
+ this.http = http;
677
+ }
678
+ /**
679
+ * Validate API response against Zod schema
680
+ * @throws {ValidationError} if validation fails
681
+ */
682
+ validate(data, schema) {
683
+ const result = schema.safeParse(data);
684
+ if (!result.success) {
685
+ throw new ValidationError("API response validation failed", result.error);
686
+ }
687
+ return result.data;
688
+ }
689
+ };
690
+
691
+ // src/resources/agents.ts
692
+ function timeseriesSearchParams(options) {
693
+ const searchParams = {};
694
+ if (options?.period_hours) {
695
+ searchParams.period_hours = String(options.period_hours);
696
+ }
697
+ if (options?.interval_hours) {
698
+ searchParams.interval_hours = String(options.interval_hours);
699
+ }
700
+ return searchParams;
701
+ }
702
+ function breakdownSearchParams(options) {
703
+ const searchParams = {};
704
+ if (options?.period_hours) {
705
+ searchParams.period_hours = String(options.period_hours);
706
+ }
707
+ if (options?.limit) {
708
+ searchParams.limit = String(options.limit);
709
+ }
710
+ return searchParams;
711
+ }
712
+ var AgentsResource = class extends BaseResource {
713
+ /**
714
+ * Time-bucketed count of agent-run spans (`gen_ai.operation.type:agent`).
715
+ */
716
+ async getRuns(projectId, options) {
717
+ const data = await this.http.get(`api/projects/${projectId}/agents/runs`, {
718
+ searchParams: timeseriesSearchParams(options)
719
+ }).json();
720
+ return this.validate(data, z.array(agentTimeseriesPointSchema));
721
+ }
722
+ /**
723
+ * Time-bucketed avg/p95 duration for `agent`/`ai_client` spans.
724
+ */
725
+ async getDuration(projectId, options) {
726
+ const data = await this.http.get(`api/projects/${projectId}/agents/duration`, {
727
+ searchParams: timeseriesSearchParams(options)
728
+ }).json();
729
+ return this.validate(data, z.array(agentDurationPointSchema));
730
+ }
731
+ /**
732
+ * Top models by LLM call count (`gen_ai.operation.type:ai_client`).
733
+ */
734
+ async getModelsByCalls(projectId, options) {
735
+ const data = await this.http.get(`api/projects/${projectId}/agents/models/calls`, {
736
+ searchParams: breakdownSearchParams(options)
737
+ }).json();
738
+ return this.validate(data, z.array(genAiBreakdownRowSchema));
739
+ }
740
+ /**
741
+ * Top models by total tokens used (`gen_ai.operation.type:ai_client`).
742
+ */
743
+ async getModelsByTokens(projectId, options) {
744
+ const data = await this.http.get(`api/projects/${projectId}/agents/models/tokens`, {
745
+ searchParams: breakdownSearchParams(options)
746
+ }).json();
747
+ return this.validate(data, z.array(genAiBreakdownRowSchema));
748
+ }
749
+ /**
750
+ * Top tools by call count (`gen_ai.operation.type:tool`).
751
+ */
752
+ async getTools(projectId, options) {
753
+ const data = await this.http.get(`api/projects/${projectId}/agents/tools`, {
754
+ searchParams: breakdownSearchParams(options)
755
+ }).json();
756
+ return this.validate(data, z.array(genAiBreakdownRowSchema));
757
+ }
758
+ /**
759
+ * Paginated per-trace_id aggregate (duration, tokens, tool usage) across
760
+ * all AI spans sharing that trace, regardless of origin.
761
+ */
762
+ async getTraces(projectId, options) {
763
+ const searchParams = {};
764
+ if (options?.page) {
765
+ searchParams.page = String(options.page);
766
+ }
767
+ if (options?.per_page) {
768
+ searchParams.per_page = String(options.per_page);
769
+ }
770
+ const data = await this.http.get(`api/projects/${projectId}/agents/traces`, { searchParams }).json();
771
+ return this.validate(
772
+ data,
773
+ offsetPaginatedResponseSchema(agentTraceSummarySchema)
774
+ );
775
+ }
776
+ };
777
+ var AlertIntegrationsResource = class extends BaseResource {
778
+ /**
779
+ * List all alert integrations
780
+ */
781
+ async list() {
782
+ const data = await this.http.get("api/integrations").json();
783
+ return this.validate(data, z.array(alertIntegrationSchema));
784
+ }
785
+ /**
786
+ * Get a single alert integration by ID
787
+ */
788
+ async get(id) {
789
+ const data = await this.http.get(`api/integrations/${id}`).json();
790
+ return this.validate(data, alertIntegrationSchema);
791
+ }
792
+ /**
793
+ * Create a new alert integration
794
+ */
795
+ async create(input) {
796
+ const validatedInput = this.validate(input, createAlertIntegrationSchema);
797
+ const data = await this.http.post("api/integrations", { json: validatedInput }).json();
798
+ return this.validate(data, alertIntegrationSchema);
799
+ }
800
+ /**
801
+ * Update an existing alert integration
802
+ */
803
+ async update(id, input) {
804
+ const validatedInput = this.validate(input, updateAlertIntegrationSchema);
805
+ const data = await this.http.patch(`api/integrations/${id}`, { json: validatedInput }).json();
806
+ return this.validate(data, alertIntegrationSchema);
807
+ }
808
+ /**
809
+ * Delete an alert integration
810
+ */
811
+ async delete(id) {
812
+ await this.http.delete(`api/integrations/${id}`);
813
+ }
814
+ /**
815
+ * Send a test notification to verify integration configuration.
816
+ * For Slack bot_token integrations, routingOverride must include `channel`.
817
+ */
818
+ async test(id, routingOverride) {
819
+ const body = routingOverride !== void 0 ? this.validate(
820
+ { routing_override: routingOverride },
821
+ testIntegrationBodySchema
822
+ ) : void 0;
823
+ const data = await this.http.post(
824
+ `api/integrations/${id}/test`,
825
+ body !== void 0 ? { json: body } : void 0
826
+ ).json();
827
+ return this.validate(data, testChannelResponseSchema);
828
+ }
829
+ };
830
+ var AlertRulesResource = class extends BaseResource {
831
+ /**
832
+ * List all alert rules for a project
833
+ */
834
+ async list(projectId) {
835
+ const data = await this.http.get(`api/projects/${projectId}/alert-rules`).json();
836
+ return this.validate(data, z.array(alertRuleSchema));
837
+ }
838
+ /**
839
+ * Get a single alert rule by ID
840
+ */
841
+ async get(projectId, ruleId) {
842
+ const data = await this.http.get(`api/projects/${projectId}/alert-rules/${ruleId}`).json();
843
+ return this.validate(data, alertRuleSchema);
844
+ }
845
+ /**
846
+ * Create a new alert rule for a project
847
+ */
848
+ async create(projectId, input) {
849
+ const validatedInput = this.validate(input, createAlertRuleSchema);
850
+ const data = await this.http.post(`api/projects/${projectId}/alert-rules`, { json: validatedInput }).json();
851
+ return this.validate(data, alertRuleSchema);
852
+ }
853
+ /**
854
+ * Update an existing alert rule
855
+ */
856
+ async update(projectId, ruleId, input) {
857
+ const validatedInput = this.validate(input, updateAlertRuleSchema);
858
+ const data = await this.http.patch(`api/projects/${projectId}/alert-rules/${ruleId}`, {
859
+ json: validatedInput
860
+ }).json();
861
+ return this.validate(data, alertRuleSchema);
862
+ }
863
+ /**
864
+ * Delete an alert rule
865
+ */
866
+ async delete(projectId, ruleId) {
867
+ await this.http.delete(`api/projects/${projectId}/alert-rules/${ruleId}`);
868
+ }
869
+ /**
870
+ * List alert history for a project
871
+ */
872
+ async listHistory(projectId, options) {
873
+ const searchParams = new URLSearchParams();
874
+ if (options?.limit !== void 0) {
875
+ searchParams.set("limit", options.limit.toString());
876
+ }
877
+ const query = searchParams.toString();
878
+ const url = query ? `api/projects/${projectId}/alert-history?${query}` : `api/projects/${projectId}/alert-history`;
879
+ const data = await this.http.get(url).json();
880
+ return this.validate(data, z.array(alertHistorySchema));
881
+ }
882
+ };
883
+
884
+ // src/resources/auth.ts
885
+ var AuthResource = class extends BaseResource {
886
+ /**
887
+ * Register a new user account
888
+ * Creates a new user and automatically logs them in (sets session cookie)
889
+ * @param credentials - Email and password for the new account
890
+ * @returns LoginResult with user information and session cookies
891
+ */
892
+ async register(credentials) {
893
+ const validatedInput = this.validate(credentials, registerRequestSchema);
894
+ const response = await this.http.post("auth/register", {
895
+ json: validatedInput
896
+ });
897
+ const cookies = response.headers.getSetCookie();
898
+ const data = await response.json();
899
+ const authResponse = this.validate(data, authResponseSchema);
900
+ return {
901
+ user: authResponse.user,
902
+ cookies
903
+ };
904
+ }
905
+ /**
906
+ * Login with email and password
907
+ * Authenticates the user and sets a session cookie
908
+ * @param credentials - Email and password
909
+ * @returns LoginResult with user information and session cookies
910
+ */
911
+ async login(credentials) {
912
+ const validatedInput = this.validate(credentials, loginRequestSchema);
913
+ const response = await this.http.post("auth/login", {
914
+ json: validatedInput
915
+ });
916
+ const cookies = response.headers.getSetCookie();
917
+ const data = await response.json();
918
+ const authResponse = this.validate(data, authResponseSchema);
919
+ return {
920
+ user: authResponse.user,
921
+ cookies
922
+ };
923
+ }
924
+ /**
925
+ * Logout the current user
926
+ * Clears the session cookie
927
+ * @returns Array of Set-Cookie headers (typically clearing cookies)
928
+ */
929
+ async logout() {
930
+ const response = await this.http.post("auth/logout");
931
+ return response.headers.getSetCookie();
932
+ }
933
+ /**
934
+ * Get current authenticated user
935
+ * Requires a valid session cookie
936
+ * @returns User information
937
+ */
938
+ async getCurrentUser() {
939
+ const data = await this.http.get("auth/me").json();
940
+ return this.validate(data, userSchema);
941
+ }
942
+ /**
943
+ * Get the details of a pending invitation by its token (public endpoint)
944
+ * Used by the accept-invitation page before the user has an account
945
+ * @param token - Invitation token
946
+ * @returns Invitation info (email, role, status, expiry)
947
+ */
948
+ async getInvitation(token) {
949
+ const data = await this.http.get(`auth/invitation/${token}`).json();
950
+ return this.validate(data, invitationInfoSchema);
951
+ }
952
+ /**
953
+ * Accept a pending invitation, creating the user account and logging in
954
+ * @param input - Invitation token and the new account's password
955
+ * @returns LoginResult with user information and session cookies
956
+ */
957
+ async acceptInvitation(input) {
958
+ const validatedInput = this.validate(input, acceptInvitationSchema);
959
+ const response = await this.http.post("auth/accept-invitation", {
960
+ json: validatedInput
961
+ });
962
+ const cookies = response.headers.getSetCookie();
963
+ const data = await response.json();
964
+ const authResponse = this.validate(data, authResponseSchema);
965
+ return {
966
+ user: authResponse.user,
967
+ cookies
968
+ };
969
+ }
970
+ };
851
971
 
852
972
  // src/resources/events.ts
853
973
  var EventsResource = class extends BaseResource {
@@ -1079,17 +1199,6 @@ var IssuesResource = class extends BaseResource {
1079
1199
  }).json();
1080
1200
  return this.validate(data, userReportSchema);
1081
1201
  }
1082
- /**
1083
- * Record a deploy of a release, finalizing resolve-in-next-release issues.
1084
- */
1085
- async createDeploy(projectId, input) {
1086
- const validatedInput = this.validate(input, createDeploySchema);
1087
- const data = await this.http.post(`api/projects/${projectId}/deploys`, { json: validatedInput }).json();
1088
- return this.validate(
1089
- data,
1090
- z.object({ version: z.string(), finalized: z.number().int() })
1091
- );
1092
- }
1093
1202
  };
1094
1203
 
1095
1204
  // src/resources/logs.ts
@@ -1324,6 +1433,37 @@ var SourceMapsResource = class extends BaseResource {
1324
1433
  return this.validate(data, listSourceMapsResponseSchema);
1325
1434
  }
1326
1435
  };
1436
+
1437
+ // src/resources/spans.ts
1438
+ var SpansResource = class extends BaseResource {
1439
+ /**
1440
+ * List spans for a project with offset-based pagination (newest first),
1441
+ * optionally filtered by op/status/trace_id/operation_type.
1442
+ */
1443
+ async list(projectId, options) {
1444
+ const searchParams = {};
1445
+ if (options?.page) {
1446
+ searchParams.page = String(options.page);
1447
+ }
1448
+ if (options?.per_page) {
1449
+ searchParams.per_page = String(options.per_page);
1450
+ }
1451
+ if (options?.op) {
1452
+ searchParams.op = options.op;
1453
+ }
1454
+ if (options?.status) {
1455
+ searchParams.status = options.status;
1456
+ }
1457
+ if (options?.trace_id) {
1458
+ searchParams.trace_id = options.trace_id;
1459
+ }
1460
+ if (options?.operation_type) {
1461
+ searchParams.operation_type = options.operation_type;
1462
+ }
1463
+ const data = await this.http.get(`api/projects/${projectId}/spans`, { searchParams }).json();
1464
+ return this.validate(data, offsetPaginatedResponseSchema(spanSchema));
1465
+ }
1466
+ };
1327
1467
  var StorageResource = class extends BaseResource {
1328
1468
  /**
1329
1469
  * Get the instance-wide storage summary: row counts per data category, the
@@ -1652,6 +1792,14 @@ var RustrakClient = class {
1652
1792
  * Logs API resource (standalone logs)
1653
1793
  */
1654
1794
  logs;
1795
+ /**
1796
+ * Spans API resource (standalone + transaction-embedded spans, shared table)
1797
+ */
1798
+ spans;
1799
+ /**
1800
+ * AI Agent Monitoring dashboard API resource
1801
+ */
1802
+ agents;
1655
1803
  /**
1656
1804
  * Storage API resource (usage + retention cleanup, admin only)
1657
1805
  */
@@ -1682,6 +1830,8 @@ var RustrakClient = class {
1682
1830
  this.releases = new ReleasesResource(this.http);
1683
1831
  this.transactions = new TransactionsResource(this.http);
1684
1832
  this.logs = new LogsResource(this.http);
1833
+ this.spans = new SpansResource(this.http);
1834
+ this.agents = new AgentsResource(this.http);
1685
1835
  this.storage = new StorageResource(this.http);
1686
1836
  this.health = new HealthResource(this.http);
1687
1837
  }