pinpointmcp 0.1.1 → 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.
Files changed (55) hide show
  1. package/README.md +316 -7
  2. package/dist/client-holder.d.ts +4 -1
  3. package/dist/client-holder.js +12 -1
  4. package/dist/client.d.ts +20 -1
  5. package/dist/client.js +180 -13
  6. package/dist/config-store.d.ts +1 -0
  7. package/dist/config.d.ts +1 -0
  8. package/dist/config.js +3 -0
  9. package/dist/index.js +26 -4
  10. package/dist/prompts/index.d.ts +1 -0
  11. package/dist/prompts/index.js +1 -0
  12. package/dist/prompts/review-request.d.ts +3 -0
  13. package/dist/prompts/review-request.js +38 -0
  14. package/dist/resources/bugs.js +1 -1
  15. package/dist/resources/index.d.ts +2 -0
  16. package/dist/resources/index.js +2 -0
  17. package/dist/resources/projects.d.ts +4 -0
  18. package/dist/resources/projects.js +46 -0
  19. package/dist/resources/requests.d.ts +3 -0
  20. package/dist/resources/requests.js +22 -0
  21. package/dist/tools/add-environment.d.ts +3 -0
  22. package/dist/tools/add-environment.js +31 -0
  23. package/dist/tools/configure.js +8 -4
  24. package/dist/tools/create-project.d.ts +3 -0
  25. package/dist/tools/create-project.js +62 -0
  26. package/dist/tools/create-request.d.ts +3 -0
  27. package/dist/tools/create-request.js +47 -0
  28. package/dist/tools/delete-project.d.ts +3 -0
  29. package/dist/tools/delete-project.js +20 -0
  30. package/dist/tools/download-report.d.ts +3 -0
  31. package/dist/tools/download-report.js +19 -0
  32. package/dist/tools/get-report.d.ts +3 -0
  33. package/dist/tools/get-report.js +32 -0
  34. package/dist/tools/get-request.d.ts +3 -0
  35. package/dist/tools/get-request.js +31 -0
  36. package/dist/tools/index.d.ts +14 -0
  37. package/dist/tools/index.js +14 -0
  38. package/dist/tools/list-bugs.js +25 -3
  39. package/dist/tools/list-dispatch-reports.d.ts +3 -0
  40. package/dist/tools/list-dispatch-reports.js +23 -0
  41. package/dist/tools/list-environments.d.ts +3 -0
  42. package/dist/tools/list-environments.js +27 -0
  43. package/dist/tools/list-projects.d.ts +3 -0
  44. package/dist/tools/list-projects.js +26 -0
  45. package/dist/tools/list-requests.d.ts +3 -0
  46. package/dist/tools/list-requests.js +35 -0
  47. package/dist/tools/remove-environment.d.ts +3 -0
  48. package/dist/tools/remove-environment.js +21 -0
  49. package/dist/tools/update-environment.d.ts +3 -0
  50. package/dist/tools/update-environment.js +37 -0
  51. package/dist/tools/update-project.d.ts +3 -0
  52. package/dist/tools/update-project.js +36 -0
  53. package/dist/types.d.ts +117 -0
  54. package/dist/types.js +26 -0
  55. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Pinpoint MCP Server
2
2
 
