Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
parser: "@typescript-eslint/parser",
extends: ["eslint:recommended", "@typescript-eslint/recommended"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
plugins: ["@typescript-eslint"],
parserOptions: {
ecmaVersion: 2020,
Expand All @@ -19,4 +19,15 @@ module.exports = {
es6: true,
jest: true,
},
overrides: [
{
files: ["src/__tests__/**/*.ts", "src/examples/**/*.ts"],
rules: {
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"no-case-declarations": "off",
},
},
],
};
25 changes: 2 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@ name: CI

on:
push:
branches: [main]
branches: [main, dev, 'feat/**']
pull_request:
branches: [main]
branches: [main, dev]

jobs:
lint:
name: ESLint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm

- run: npm ci

- name: eslint
run: npm run lint

Expand All @@ -28,14 +25,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm

- run: npm ci

- name: tsc
run: npx tsc --noEmit

Expand All @@ -44,25 +38,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm

- run: npm ci

- name: jest
run: npm test -- --ci --forceExit

secret-scan:
name: Secret Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 5 additions & 6 deletions src/__tests__/retry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ describe('HTTPClient request headers', () => {
const client = new HTTPClient({ apiKey: 'my-api-key', baseUrl: 'http://localhost', orgId: 'o' });
await client.get('/test');

const [, options] = mockFetch.mock.calls[0];
expect((options as any).headers['X-Governs-Key']).toBe('my-api-key');
const firstCall0 = mockFetch.mock.calls[0];
const options0 = firstCall0 !== undefined ? firstCall0[1] : undefined;
expect((options0 as any).headers['X-Governs-Key']).toBe('my-api-key');
});

it('includes Content-Type application/json on POST', async () => {
Expand All @@ -129,7 +130,8 @@ describe('HTTPClient request headers', () => {
const client = new HTTPClient({ apiKey: 'k', baseUrl: 'http://localhost', orgId: 'o' });
await client.post('/test', { data: 1 });

const [, options] = mockFetch.mock.calls[0];
const firstCall1 = mockFetch.mock.calls[0];
const options = firstCall1 !== undefined ? firstCall1[1] : undefined;
expect((options as any).headers['Content-Type']).toBe('application/json');
});

Expand Down Expand Up @@ -170,9 +172,6 @@ describe('HTTPClient request headers', () => {
// ---------------------------------------------------------------------------

describe('withRetry', () => {
// Import after mocking to get the real implementation
const getWithRetry = () => require('../utils').withRetry as typeof import('../utils').withRetry;

beforeEach(() => {
jest.resetModules();
});
Expand Down
12 changes: 8 additions & 4 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ export interface RetryConfig {
export class GovernsAIError extends Error {
public readonly statusCode?: number;
public readonly response?: HTTPResponse;
public readonly retryable?: boolean;
public readonly retryable: boolean;

constructor(
message: string,
statusCode?: number,
response?: HTTPResponse,
retryable?: boolean
retryable: boolean = false
) {
super(message);
this.name = 'GovernsAIError';
if (statusCode !== undefined) this.statusCode = statusCode;
if (response !== undefined) this.response = response;
if (retryable !== undefined) this.retryable = retryable;
this.retryable = retryable;
}
}

Expand Down Expand Up @@ -388,8 +388,12 @@ export async function withRetry<T>(
}
}

if (lastError) {
throw lastError;
}

throw new GovernsAIError(
`${context} failed after ${config.maxRetries} attempts: ${lastError?.message || 'Unknown error'}`,
`${context} failed after ${config.maxRetries} attempts`,
undefined,
undefined,
false
Expand Down
6 changes: 5 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,12 @@ export async function withRetry<T>(
}
}

if (lastError) {
throw lastError;
}

throw new GovernsAIError(
`${context} failed after ${config.maxRetries} attempts: ${lastError?.message || 'Unknown error'}`,
`${context} failed after ${config.maxRetries} attempts`,
undefined,
undefined,
false
Expand Down
Loading