From 88a995e1dd4c87d7bd933635f7a814ab40f7dc90 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 04:15:31 +0000 Subject: [PATCH 1/2] Initial plan From dd98c5fb4fb34662af8bdc2acbee1d25e3609381 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 04:18:32 +0000 Subject: [PATCH 2/2] Fix API paths: remove /v1 prefix to match server endpoints Co-authored-by: sparck75 <14064405+sparck75@users.noreply.github.com> --- package-lock.json | 119 ------------------------------------------- src/client.ts | 20 ++++---- tests/client.test.ts | 72 +++++++++++++------------- 3 files changed, 46 insertions(+), 165 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3331763..664b294 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2550,14 +2550,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2699,27 +2691,6 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/babel-plugin-istanbul": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", - "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "workspaces": [ - "test/babel-8" - ], - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-instrument": "^6.0.2", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", @@ -5257,32 +5228,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-haste-map": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", - "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "anymatch": "^3.1.3", - "fb-watchman": "^2.0.2", - "graceful-fs": "^4.2.11", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "micromatch": "^4.0.8", - "walker": "^1.0.8" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.3" - } - }, "node_modules/jest-leak-detector": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", @@ -6662,41 +6607,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-worker": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", - "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*", - "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.2.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.1.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jest/node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -7554,20 +7464,6 @@ "node": ">=8" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "optional": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8172,21 +8068,6 @@ "dev": true, "license": "ISC" }, - "node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/src/client.ts b/src/client.ts index e261460..379c97c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -240,7 +240,7 @@ export class AlteriomWebhookClient { list: async (params?: EventListParams): Promise> => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.get('/api/v1/events', { params }); + const { data } = await this.http.get('/api/events', { params }); return { data: data.events, total: data.total, @@ -257,7 +257,7 @@ export class AlteriomWebhookClient { get: async (id: string): Promise => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.get(`/api/v1/events/${id}`); + const { data } = await this.http.get(`/api/events/${id}`); return data; }); }, @@ -273,7 +273,7 @@ export class AlteriomWebhookClient { list: async (params?: { page?: number; limit?: number }): Promise> => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.get('/api/v1/aggregates', { params }); + const { data } = await this.http.get('/api/aggregates', { params }); return { data: data.aggregates, total: data.total, @@ -290,7 +290,7 @@ export class AlteriomWebhookClient { get: async (id: string): Promise => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.get(`/api/v1/aggregates/${id}`); + const { data } = await this.http.get(`/api/aggregates/${id}`); return data; }); }, @@ -306,7 +306,7 @@ export class AlteriomWebhookClient { enrich: async (aggregateId: string): Promise => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data} = await this.http.post(`/api/v1/aggregates/${aggregateId}/enrich`); + const { data} = await this.http.post(`/api/aggregates/${aggregateId}/enrich`); return data; }); }, @@ -322,7 +322,7 @@ export class AlteriomWebhookClient { list: async (params?: { page?: number; limit?: number }): Promise> => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.get('/api/v1/deliveries', { params }); + const { data } = await this.http.get('/api/deliveries', { params }); return { data: data.deliveries, total: data.total, @@ -344,7 +344,7 @@ export class AlteriomWebhookClient { list: async (): Promise => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.get('/api/v1/subscribers'); + const { data } = await this.http.get('/api/subscribers'); return data; }); }, @@ -355,7 +355,7 @@ export class AlteriomWebhookClient { create: async (request: CreateSubscriberRequest): Promise => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.post('/api/v1/subscribers', request); + const { data } = await this.http.post('/api/subscribers', request); return data; }); }, @@ -366,7 +366,7 @@ export class AlteriomWebhookClient { update: async (id: string, request: UpdateSubscriberRequest): Promise => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - const { data } = await this.http.put(`/api/v1/subscribers/${id}`, request); + const { data } = await this.http.put(`/api/subscribers/${id}`, request); return data; }); }, @@ -377,7 +377,7 @@ export class AlteriomWebhookClient { delete: async (id: string): Promise => { await this.rateLimiter.acquire(); return this.retryLogic.execute(async () => { - await this.http.delete(`/api/v1/subscribers/${id}`); + await this.http.delete(`/api/subscribers/${id}`); }); }, }; diff --git a/tests/client.test.ts b/tests/client.test.ts index 32408b0..fbf371d 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -10,7 +10,7 @@ import { AlteriomWebhookClient } from '../src/client'; jest.mock('axios'); const mockedAxios = axios as jest.Mocked; -describe('AlteriomWebhookClient - Versioned Endpoints', () => { +describe('AlteriomWebhookClient - API Endpoints', () => { let client: AlteriomWebhookClient; let mockAxiosInstance: any; @@ -66,8 +66,8 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { }); }); - describe('Events API - /api/v1/events', () => { - it('should call /api/v1/events for list', async () => { + describe('Events API - /api/events', () => { + it('should call /api/events for list', async () => { mockAxiosInstance.get.mockResolvedValue({ data: { events: [], total: 0 }, }); @@ -75,19 +75,19 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.events.list(); expect(mockAxiosInstance.get).toHaveBeenCalledWith( - '/api/v1/events', + '/api/events', expect.any(Object) ); }); - it('should call /api/v1/events/{id} for get', async () => { + it('should call /api/events/{id} for get', async () => { mockAxiosInstance.get.mockResolvedValue({ data: { id: 'event-123' }, }); await client.events.get('event-123'); - expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/v1/events/event-123'); + expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/events/event-123'); }); it('should pass query parameters to list endpoint', async () => { @@ -101,7 +101,7 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { event_type: 'pull_request', }); - expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/v1/events', { + expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/events', { params: { page: 2, limit: 25, @@ -111,8 +111,8 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { }); }); - describe('Aggregates API - /api/v1/aggregates', () => { - it('should call /api/v1/aggregates for list', async () => { + describe('Aggregates API - /api/aggregates', () => { + it('should call /api/aggregates for list', async () => { mockAxiosInstance.get.mockResolvedValue({ data: { aggregates: [], total: 0 }, }); @@ -120,19 +120,19 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.aggregates.list(); expect(mockAxiosInstance.get).toHaveBeenCalledWith( - '/api/v1/aggregates', + '/api/aggregates', expect.any(Object) ); }); - it('should call /api/v1/aggregates/{id} for get', async () => { + it('should call /api/aggregates/{id} for get', async () => { mockAxiosInstance.get.mockResolvedValue({ data: { id: 'agg-123' }, }); await client.aggregates.get('agg-123'); - expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/v1/aggregates/agg-123'); + expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/aggregates/agg-123'); }); it('should pass pagination parameters to list endpoint', async () => { @@ -142,14 +142,14 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.aggregates.list({ page: 3, limit: 10 }); - expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/v1/aggregates', { + expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/aggregates', { params: { page: 3, limit: 10 }, }); }); }); - describe('Enrichment API - /api/v1/aggregates/{id}/enrich', () => { - it('should call /api/v1/aggregates/{id}/enrich for enrich', async () => { + describe('Enrichment API - /api/aggregates/{id}/enrich', () => { + it('should call /api/aggregates/{id}/enrich for enrich', async () => { mockAxiosInstance.post.mockResolvedValue({ data: { aggregate_id: 'agg-123' }, }); @@ -157,13 +157,13 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.enrichment.enrich('agg-123'); expect(mockAxiosInstance.post).toHaveBeenCalledWith( - '/api/v1/aggregates/agg-123/enrich' + '/api/aggregates/agg-123/enrich' ); }); }); - describe('Deliveries API - /api/v1/deliveries', () => { - it('should call /api/v1/deliveries for list', async () => { + describe('Deliveries API - /api/deliveries', () => { + it('should call /api/deliveries for list', async () => { mockAxiosInstance.get.mockResolvedValue({ data: { deliveries: [], total: 0 }, }); @@ -171,7 +171,7 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.deliveries.list(); expect(mockAxiosInstance.get).toHaveBeenCalledWith( - '/api/v1/deliveries', + '/api/deliveries', expect.any(Object) ); }); @@ -183,24 +183,24 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.deliveries.list({ page: 1, limit: 100 }); - expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/v1/deliveries', { + expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/deliveries', { params: { page: 1, limit: 100 }, }); }); }); - describe('Subscribers API - /api/v1/subscribers', () => { - it('should call /api/v1/subscribers for list', async () => { + describe('Subscribers API - /api/subscribers', () => { + it('should call /api/subscribers for list', async () => { mockAxiosInstance.get.mockResolvedValue({ data: [], }); await client.subscribers.list(); - expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/v1/subscribers'); + expect(mockAxiosInstance.get).toHaveBeenCalledWith('/api/subscribers'); }); - it('should call /api/v1/subscribers for create', async () => { + it('should call /api/subscribers for create', async () => { const request = { name: 'Test Subscriber', url: 'https://example.com/webhook', @@ -215,12 +215,12 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.subscribers.create(request); expect(mockAxiosInstance.post).toHaveBeenCalledWith( - '/api/v1/subscribers', + '/api/subscribers', request ); }); - it('should call /api/v1/subscribers/{id} for update', async () => { + it('should call /api/subscribers/{id} for update', async () => { const request = { url: 'https://example.com/new-webhook', events: ['push', 'pull_request'], @@ -233,22 +233,22 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { await client.subscribers.update('sub-123', request); expect(mockAxiosInstance.put).toHaveBeenCalledWith( - '/api/v1/subscribers/sub-123', + '/api/subscribers/sub-123', request ); }); - it('should call /api/v1/subscribers/{id} for delete', async () => { + it('should call /api/subscribers/{id} for delete', async () => { mockAxiosInstance.delete.mockResolvedValue({ data: null }); await client.subscribers.delete('sub-123'); - expect(mockAxiosInstance.delete).toHaveBeenCalledWith('/api/v1/subscribers/sub-123'); + expect(mockAxiosInstance.delete).toHaveBeenCalledWith('/api/subscribers/sub-123'); }); }); - describe('Endpoint Version Verification', () => { - it('should never call endpoints without v1 prefix', async () => { + describe('Endpoint Path Verification', () => { + it('should call endpoints with /api/ prefix (no version)', async () => { // Mock proper response structures mockAxiosInstance.get.mockImplementation((url: string) => { if (url.includes('/events')) { @@ -289,7 +289,7 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { const putCalls = mockAxiosInstance.put.mock.calls; const deleteCalls = mockAxiosInstance.delete.mock.calls; - // Verify all calls use /api/v1/ prefix + // Verify all calls use /api/ prefix (without version) const allCalls = [ ...getCalls.map((call: any) => call[0]), ...postCalls.map((call: any) => call[0]), @@ -297,14 +297,14 @@ describe('AlteriomWebhookClient - Versioned Endpoints', () => { ...deleteCalls.map((call: any) => call[0]), ]; - // All should start with /api/v1/ + // All should start with /api/ allCalls.forEach((path) => { - expect(path).toMatch(/^\/api\/v1\//); + expect(path).toMatch(/^\/api\//); }); - // None should be /api/ without version + // None should have version prefix allCalls.forEach((path) => { - expect(path).not.toMatch(/^\/api\/[^v]/); + expect(path).not.toMatch(/^\/api\/v\d+\//); }); }, 10000); // Increase timeout to 10 seconds due to rate limiter });