3
- MCP server for the [Pinpoint](https://testwithpinpoint.com) bug tracking platform. Enables AI agents in Claude Code, Cursor, and other MCP-compatible environments to list bugs, inspect details, update status, and autonomously resolve reported issues.
3
+ MCP server for the [Pinpoint](https://testwithpinpoint.com) testing and bug tracking platform. Enables AI agents in Claude Code, Cursor, and other MCP-compatible environments to manage projects, environments, test requests, bug reports, and autonomously resolve reported issues.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -98,6 +98,75 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
98
98
  }
99
99
  ```
100
100
 
101
+ ## Tech Stack
102
+
103
+ - **Runtime:** Node.js >= 18
104
+ - **Language:** TypeScript 5.9+
105
+ - **MCP SDK:** @modelcontextprotocol/sdk 1.27+
106
+ - **Validation:** Zod 4.3+
107
+ - **Testing:** Vitest 4.0+
108
+ - **Build:** TypeScript compiler (tsc)
109
+
110
+ ## Project Structure
111
+
112
+ ```
113
+ src/
114
+ ├── index.ts # Main server entry point
115
+ ├── client.ts # Pinpoint API client
116
+ ├── client-holder.ts # Client lifecycle management
117
+ ├── config.ts # Configuration loading
118
+ ├── config-store.ts # Persistent config storage
119
+ ├── types.ts # Shared TypeScript types
120
+ ├── tools/ # MCP tool implementations
121
+ │ ├── configure.ts # Runtime configuration
122
+ │ ├── list-bugs.ts # Bug listing
123
+ │ ├── get-bug.ts # Bug details
124
+ │ ├── update-bug-status.ts # Bug status updates
125
+ │ ├── list-projects.ts # Project listing
126
+ │ ├── create-project.ts # Project creation
127
+ │ ├── update-project.ts # Project updates
128
+ │ ├── delete-project.ts # Project deletion
129
+ │ ├── list-environments.ts # Environment listing
130
+ │ ├── add-environment.ts # Environment creation
131
+ │ ├── update-environment.ts# Environment updates
132
+ │ ├── remove-environment.ts# Environment deletion
133
+ │ ├── list-requests.ts # Test request listing
134
+ │ ├── create-request.ts # Test request creation
135
+ │ ├── get-request.ts # Test request details
136
+ │ ├── get-report.ts # Report details
137
+ │ ├── download-report.ts # Report download URLs
138
+ │ └── list-dispatch-reports.ts # Reports for a dispatch
139
+ ├── resources/ # MCP resource implementations
140
+ │ ├── bugs.ts # Bug resources
141
+ │ ├── projects.ts # Project resources
142
+ │ └── requests.ts # Request resources
143
+ └── prompts/ # MCP prompt templates
144
+ ├── solve-bug.ts # Bug solving workflow
145
+ └── review-request.ts # Test request review
146
+ ```
147
+
148
+ ## Build and Run
149
+
150
+ ```bash
151
+ # Install dependencies
152
+ npm install
153
+
154
+ # Build TypeScript to JavaScript
155
+ npm run build
156
+
157
+ # Run the server (after building)
158
+ npm start
159
+
160
+ # Run tests
161
+ npm test
162
+
163
+ # Run tests in watch mode
164
+ npm run test:watch
165
+
166
+ # Development mode (watch for changes)
167
+ npm run dev
168
+ ```
169
+
101
170
  ## Tools
102
171
 
103
172
  ### configure
@@ -115,18 +184,21 @@ Configure the server with an API token at runtime. Validates the token before pe
115
184
  - On validation failure: returns an error without persisting
116
185
  - On write failure: configures the current session and warns about persistence
117
186
 
118
- ### list_bugs
187
+ ### Bug Management
188
+
189
+ #### list_bugs
119
190
 
120
191
  List bug reports filtered by status and project.
121
192
 
122
193
  | Parameter | Type | Required | Default | Description |
123
194
  |-----------|------|----------|---------|-------------|
124
- | `status` | string | No | `"open"` | Filter: `open`, `in_progress`, `resolved`, `closed` |
195
+ | `status` | string | No | all non-closed | Filter: `open`, `in_progress`, `resolved`, `closed`. Omit to see all active bugs. Supports comma-separated values (e.g., `"open,in_progress"`) |
125
196
  | `project` | string | No | n/a | Filter by project name |
126
- | `page` | number | No | `0` | Page number (0-indexed) |
197
+ | `cursor` | string | No | n/a | Cursor token from a previous response for efficient pagination through large lists |
198
+ | `page` | number | No | `0` | Page number (0-indexed). Ignored when `cursor` is provided |
127
199
  | `size` | number | No | `20` | Page size (max 200) |
128
200
 
129
- ### get_bug
201
+ #### get_bug
130
202
 
131
203
  Get detailed information about a specific bug report, including description, reproduction steps, expected/actual behavior, and environment.
132
204
 
@@ -134,7 +206,7 @@ Get detailed information about a specific bug report, including description, rep
134
206
  |-----------|------|----------|-------------|
135
207
  | `id` | string | Yes | Bug report UUID |
136
208
 
137
- ### update_bug_status
209
+ #### update_bug_status
138
210
 
139
211
  Update the status of a bug report.
140
212
 
@@ -144,15 +216,236 @@ Update the status of a bug report.
144
216
  | `status` | enum | Yes | New status: `open`, `in_progress`, `resolved`, `closed` |
145
217
  | `resolution` | string | No | Resolution notes (recommended when resolving) |
146
218
 
219
+ #### Bug Workflow
220
+
221
+ These examples show how to combine the bug management tools into a practical workflow for tracking and resolving bugs before they reach production.
222
+
223
+ ##### See all active bugs
224
+
225
+ Call `list_bugs` with no `status` parameter to retrieve every bug that is not closed. This returns all OPEN, IN_PROGRESS, and RESOLVED bugs in a single request, giving you a complete picture of outstanding work.
226
+
227
+ ```json
228
+ { "project": "my-app" }
229
+ ```
230
+
231
+ ##### Filter by project
232
+
233
+ When working on a specific codebase, pass the `project` parameter to narrow results to bugs relevant to that project.
234
+
235
+ ```json
236
+ { "project": "checkout-service" }
237
+ ```
238
+
239
+ This focuses your view so you can address bugs in the code you are actively changing.
240
+
241
+ ##### Triage with multi-status filtering
242
+
243
+ Use comma-separated status values to see only bugs that still need attention. For example, filtering to `"open,in_progress"` excludes resolved bugs so you can focus on what remains.
244
+
245
+ ```json
246
+ { "status": "open,in_progress", "project": "checkout-service" }
247
+ ```
248
+
249
+ ##### Investigate and fix a bug
250
+
251
+ Once you identify a bug to work on, use the full lifecycle:
252
+
253
+ 1. **List bugs** to find candidates:
254
+ ```json
255
+ list_bugs { "status": "open", "project": "checkout-service" }
256
+ ```
257
+
258
+ 2. **Get details** to understand the issue, including reproduction steps and expected behavior:
259
+ ```json
260
+ get_bug { "id": "bug-uuid-here" }
261
+ ```
262
+
263
+ 3. **Mark as in progress** to signal you are actively working on it:
264
+ ```json
265
+ update_bug_status { "id": "bug-uuid-here", "status": "in_progress" }
266
+ ```
267
+
268
+ 4. **Fix the code** in your editor or through your AI agent.
269
+
270
+ 5. **Mark as resolved** with notes describing what changed:
271
+ ```json
272
+ update_bug_status { "id": "bug-uuid-here", "status": "resolved", "resolution": "Fixed null check in payment validation; added unit test" }
273
+ ```
274
+
275
+ ##### Paginate large bug lists with cursor
276
+
277
+ For projects with many bugs, use cursor-based pagination to walk through results efficiently. The response includes `hasMore` and `nextCursor` fields when additional pages exist.
278
+
279
+ First request:
280
+ ```json
281
+ list_bugs { "project": "large-project", "size": 50 }
282
+ ```
283
+
284
+ If the response contains `"hasMore": true` and a `"nextCursor"` value, pass that cursor to fetch the next page:
285
+ ```json
286
+ list_bugs { "project": "large-project", "size": 50, "cursor": "returned-cursor-token" }
287
+ ```
288
+
289
+ Continue until `hasMore` is `false`. When a `cursor` is provided, the `page` parameter is ignored, so you do not need to track page numbers manually.
290
+
291
+ ### Project Management
292
+
293
+ #### list_projects
294
+
295
+ List all projects for your organization.
296
+
297
+ | Parameter | Type | Required | Default | Description |
298
+ |-----------|------|----------|---------|-------------|
299
+ | `page` | number | No | `0` | Page number (0-indexed) |
300
+ | `size` | number | No | `20` | Page size (max 200) |
301
+
302
+ #### create_project
303
+
304
+ Create a new project in your organization.
305
+
306
+ | Parameter | Type | Required | Description |
307
+ |-----------|------|----------|-------------|
308
+ | `name` | string | Yes | Project name |
309
+ | `description` | string | No | Project description |
310
+ | `type` | string | No | Project type (UI, API, CLI, MCP) |
311
+
312
+ #### update_project
313
+
314
+ Update a project's name, description, or type.
315
+
316
+ | Parameter | Type | Required | Description |
317
+ |-----------|------|----------|-------------|
318
+ | `projectId` | string | Yes | Project UUID |
319
+ | `name` | string | No | New project name |
320
+ | `description` | string | No | New project description |
321
+ | `type` | string | No | New project type |
322
+
323
+ #### delete_project
324
+
325
+ Delete a project by ID.
326
+
327
+ | Parameter | Type | Required | Description |
328
+ |-----------|------|----------|-------------|
329
+ | `id` | string | Yes | Project UUID |
330
+
331
+ ### Environment Management
332
+
333
+ #### list_environments
334
+
335
+ List environments for a project.
336
+
337
+ | Parameter | Type | Required | Description |
338
+ |-----------|------|----------|-------------|
339
+ | `projectId` | string | Yes | Project UUID |
340
+
341
+ #### add_environment
342
+
343
+ Add a new environment to a project.
344
+
345
+ | Parameter | Type | Required | Description |
346
+ |-----------|------|----------|-------------|
347
+ | `projectId` | string | Yes | Project UUID |
348
+ | `name` | string | Yes | Environment name (e.g., staging, production) |
349
+ | `baseUrl` | string | Yes | Base URL for the environment |
350
+ | `isDefault` | boolean | No | Whether this is the default environment |
351
+
352
+ #### update_environment
353
+
354
+ Update an environment's configuration.
355
+
356
+ | Parameter | Type | Required | Description |
357
+ |-----------|------|----------|-------------|
358
+ | `projectId` | string | Yes | Project UUID |
359
+ | `environmentId` | string | Yes | Environment UUID to update |
360
+ | `name` | string | No | New environment name |
361
+ | `baseUrl` | string | No | New base URL |
362
+ | `isDefault` | boolean | No | Set as the default environment |
363
+
364
+ #### remove_environment
365
+
366
+ Remove an environment from a project.
367
+
368
+ | Parameter | Type | Required | Description |
369
+ |-----------|------|----------|-------------|
370
+ | `projectId` | string | Yes | Project UUID |
371
+ | `environmentId` | string | Yes | Environment UUID to remove |
372
+
373
+ ### Test Request Management
374
+
375
+ #### list_requests
376
+
377
+ List test requests for your account.
378
+
379
+ | Parameter | Type | Required | Default | Description |
380
+ |-----------|------|----------|---------|-------------|
381
+ | `page` | number | No | `0` | Page number (0-indexed) |
382
+ | `size` | number | No | `20` | Page size (max 200) |
383
+
384
+ #### create_request
385
+
386
+ Create a new manual test request (dispatch).
387
+
388
+ | Parameter | Type | Required | Description |
389
+ |-----------|------|----------|-------------|
390
+ | `projectId` | string | Yes | Project UUID to dispatch tests for |
391
+ | `environment` | string | No | Target environment (e.g., staging, production) |
392
+ | `buildUrl` | string | No | CI/CD build URL |
393
+ | `commitSha` | string | No | Git commit SHA |
394
+ | `branch` | string | No | Git branch name |
395
+ | `triggeredBy` | string | No | Who triggered this request |
396
+
397
+ #### get_request
398
+
399
+ Get detailed information about a specific dispatch.
400
+
401
+ | Parameter | Type | Required | Description |
402
+ |-----------|------|----------|-------------|
403
+ | `id` | string | Yes | Dispatch UUID |
404
+
405
+ ### Report Management
406
+
407
+ #### get_report
408
+
409
+ Get detailed information about a specific report.
410
+
411
+ | Parameter | Type | Required | Description |
412
+ |-----------|------|----------|-------------|
413
+ | `id` | string | Yes | Report UUID |
414
+
415
+ #### download_report
416
+
417
+ Get a presigned download URL for a report attachment.
418
+
419
+ | Parameter | Type | Required | Description |
420
+ |-----------|------|----------|-------------|
421
+ | `id` | string | Yes | Report UUID |
422
+
423
+ **Note:** Presigned URLs expire in 1 hour.
424
+
425
+ #### list_dispatch_reports
426
+
427
+ List all reports for a specific dispatch event.
428
+
429
+ | Parameter | Type | Required | Description |
430
+ |-----------|------|----------|-------------|
431
+ | `dispatch_id` | string | Yes | Dispatch event UUID |
432
+
147
433
  ## Resources
148
434
 
435
+ Resources provide read-only access to Pinpoint data via URIs.
436
+
149
437
  | URI | Format | Description |
150
438
  |-----|--------|-------------|
151
- | `pinpoint://bugs` | JSON | All open bugs as a JSON array |
439
+ | `pinpoint://bugs` | JSON | All non-closed bugs as a JSON array (OPEN, IN_PROGRESS, RESOLVED) |
152
440
  | `pinpoint://bugs/{id}` | Markdown | Detailed bug report rendered as Markdown |
441
+ | `pinpoint://projects` | JSON | All projects as a JSON array |
442
+ | `pinpoint://projects/{id}` | Markdown | Detailed project information rendered as Markdown |
443
+ | `pinpoint://requests/{id}` | Markdown | Detailed test request information rendered as Markdown |
153
444
 
154
445
  ## Prompts
155
446
 
447
+ Prompts provide structured workflows for common tasks.
448
+
156
449
  ### solve_bug
157
450
 
158
451
  Structured prompt for analyzing and fixing a specific bug. Assembles the title, description, reproduction steps, expected/actual behavior, and environment into a context block, then asks the agent to identify the root cause, implement a fix, and create a merge request.
@@ -161,6 +454,20 @@ Structured prompt for analyzing and fixing a specific bug. Assembles the title,
161
454
  |----------|------|----------|-------------|
162
455
  | `bug_id` | string | Yes | UUID of the bug to solve |
163
456
 
457
+ ### review_request
458
+
459
+ Analyze test request results and associated reports. Gathers all reports for a dispatch event and asks the agent to identify patterns across bugs and suggest improvements.
460
+
461
+ | Argument | Type | Required | Description |
462
+ |----------|------|----------|-------------|
463
+ | `request_id` | string | Yes | UUID of the test request to review |
464
+
465
+ ## Prerequisites
466
+
467
+ - **Node.js:** Version 18 or higher
468
+ - **Pinpoint Account:** Sign up at [testwithpinpoint.com](https://testwithpinpoint.com)
469
+ - **API Token:** Generate from the Pinpoint dashboard (Settings > API Tokens)
470
+
164
471
  ## Troubleshooting
165
472
 
166
473
  - **Server starts but tools return setup guidance:** No token is configured. Either set `PINPOINT_TOKEN`, create the dotfile, or ask the agent to call the `configure` tool.
@@ -169,3 +476,5 @@ Structured prompt for analyzing and fixing a specific bug. Assembles the title,
169
476
  - **"Authentication failed" on tool calls:** Your stored or environment token may have expired. Re-run the `configure` tool with a fresh token.
170
477
  - **Connection errors:** Check `PINPOINT_API_URL` and confirm network connectivity to the API.
171
478
  - **Server not discovered by Claude Code:** Ensure `.mcp.json` exists in the project root and that `npm run build` has been executed so `dist/index.js` is present.
479
+ - **TypeScript compilation errors:** Ensure you have TypeScript 5.9+ installed and run `npm install` to install dependencies.
480
+ - **Test failures:** Run `npm test` to execute the test suite. Ensure all dependencies are installed and the build is up to date.
@@ -1,8 +1,11 @@
1
1
  import { PinpointClient } from "./client.js";
2
2
  export declare class ClientHolder {
3
3
  private client;
4
- constructor(client?: PinpointClient | null);
4
+ private customerId;
5
+ constructor(client?: PinpointClient | null, customerId?: string | null);
5
6
  isConfigured(): boolean;
6
7
  getClient(): PinpointClient;
8
+ getCustomerId(): string;
7
9
  setClient(client: PinpointClient): void;
10
+ setCustomerId(customerId: string): void;
8
11
  }
@@ -1,7 +1,9 @@
1
1
  export class ClientHolder {
2
2
  client;
3
- constructor(client = null) {
3
+ customerId;
4
+ constructor(client = null, customerId = null) {
4
5
  this.client = client;
6
+ this.customerId = customerId;
5
7
  }
6
8
  isConfigured() {
7
9
  return this.client !== null;
@@ -12,7 +14,16 @@ export class ClientHolder {
12
14
  }
13
15
  return this.client;
14
16
  }
17
+ getCustomerId() {
18
+ if (!this.customerId) {
19
+ throw new Error("Customer ID is not available. Call the configure tool first.");
20
+ }
21
+ return this.customerId;
22
+ }
15
23
  setClient(client) {
16
24
  this.client = client;
17
25
  }
26
+ setCustomerId(customerId) {
27
+ this.customerId = customerId;
28
+ }
18
29
  }
package/dist/client.d.ts CHANGED
@@ -1,10 +1,29 @@
1
- import { BugReport, PaginatedResponse, ListBugsOptions } from "./types.js";
1
+ import { BugReport, PaginatedResponse, CursorPageResponse, ListBugsOptions, Project, TestRequest, DispatchResponse, Report, MeResponse, CreateProjectRequest, UpdateProjectRequest, ManualDispatchRequest, Environment, CreateEnvironmentRequest, UpdateEnvironmentRequest } from "./types.js";
2
2
  export declare class PinpointClient {
3
3
  private baseUrl;
4
4
  private token;
5
5
  constructor(baseUrl: string, token: string);
6
6
  listBugs(options?: ListBugsOptions): Promise<PaginatedResponse<BugReport>>;
7
+ listBugsWithCursor(options?: ListBugsOptions): Promise<CursorPageResponse<BugReport>>;
7
8
  getBug(id: string): Promise<BugReport>;
8
9
  updateBugStatus(id: string, status: string, resolution?: string): Promise<BugReport>;
10
+ listProjects(customerId: string, page?: number, size?: number): Promise<PaginatedResponse<Project>>;
11
+ createProject(customerId: string, request: CreateProjectRequest): Promise<Project>;
12
+ deleteProject(customerId: string, projectId: string): Promise<void>;
13
+ listRequests(customerId: string, page?: number, size?: number): Promise<PaginatedResponse<TestRequest>>;
14
+ createRequest(customerId: string, request: ManualDispatchRequest): Promise<TestRequest>;
15
+ getDispatch(dispatchId: string): Promise<DispatchResponse>;
16
+ getReport(reportId: string): Promise<Report>;
17
+ getReportDownloadUrl(reportId: string): Promise<{
18
+ url: string;
19
+ }>;
20
+ getReportsForDispatch(dispatchId: string): Promise<Report[]>;
21
+ getMe(): Promise<MeResponse>;
22
+ updateProject(customerId: string, projectId: string, request: UpdateProjectRequest): Promise<Project>;
23
+ listEnvironments(customerId: string, projectId: string): Promise<Environment[]>;
24
+ createEnvironment(customerId: string, projectId: string, request: CreateEnvironmentRequest): Promise<Environment>;
25
+ updateEnvironment(customerId: string, projectId: string, environmentId: string, request: UpdateEnvironmentRequest): Promise<Environment>;
26
+ deleteEnvironment(customerId: string, projectId: string, environmentId: string): Promise<void>;
27
+ private handleErrorResponse;
9
28
  private request;
10
29
  }
package/dist/client.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AuthenticationError, NotFoundError, ServerError, ConnectionError, } from "./types.js";
1
+ import { AuthenticationError, NotFoundError, ServerError, ConnectionError, ConflictError, BillingError, ProjectLimitError, } from "./types.js";
2
2
  export class PinpointClient {
3
3
  baseUrl;
4
4
  token;
@@ -8,13 +8,25 @@ export class PinpointClient {
8
8
  }
9
9
  async listBugs(options) {
10
10
  const params = new URLSearchParams();
11
- params.set("status", options?.status ?? "open");
11
+ if (options?.status)
12
+ params.set("status", options.status);
12
13
  if (options?.project)
13
14
  params.set("project", options.project);
14
15
  params.set("page", String(options?.page ?? 0));
15
16
  params.set("size", String(options?.size ?? 20));
16
17
  return this.request(`/api/v1/bugs?${params.toString()}`);
17
18
  }
19
+ async listBugsWithCursor(options) {
20
+ const params = new URLSearchParams();
21
+ if (options?.status)
22
+ params.set("status", options.status);
23
+ if (options?.project)
24
+ params.set("project", options.project);
25
+ if (options?.cursor)
26
+ params.set("cursor", options.cursor);
27
+ params.set("size", String(options?.size ?? 50));
28
+ return this.request(`/api/v1/bugs?${params.toString()}`);
29
+ }
18
30
  async getBug(id) {
19
31
  return this.request(`/api/v1/bugs/${encodeURIComponent(id)}`);
20
32
  }
@@ -29,6 +41,171 @@ export class PinpointClient {
29
41
  body: JSON.stringify(body),
30
42
  });
31
43
  }
44
+ async listProjects(customerId, page, size) {
45
+ const params = new URLSearchParams();
46
+ params.set("page", String(page ?? 0));
47
+ params.set("size", String(size ?? 20));
48
+ return this.request(`/api/v1/customers/${encodeURIComponent(customerId)}/projects?${params.toString()}`);
49
+ }
50
+ async createProject(customerId, request) {
51
+ const url = `${this.baseUrl}/api/v1/customers/${encodeURIComponent(customerId)}/projects`;
52
+ let response;
53
+ try {
54
+ response = await fetch(url, {
55
+ method: "POST",
56
+ headers: {
57
+ Authorization: `Bearer ${this.token}`,
58
+ Accept: "application/json",
59
+ "Content-Type": "application/json",
60
+ },
61
+ body: JSON.stringify(request),
62
+ });
63
+ }
64
+ catch {
65
+ throw new ConnectionError(this.baseUrl);
66
+ }
67
+ if (!response.ok) {
68
+ if (response.status === 402) {
69
+ try {
70
+ const body = await response.json();
71
+ throw new BillingError(String(body.message ?? "Billing confirmation required"), Number(body.priceCents ?? 0), String(body.tierName ?? "unknown"), Number(body.includedProjects ?? 0), Number(body.currentCount ?? 0));
72
+ }
73
+ catch (e) {
74
+ if (e instanceof BillingError)
75
+ throw e;
76
+ throw new BillingError("Billing confirmation required", 0, "unknown", 0, 0);
77
+ }
78
+ }
79
+ if (response.status === 403) {
80
+ try {
81
+ const body = await response.json();
82
+ throw new ProjectLimitError(String(body.message ?? "Project limit exceeded"));
83
+ }
84
+ catch (e) {
85
+ if (e instanceof ProjectLimitError)
86
+ throw e;
87
+ throw new ProjectLimitError("Project limit exceeded");
88
+ }
89
+ }
90
+ this.handleErrorResponse(response);
91
+ }
92
+ return response.json();
93
+ }
94
+ async deleteProject(customerId, projectId) {
95
+ const url = `${this.baseUrl}/api/v1/customers/${encodeURIComponent(customerId)}/projects/${encodeURIComponent(projectId)}`;
96
+ let response;
97
+ try {
98
+ response = await fetch(url, {
99
+ method: "DELETE",
100
+ headers: {
101
+ Authorization: `Bearer ${this.token}`,
102
+ Accept: "application/json",
103
+ },
104
+ });
105
+ }
106
+ catch {
107
+ throw new ConnectionError(this.baseUrl);
108
+ }
109
+ if (!response.ok && response.status !== 204) {
110
+ this.handleErrorResponse(response);
111
+ }
112
+ }
113
+ async listRequests(customerId, page, size) {
114
+ const params = new URLSearchParams();
115
+ params.set("page", String(page ?? 0));
116
+ params.set("size", String(size ?? 20));
117
+ return this.request(`/api/v1/customers/${encodeURIComponent(customerId)}/requests?${params.toString()}`);
118
+ }
119
+ async createRequest(customerId, request) {
120
+ const url = `${this.baseUrl}/api/v1/customers/${encodeURIComponent(customerId)}/requests`;
121
+ let response;
122
+ try {
123
+ response = await fetch(url, {
124
+ method: "POST",
125
+ headers: {
126
+ Authorization: `Bearer ${this.token}`,
127
+ Accept: "application/json",
128
+ "Content-Type": "application/json",
129
+ },
130
+ body: JSON.stringify(request),
131
+ });
132
+ }
133
+ catch {
134
+ throw new ConnectionError(this.baseUrl);
135
+ }
136
+ if (!response.ok) {
137
+ if (response.status === 409) {
138
+ try {
139
+ const body = await response.json();
140
+ throw new ConflictError(String(body.message ?? "A dispatch is already in progress for this project"));
141
+ }
142
+ catch (e) {
143
+ if (e instanceof ConflictError)
144
+ throw e;
145
+ throw new ConflictError("A dispatch is already in progress for this project");
146
+ }
147
+ }
148
+ this.handleErrorResponse(response);
149
+ }
150
+ return response.json();
151
+ }
152
+ async getDispatch(dispatchId) {
153
+ return this.request(`/api/v1/dispatch/${encodeURIComponent(dispatchId)}`);
154
+ }
155
+ async getReport(reportId) {
156
+ return this.request(`/api/v1/bug-reports/${encodeURIComponent(reportId)}`);
157
+ }
158
+ async getReportDownloadUrl(reportId) {
159
+ return this.request(`/api/v1/bug-reports/${encodeURIComponent(reportId)}/download`);
160
+ }
161
+ async getReportsForDispatch(dispatchId) {
162
+ return this.request(`/api/v1/dispatch/${encodeURIComponent(dispatchId)}/reports`);
163
+ }
164
+ async getMe() {
165
+ return this.request("/api/v1/me");
166
+ }
167
+ async updateProject(customerId, projectId, request) {
168
+ return this.request(`/api/v1/customers/${encodeURIComponent(customerId)}/projects/${encodeURIComponent(projectId)}`, {
169
+ method: "PUT",
170
+ headers: { "Content-Type": "application/json" },
171
+ body: JSON.stringify(request),
172
+ });
173
+ }
174
+ async listEnvironments(customerId, projectId) {
175
+ return this.request(`/api/v1/customers/${encodeURIComponent(customerId)}/projects/${encodeURIComponent(projectId)}/environments`);
176
+ }
177
+ async createEnvironment(customerId, projectId, request) {
178
+ return this.request(`/api/v1/customers/${encodeURIComponent(customerId)}/projects/${encodeURIComponent(projectId)}/environments`, {
179
+ method: "POST",
180
+ headers: { "Content-Type": "application/json" },
181
+ body: JSON.stringify(request),
182
+ });
183
+ }
184
+ async updateEnvironment(customerId, projectId, environmentId, request) {
185
+ return this.request(`/api/v1/customers/${encodeURIComponent(customerId)}/projects/${encodeURIComponent(projectId)}/environments/${encodeURIComponent(environmentId)}`, {
186
+ method: "PUT",
187
+ headers: { "Content-Type": "application/json" },
188
+ body: JSON.stringify(request),
189
+ });
190
+ }
191
+ async deleteEnvironment(customerId, projectId, environmentId) {
192
+ await this.request(`/api/v1/customers/${encodeURIComponent(customerId)}/projects/${encodeURIComponent(projectId)}/environments/${encodeURIComponent(environmentId)}`, { method: "DELETE" });
193
+ }
194
+ handleErrorResponse(response) {
195
+ switch (response.status) {
196
+ case 401:
197
+ throw new AuthenticationError();
198
+ case 404:
199
+ throw new NotFoundError();
200
+ case 409:
201
+ throw new ConflictError(response.statusText);
202
+ default:
203
+ if (response.status >= 500) {
204
+ throw new ServerError(`Server error: ${response.status} ${response.statusText}`, response.status);
205
+ }
206
+ throw new ServerError(`Request failed: ${response.status} ${response.statusText}`, response.status);
207
+ }
208
+ }
32
209
  async request(path, init) {
33
210
  const url = `${this.baseUrl}${path}`;
34
211
  let response;
@@ -46,17 +223,7 @@ export class PinpointClient {
46
223
  throw new ConnectionError(this.baseUrl);
47
224
  }
48
225
  if (!response.ok) {
49
- switch (response.status) {
50
- case 401:
51
- throw new AuthenticationError();
52
- case 404:
53
- throw new NotFoundError();
54
- default:
55
- if (response.status >= 500) {
56
- throw new ServerError(`Server error: ${response.status} ${response.statusText}`, response.status);
57
- }
58
- throw new ServerError(`Request failed: ${response.status} ${response.statusText}`, response.status);
59
- }
226
+ this.handleErrorResponse(response);
60
227
  }
61
228
  return response.json();
62
229
  }
@@ -1,6 +1,7 @@
1
1
  export interface StoredConfig {
2
2
  token: string;
3
3
  apiUrl: string;
4
+ customerId?: string;
4
5
  }
5
6
  export declare function getConfigPath(): string;
6
7
  export declare function readStoredConfig(): Promise<StoredConfig | null>;