@rustrak/client 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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-channels.ts
4
+ // src/resources/alert-integrations.ts
5
5
  var paginatedResponseSchema = (itemSchema) => z.object({
6
6
  items: z.array(itemSchema),
7
7
  next_cursor: z.string().optional(),
@@ -25,7 +25,7 @@ z.object({
25
25
  });
26
26
 
27
27
  // src/schemas/alert.ts
28
- var channelTypeSchema = z.enum(["webhook", "email", "slack"]);
28
+ var providerTypeSchema = z.enum(["webhook", "email", "slack"]);
29
29
  var alertTypeSchema = z.enum(["new_issue", "regression", "unmute"]);
30
30
  var alertStatusSchema = z.enum([
31
31
  "pending",
@@ -33,11 +33,11 @@ var alertStatusSchema = z.enum([
33
33
  "failed",
34
34
  "skipped"
35
35
  ]);
36
- var notificationChannelSchema = z.object({
36
+ var alertIntegrationSchema = z.object({
37
37
  id: z.number().int(),
38
38
  name: z.string(),
39
- channel_type: channelTypeSchema,
40
- config: z.record(z.string(), z.unknown()),
39
+ provider_type: providerTypeSchema,
40
+ credentials: z.record(z.string(), z.unknown()),
41
41
  is_enabled: z.boolean(),
42
42
  failure_count: z.number().int(),
43
43
  last_failure_at: dateTimeSchema.nullable(),
@@ -46,17 +46,21 @@ var notificationChannelSchema = z.object({
46
46
  created_at: dateTimeSchema,
47
47
  updated_at: dateTimeSchema
48
48
  });
49
- var createNotificationChannelSchema = z.object({
49
+ var createAlertIntegrationSchema = z.object({
50
50
  name: z.string().min(1),
51
- channel_type: channelTypeSchema,
52
- config: z.record(z.string(), z.unknown()),
51
+ provider_type: providerTypeSchema,
52
+ credentials: z.record(z.string(), z.unknown()),
53
53
  is_enabled: z.boolean().optional()
54
54
  });
55
- var updateNotificationChannelSchema = z.object({
55
+ var updateAlertIntegrationSchema = z.object({
56
56
  name: z.string().min(1).optional(),
57
- config: z.record(z.string(), z.unknown()).optional(),
57
+ credentials: z.record(z.string(), z.unknown()).optional(),
58
58
  is_enabled: z.boolean().optional()
59
59
  });
60
+ var alertRuleChannelInputSchema = z.object({
61
+ integration_id: z.number().int(),
62
+ routing_override: z.record(z.string(), z.unknown()).default({})
63
+ });
60
64
  var alertRuleSchema = z.object({
61
65
  id: z.number().int(),
62
66
  project_id: z.number().int(),
@@ -68,12 +72,13 @@ var alertRuleSchema = z.object({
68
72
  last_triggered_at: dateTimeSchema.nullable(),
69
73
  created_at: dateTimeSchema,
70
74
  updated_at: dateTimeSchema,
71
- channel_ids: z.array(z.number().int())
75
+ channels: z.array(alertRuleChannelInputSchema).default([]),
76
+ integration_ids: z.array(z.number().int())
72
77
  });
73
78
  var createAlertRuleSchema = z.object({
74
79
  name: z.string().min(1),
75
80
  alert_type: alertTypeSchema,
76
- channel_ids: z.array(z.number().int()).min(1),
81
+ channels: z.array(alertRuleChannelInputSchema).default([]),
77
82
  is_enabled: z.boolean().optional(),
78
83
  conditions: z.record(z.string(), z.unknown()).optional(),
79
84
  cooldown_minutes: z.number().int().min(0).optional()
@@ -83,12 +88,12 @@ var updateAlertRuleSchema = z.object({
83
88
  is_enabled: z.boolean().optional(),
84
89
  conditions: z.record(z.string(), z.unknown()).optional(),
85
90
  cooldown_minutes: z.number().int().min(0).optional(),
86
- channel_ids: z.array(z.number().int()).optional()
91
+ channels: z.array(alertRuleChannelInputSchema).optional()
87
92
  });
88
93
  var alertHistorySchema = z.object({
89
94
  id: z.number().int(),
90
95
  alert_rule_id: z.number().int().nullable(),
91
- channel_id: z.number().int().nullable(),
96
+ integration_id: z.number().int().nullable(),
92
97
  issue_id: z.string().uuid().nullable(),
93
98
  project_id: z.number().int().nullable(),
94
99
  alert_type: z.string(),
@@ -107,6 +112,9 @@ var testChannelResponseSchema = z.object({
107
112
  success: z.boolean(),
108
113
  message: z.string()
109
114
  });
115
+ var testIntegrationBodySchema = z.object({
116
+ routing_override: z.record(z.string(), z.unknown()).optional()
117
+ });
110
118
 
111
119
  // src/errors/base.ts
112
120
  var RustrakError = class extends Error {
@@ -222,55 +230,57 @@ var BaseResource = class {
222
230
  }
223
231
  };
224
232
 
225
- // src/resources/alert-channels.ts
226
- var AlertChannelsResource = class extends BaseResource {
233
+ // src/resources/alert-integrations.ts
234
+ var AlertIntegrationsResource = class extends BaseResource {
227
235
  /**
228
- * List all notification channels
236
+ * List all alert integrations
229
237
  */
230
238
  async list() {
231
- const data = await this.http.get("api/alert-channels").json();
232
- return this.validate(data, z.array(notificationChannelSchema));
239
+ const data = await this.http.get("api/integrations").json();
240
+ return this.validate(data, z.array(alertIntegrationSchema));
233
241
  }
234
242
  /**
235
- * Get a single notification channel by ID
243
+ * Get a single alert integration by ID
236
244
  */
237
245
  async get(id) {
238
- const data = await this.http.get(`api/alert-channels/${id}`).json();
239
- return this.validate(data, notificationChannelSchema);
246
+ const data = await this.http.get(`api/integrations/${id}`).json();
247
+ return this.validate(data, alertIntegrationSchema);
240
248
  }
241
249
  /**
242
- * Create a new notification channel
250
+ * Create a new alert integration
243
251
  */
244
252
  async create(input) {
245
- const validatedInput = this.validate(
246
- input,
247
- createNotificationChannelSchema
248
- );
249
- const data = await this.http.post("api/alert-channels", { json: validatedInput }).json();
250
- return this.validate(data, notificationChannelSchema);
253
+ const validatedInput = this.validate(input, createAlertIntegrationSchema);
254
+ const data = await this.http.post("api/integrations", { json: validatedInput }).json();
255
+ return this.validate(data, alertIntegrationSchema);
251
256
  }
252
257
  /**
253
- * Update an existing notification channel
258
+ * Update an existing alert integration
254
259
  */
255
260
  async update(id, input) {
256
- const validatedInput = this.validate(
257
- input,
258
- updateNotificationChannelSchema
259
- );
260
- const data = await this.http.patch(`api/alert-channels/${id}`, { json: validatedInput }).json();
261
- return this.validate(data, notificationChannelSchema);
261
+ const validatedInput = this.validate(input, updateAlertIntegrationSchema);
262
+ const data = await this.http.patch(`api/integrations/${id}`, { json: validatedInput }).json();
263
+ return this.validate(data, alertIntegrationSchema);
262
264
  }
263
265
  /**
264
- * Delete a notification channel
266
+ * Delete an alert integration
265
267
  */
266
268
  async delete(id) {
267
- await this.http.delete(`api/alert-channels/${id}`);
269
+ await this.http.delete(`api/integrations/${id}`);
268
270
  }
269
271
  /**
270
- * Send a test notification to verify channel configuration
272
+ * Send a test notification to verify integration configuration.
273
+ * For Slack bot_token integrations, routingOverride must include `channel`.
271
274
  */
272
- async test(id) {
273
- const data = await this.http.post(`api/alert-channels/${id}/test`).json();
275
+ async test(id, routingOverride) {
276
+ const body = routingOverride !== void 0 ? this.validate(
277
+ { routing_override: routingOverride },
278
+ testIntegrationBodySchema
279
+ ) : void 0;
280
+ const data = await this.http.post(
281
+ `api/integrations/${id}/test`,
282
+ body !== void 0 ? { json: body } : void 0
283
+ ).json();
274
284
  return this.validate(data, testChannelResponseSchema);
275
285
  }
276
286
  };
@@ -327,9 +337,49 @@ var AlertRulesResource = class extends BaseResource {
327
337
  return this.validate(data, z.array(alertHistorySchema));
328
338
  }
329
339
  };
340
+ var globalRoleSchema = z.enum(["admin", "member"]);
341
+ var teamMemberSchema = z.object({
342
+ id: z.number().int(),
343
+ email: z.string().email(),
344
+ role: globalRoleSchema,
345
+ is_active: z.boolean(),
346
+ /** True for the first-registered account, which cannot be demoted or deleted. */
347
+ is_primary: z.boolean().optional(),
348
+ created_at: dateTimeSchema,
349
+ last_login: dateTimeSchema.nullable().optional()
350
+ });
351
+ var updateUserRoleSchema = z.object({
352
+ role: globalRoleSchema
353
+ });
354
+
355
+ // src/schemas/invitation.ts
356
+ var invitationStatusSchema = z.string();
357
+ var invitationSchema = z.object({
358
+ token: z.string(),
359
+ email: z.string().email(),
360
+ role: globalRoleSchema,
361
+ status: invitationStatusSchema,
362
+ expires_at: dateTimeSchema,
363
+ created_at: dateTimeSchema
364
+ });
365
+ var invitationInfoSchema = z.object({
366
+ email: z.string().email(),
367
+ role: globalRoleSchema,
368
+ status: invitationStatusSchema,
369
+ expires_at: dateTimeSchema
370
+ });
371
+ var createInvitationSchema = z.object({
372
+ email: z.string().email(),
373
+ role: globalRoleSchema
374
+ });
375
+ var acceptInvitationSchema = z.object({
376
+ token: z.string().min(1),
377
+ password: z.string().min(1)
378
+ });
330
379
  var userSchema = z.object({
331
380
  id: z.number().int().positive(),
332
381
  email: z.string().email(),
382
+ role: globalRoleSchema,
333
383
  is_admin: z.boolean()
334
384
  });
335
385
  var authResponseSchema = z.object({
@@ -341,11 +391,11 @@ z.object({
341
391
  });
342
392
  var loginRequestSchema = z.object({
343
393
  email: z.string().email(),
344
- password: z.string().min(8)
394
+ password: z.string().min(1)
345
395
  });
346
396
  var registerRequestSchema = z.object({
347
397
  email: z.string().email(),
348
- password: z.string().min(8)
398
+ password: z.string().min(1)
349
399
  });
350
400
 
351
401
  // src/resources/auth.ts
@@ -406,6 +456,34 @@ var AuthResource = class extends BaseResource {
406
456
  const data = await this.http.get("auth/me").json();
407
457
  return this.validate(data, userSchema);
408
458
  }
459
+ /**
460
+ * Get the details of a pending invitation by its token (public endpoint)
461
+ * Used by the accept-invitation page before the user has an account
462
+ * @param token - Invitation token
463
+ * @returns Invitation info (email, role, status, expiry)
464
+ */
465
+ async getInvitation(token) {
466
+ const data = await this.http.get(`auth/invitation/${token}`).json();
467
+ return this.validate(data, invitationInfoSchema);
468
+ }
469
+ /**
470
+ * Accept a pending invitation, creating the user account and logging in
471
+ * @param input - Invitation token and the new account's password
472
+ * @returns LoginResult with user information and session cookies
473
+ */
474
+ async acceptInvitation(input) {
475
+ const validatedInput = this.validate(input, acceptInvitationSchema);
476
+ const response = await this.http.post("auth/accept-invitation", {
477
+ json: validatedInput
478
+ });
479
+ const cookies = response.headers.getSetCookie();
480
+ const data = await response.json();
481
+ const authResponse = this.validate(data, authResponseSchema);
482
+ return {
483
+ user: authResponse.user,
484
+ cookies
485
+ };
486
+ }
409
487
  };
410
488
  var eventSchema = z.object({
411
489
  id: uuidSchema,
@@ -453,6 +531,17 @@ var updateIssueStateSchema = z.object({
453
531
  is_resolved: z.boolean().optional(),
454
532
  is_muted: z.boolean().optional()
455
533
  });
534
+ var projectRoleSchema = z.enum(["viewer", "editor", "admin"]);
535
+ var projectMemberSchema = z.object({
536
+ user_id: z.number().int(),
537
+ email: z.string().email(),
538
+ role: projectRoleSchema,
539
+ created_at: dateTimeSchema
540
+ });
541
+ var upsertProjectMemberSchema = z.object({
542
+ user_id: z.number().int(),
543
+ role: projectRoleSchema
544
+ });
456
545
  var projectSchema = z.object({
457
546
  id: z.number().int(),
458
547
  name: z.string(),
@@ -539,6 +628,33 @@ var EventsResource = class extends BaseResource {
539
628
  }
540
629
  };
541
630
 
631
+ // src/resources/invitations.ts
632
+ var InvitationsResource = class extends BaseResource {
633
+ /**
634
+ * Create a new invitation
635
+ * @param input - Email and global role for the invited user
636
+ */
637
+ async create(input) {
638
+ const validatedInput = this.validate(input, createInvitationSchema);
639
+ const data = await this.http.post("api/invitations", { json: validatedInput }).json();
640
+ return this.validate(data, invitationSchema);
641
+ }
642
+ /**
643
+ * List all invitations
644
+ */
645
+ async list() {
646
+ const data = await this.http.get("api/invitations").json();
647
+ return this.validate(data, invitationSchema.array());
648
+ }
649
+ /**
650
+ * Revoke a pending invitation
651
+ * @param token - Invitation token to revoke
652
+ */
653
+ async revoke(token) {
654
+ await this.http.delete(`api/invitations/${token}`);
655
+ }
656
+ };
657
+
542
658
  // src/resources/issues.ts
543
659
  var IssuesResource = class extends BaseResource {
544
660
  /**
@@ -589,6 +705,37 @@ var IssuesResource = class extends BaseResource {
589
705
  }
590
706
  };
591
707
 
708
+ // src/resources/members.ts
709
+ var MembersResource = class extends BaseResource {
710
+ /**
711
+ * List members of a project
712
+ * @param projectId - ID of the project
713
+ */
714
+ async list(projectId) {
715
+ const data = await this.http.get(`api/projects/${projectId}/members`).json();
716
+ return this.validate(data, projectMemberSchema.array());
717
+ }
718
+ /**
719
+ * Add or update a project member
720
+ * @param projectId - ID of the project
721
+ * @param input - User ID and per-project role
722
+ */
723
+ async upsert(projectId, input) {
724
+ const validatedInput = this.validate(input, upsertProjectMemberSchema);
725
+ await this.http.put(`api/projects/${projectId}/members`, {
726
+ json: validatedInput
727
+ });
728
+ }
729
+ /**
730
+ * Remove a member from a project
731
+ * @param projectId - ID of the project
732
+ * @param userId - ID of the user to remove
733
+ */
734
+ async remove(projectId, userId) {
735
+ await this.http.delete(`api/projects/${projectId}/members/${userId}`);
736
+ }
737
+ };
738
+
592
739
  // src/resources/projects.ts
593
740
  var ProjectsResource = class extends BaseResource {
594
741
  /**
@@ -693,6 +840,33 @@ var SourceMapsResource = class extends BaseResource {
693
840
  }
694
841
  };
695
842
 
843
+ // src/resources/team.ts
844
+ var TeamResource = class extends BaseResource {
845
+ /**
846
+ * List all team members (users)
847
+ */
848
+ async list() {
849
+ const data = await this.http.get("api/team").json();
850
+ return this.validate(data, teamMemberSchema.array());
851
+ }
852
+ /**
853
+ * Change a user's global role
854
+ * @param userId - ID of the user to update
855
+ * @param role - New global role to assign
856
+ */
857
+ async updateRole(userId, role) {
858
+ const body = this.validate({ role }, updateUserRoleSchema);
859
+ await this.http.patch(`api/team/${userId}/role`, { json: body });
860
+ }
861
+ /**
862
+ * Permanently remove a user from the instance.
863
+ * @param userId - ID of the user to delete
864
+ */
865
+ async remove(userId) {
866
+ await this.http.delete(`api/team/${userId}`);
867
+ }
868
+ };
869
+
696
870
  // src/resources/tokens.ts
697
871
  var TokensResource = class extends BaseResource {
698
872
  /**
@@ -813,9 +987,9 @@ var RustrakClient = class {
813
987
  */
814
988
  tokens;
815
989
  /**
816
- * Alert Channels API resource (global notification destinations)
990
+ * Alert Integrations API resource (global credential destinations)
817
991
  */
818
- alertChannels;
992
+ alertIntegrations;
819
993
  /**
820
994
  * Alert Rules API resource (per-project alert configuration)
821
995
  */
@@ -824,6 +998,18 @@ var RustrakClient = class {
824
998
  * Source Maps API resource (sentry-cli artifact bundle upload protocol)
825
999
  */
826
1000
  sourceMaps;
1001
+ /**
1002
+ * Team API resource (global user roster and roles)
1003
+ */
1004
+ team;
1005
+ /**
1006
+ * Invitations API resource (pending user invitations)
1007
+ */
1008
+ invitations;
1009
+ /**
1010
+ * Project Members API resource (per-project membership and roles)
1011
+ */
1012
+ members;
827
1013
  /**
828
1014
  * Create a new Rustrak API client
829
1015
  *
@@ -836,9 +1022,12 @@ var RustrakClient = class {
836
1022
  this.issues = new IssuesResource(this.http);
837
1023
  this.events = new EventsResource(this.http);
838
1024
  this.tokens = new TokensResource(this.http);
839
- this.alertChannels = new AlertChannelsResource(this.http);
1025
+ this.alertIntegrations = new AlertIntegrationsResource(this.http);
840
1026
  this.alertRules = new AlertRulesResource(this.http);
841
1027
  this.sourceMaps = new SourceMapsResource(this.http);
1028
+ this.team = new TeamResource(this.http);
1029
+ this.invitations = new InvitationsResource(this.http);
1030
+ this.members = new MembersResource(this.http);
842
1031
  }
843
1032
  };
844
1033