@thalorlabs/chucknorris 1.0.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/.env.example +6 -0
- package/.prettierrc +7 -0
- package/CLAUDE.md +52 -0
- package/README.md +44 -0
- package/dist/ChuckNorrisClient.d.ts +21 -0
- package/dist/ChuckNorrisClient.js +45 -0
- package/dist/ChuckNorrisTypes.d.ts +12 -0
- package/dist/ChuckNorrisTypes.js +2 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +9 -0
- package/eslint.config.mjs +21 -0
- package/package.json +46 -0
- package/src/ChuckNorrisClient.ts +50 -0
- package/src/ChuckNorrisTypes.ts +12 -0
- package/src/index.ts +9 -0
- package/tests/ChuckNorrisClient.test.ts +121 -0
- package/tsconfig.json +14 -0
package/.env.example
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# @thalorlabs/chucknorris
|
|
2
|
+
# No environment variables required — api.chucknorris.io is free and unauthenticated.
|
|
3
|
+
# This file exists for consistency with other provider packages.
|
|
4
|
+
|
|
5
|
+
# Optional: Override the API base URL (e.g. for testing with a mock server)
|
|
6
|
+
# CHUCK_NORRIS_BASE_URL=https://api.chucknorris.io
|
package/.prettierrc
ADDED
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @thalorlabs/chucknorris
|
|
2
|
+
|
|
3
|
+
## What this repo is
|
|
4
|
+
|
|
5
|
+
Provider adapter package for api.chucknorris.io. Calls one external API, normalises the response to `TLJoke`, and returns it. No DB, no cache, no logging.
|
|
6
|
+
|
|
7
|
+
## Knowledge base
|
|
8
|
+
|
|
9
|
+
Before writing any code, read:
|
|
10
|
+
- TL-Coding vault: `knowledge/multi-provider-pattern.md`
|
|
11
|
+
- TL-Coding vault: `examples/jokes/layer-provider-package.md`
|
|
12
|
+
- TL-Coding vault: `context/packages.md`
|
|
13
|
+
|
|
14
|
+
## External API
|
|
15
|
+
|
|
16
|
+
- **API:** api.chucknorris.io
|
|
17
|
+
- **Auth:** None
|
|
18
|
+
- **Billable:** No
|
|
19
|
+
- **Joke type:** Always SINGLE (one-liner)
|
|
20
|
+
- **Category:** Always GENERAL
|
|
21
|
+
|
|
22
|
+
## Build & publish
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run build # tsc → dist/
|
|
26
|
+
npm test # vitest
|
|
27
|
+
npm version patch # or minor/major
|
|
28
|
+
npm publish --access public
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Folder structure
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
src/
|
|
35
|
+
index.ts ← exports ChuckNorrisClient, CHUCK_NORRIS_CONFIG
|
|
36
|
+
ChuckNorrisClient.ts ← HTTP adapter, normalises to TLJoke
|
|
37
|
+
ChuckNorrisTypes.ts ← raw API types, local only, never exported
|
|
38
|
+
tests/
|
|
39
|
+
ChuckNorrisClient.test.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## What this package does NOT do
|
|
43
|
+
|
|
44
|
+
- No database access
|
|
45
|
+
- No caching (orchestrator handles this)
|
|
46
|
+
- No logging (orchestrator handles this)
|
|
47
|
+
- Raw types (`ChuckNorrisRawResponse`) never exported, never in `@thalorlabs/types`
|
|
48
|
+
- No provider selection logic — that's the orchestrator's job
|
|
49
|
+
|
|
50
|
+
## Migration note
|
|
51
|
+
|
|
52
|
+
When `@thalorlabs/api` is published, `ChuckNorrisClient` should extend `BaseHttpClient` instead of managing its own axios instance.
|
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @thalorlabs/chucknorris
|
|
2
|
+
|
|
3
|
+
Provider adapter for [api.chucknorris.io](https://api.chucknorris.io). Returns normalised `TLJoke` from `@thalorlabs/types`.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @thalorlabs/chucknorris
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { ChuckNorrisClient, CHUCK_NORRIS_CONFIG } from '@thalorlabs/chucknorris';
|
|
15
|
+
|
|
16
|
+
const client = new ChuckNorrisClient();
|
|
17
|
+
const joke = await client.getJoke();
|
|
18
|
+
// → TLJoke { id, type: 'SINGLE', joke: '...', category: 'GENERAL', safe: false, provider: 'chucknorris' }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
| Option | Default | Description |
|
|
24
|
+
|--------|---------|-------------|
|
|
25
|
+
| `baseURL` | `https://api.chucknorris.io` | API base URL |
|
|
26
|
+
| `timeout` | `10000` | Request timeout (ms) |
|
|
27
|
+
|
|
28
|
+
## Exported Config
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
CHUCK_NORRIS_CONFIG = {
|
|
32
|
+
cacheTtlMs: 3600000, // 1h
|
|
33
|
+
isBillable: false,
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Scripts
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm run build # tsc → dist/
|
|
41
|
+
npm test # vitest
|
|
42
|
+
npm run lint # eslint
|
|
43
|
+
npm run format:check # prettier
|
|
44
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TLJoke } from '@thalorlabs/types';
|
|
2
|
+
export interface ChuckNorrisClientConfig {
|
|
3
|
+
baseURL?: string;
|
|
4
|
+
timeout?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* HTTP adapter for api.chucknorris.io.
|
|
8
|
+
*
|
|
9
|
+
* Calls the external API and normalises the raw response to TLJoke.
|
|
10
|
+
* No DB, no cache, no logging — pure HTTP adapter.
|
|
11
|
+
*
|
|
12
|
+
* When @thalorlabs/api is available, this should extend BaseHttpClient
|
|
13
|
+
* instead of managing its own axios instance.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ChuckNorrisClient {
|
|
16
|
+
readonly serviceName = "chucknorris";
|
|
17
|
+
private readonly axiosInstance;
|
|
18
|
+
constructor(config?: ChuckNorrisClientConfig);
|
|
19
|
+
getJoke(): Promise<TLJoke>;
|
|
20
|
+
private normalise;
|
|
21
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ChuckNorrisClient = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const crypto_1 = require("crypto");
|
|
9
|
+
const types_1 = require("@thalorlabs/types");
|
|
10
|
+
/**
|
|
11
|
+
* HTTP adapter for api.chucknorris.io.
|
|
12
|
+
*
|
|
13
|
+
* Calls the external API and normalises the raw response to TLJoke.
|
|
14
|
+
* No DB, no cache, no logging — pure HTTP adapter.
|
|
15
|
+
*
|
|
16
|
+
* When @thalorlabs/api is available, this should extend BaseHttpClient
|
|
17
|
+
* instead of managing its own axios instance.
|
|
18
|
+
*/
|
|
19
|
+
class ChuckNorrisClient {
|
|
20
|
+
constructor(config = {}) {
|
|
21
|
+
this.serviceName = 'chucknorris';
|
|
22
|
+
this.axiosInstance = axios_1.default.create({
|
|
23
|
+
baseURL: config.baseURL ?? 'https://api.chucknorris.io',
|
|
24
|
+
timeout: config.timeout ?? 10000,
|
|
25
|
+
headers: {
|
|
26
|
+
Accept: 'application/json',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async getJoke() {
|
|
31
|
+
const { data } = await this.axiosInstance.get('/jokes/random');
|
|
32
|
+
return this.normalise(data);
|
|
33
|
+
}
|
|
34
|
+
normalise(raw) {
|
|
35
|
+
return types_1.TLJoke.parse({
|
|
36
|
+
id: (0, crypto_1.createHash)('md5').update(raw.value).digest('hex'),
|
|
37
|
+
type: types_1.EJokeType.SINGLE,
|
|
38
|
+
joke: raw.value,
|
|
39
|
+
category: types_1.EJokeCategory.GENERAL,
|
|
40
|
+
safe: false, // Chuck Norris jokes can contain explicit content
|
|
41
|
+
provider: this.serviceName,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.ChuckNorrisClient = ChuckNorrisClient;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw response from api.chucknorris.io.
|
|
3
|
+
*
|
|
4
|
+
* Internal to this package only — never exported from index.ts,
|
|
5
|
+
* never added to @thalorlabs/types.
|
|
6
|
+
*/
|
|
7
|
+
export interface ChuckNorrisRawResponse {
|
|
8
|
+
icon_url: string;
|
|
9
|
+
id: string;
|
|
10
|
+
url: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CHUCK_NORRIS_CONFIG = exports.ChuckNorrisClient = void 0;
|
|
4
|
+
var ChuckNorrisClient_1 = require("./ChuckNorrisClient");
|
|
5
|
+
Object.defineProperty(exports, "ChuckNorrisClient", { enumerable: true, get: function () { return ChuckNorrisClient_1.ChuckNorrisClient; } });
|
|
6
|
+
exports.CHUCK_NORRIS_CONFIG = {
|
|
7
|
+
cacheTtlMs: 1000 * 60 * 60, // 1h
|
|
8
|
+
isBillable: false, // api.chucknorris.io is free
|
|
9
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import tseslint from 'typescript-eslint';
|
|
3
|
+
import prettier from 'eslint-config-prettier';
|
|
4
|
+
import nodePlugin from 'eslint-plugin-n';
|
|
5
|
+
|
|
6
|
+
export default tseslint.config(
|
|
7
|
+
eslint.configs.recommended,
|
|
8
|
+
...tseslint.configs.recommended,
|
|
9
|
+
nodePlugin.configs['flat/recommended-module'],
|
|
10
|
+
prettier,
|
|
11
|
+
{
|
|
12
|
+
rules: {
|
|
13
|
+
'@typescript-eslint/no-explicit-any': 'error',
|
|
14
|
+
'n/no-missing-import': 'off',
|
|
15
|
+
'n/no-unpublished-import': 'off',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
ignores: ['dist/', 'node_modules/'],
|
|
20
|
+
}
|
|
21
|
+
);
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thalorlabs/chucknorris",
|
|
3
|
+
"author": "ThalorLabs",
|
|
4
|
+
"private": false,
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"description": "Provider adapter for api.chucknorris.io — returns TLJoke",
|
|
7
|
+
"homepage": "https://github.com/ThalorLabs/chucknorris#readme",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/ThalorLabs/chucknorris/issues"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/ThalorLabs/chucknorris.git"
|
|
14
|
+
},
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"main": "dist/index.js",
|
|
17
|
+
"types": "dist/index.d.ts",
|
|
18
|
+
"scripts": {
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"clean": "rimraf dist",
|
|
23
|
+
"prebuild": "npm run clean",
|
|
24
|
+
"prepublishOnly": "npm run build",
|
|
25
|
+
"lint": "eslint src/",
|
|
26
|
+
"lint:fix": "eslint src/ --fix",
|
|
27
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
28
|
+
"format:check": "prettier --check \"src/**/*.ts\""
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@eslint/js": "^10.0.1",
|
|
32
|
+
"@types/node": "^25.5.2",
|
|
33
|
+
"eslint": "^10.1.0",
|
|
34
|
+
"eslint-config-prettier": "^10.1.8",
|
|
35
|
+
"eslint-plugin-n": "^17.24.0",
|
|
36
|
+
"prettier": "^3.8.1",
|
|
37
|
+
"rimraf": "^5.0.0",
|
|
38
|
+
"typescript": "^5.0.0",
|
|
39
|
+
"typescript-eslint": "^8.58.0",
|
|
40
|
+
"vitest": "^3.0.0"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@thalorlabs/types": "^1.7.0",
|
|
44
|
+
"axios": "^1.7.0"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from 'axios';
|
|
2
|
+
import { createHash } from 'crypto';
|
|
3
|
+
import { TLJoke, EJokeType, EJokeCategory } from '@thalorlabs/types';
|
|
4
|
+
import { ChuckNorrisRawResponse } from './ChuckNorrisTypes';
|
|
5
|
+
|
|
6
|
+
export interface ChuckNorrisClientConfig {
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
timeout?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* HTTP adapter for api.chucknorris.io.
|
|
13
|
+
*
|
|
14
|
+
* Calls the external API and normalises the raw response to TLJoke.
|
|
15
|
+
* No DB, no cache, no logging — pure HTTP adapter.
|
|
16
|
+
*
|
|
17
|
+
* When @thalorlabs/api is available, this should extend BaseHttpClient
|
|
18
|
+
* instead of managing its own axios instance.
|
|
19
|
+
*/
|
|
20
|
+
export class ChuckNorrisClient {
|
|
21
|
+
public readonly serviceName = 'chucknorris';
|
|
22
|
+
private readonly axiosInstance: AxiosInstance;
|
|
23
|
+
|
|
24
|
+
constructor(config: ChuckNorrisClientConfig = {}) {
|
|
25
|
+
this.axiosInstance = axios.create({
|
|
26
|
+
baseURL: config.baseURL ?? 'https://api.chucknorris.io',
|
|
27
|
+
timeout: config.timeout ?? 10000,
|
|
28
|
+
headers: {
|
|
29
|
+
Accept: 'application/json',
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async getJoke(): Promise<TLJoke> {
|
|
35
|
+
const { data } =
|
|
36
|
+
await this.axiosInstance.get<ChuckNorrisRawResponse>('/jokes/random');
|
|
37
|
+
return this.normalise(data);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private normalise(raw: ChuckNorrisRawResponse): TLJoke {
|
|
41
|
+
return TLJoke.parse({
|
|
42
|
+
id: createHash('md5').update(raw.value).digest('hex'),
|
|
43
|
+
type: EJokeType.SINGLE,
|
|
44
|
+
joke: raw.value,
|
|
45
|
+
category: EJokeCategory.GENERAL,
|
|
46
|
+
safe: false, // Chuck Norris jokes can contain explicit content
|
|
47
|
+
provider: this.serviceName,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw response from api.chucknorris.io.
|
|
3
|
+
*
|
|
4
|
+
* Internal to this package only — never exported from index.ts,
|
|
5
|
+
* never added to @thalorlabs/types.
|
|
6
|
+
*/
|
|
7
|
+
export interface ChuckNorrisRawResponse {
|
|
8
|
+
icon_url: string;
|
|
9
|
+
id: string;
|
|
10
|
+
url: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { ChuckNorrisClient } from '../src/ChuckNorrisClient';
|
|
3
|
+
import { EJokeType, EJokeCategory } from '@thalorlabs/types';
|
|
4
|
+
import axios from 'axios';
|
|
5
|
+
|
|
6
|
+
vi.mock('axios', () => {
|
|
7
|
+
const mockAxiosInstance = {
|
|
8
|
+
get: vi.fn(),
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
default: {
|
|
12
|
+
create: vi.fn(() => mockAxiosInstance),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
function getMockAxios() {
|
|
18
|
+
const instance = (axios.create as ReturnType<typeof vi.fn>).mock.results[0]
|
|
19
|
+
.value;
|
|
20
|
+
return instance.get as ReturnType<typeof vi.fn>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('ChuckNorrisClient', () => {
|
|
24
|
+
let client: ChuckNorrisClient;
|
|
25
|
+
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
vi.clearAllMocks();
|
|
28
|
+
client = new ChuckNorrisClient();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('constructor', () => {
|
|
32
|
+
it('sets serviceName to chucknorris', () => {
|
|
33
|
+
expect(client.serviceName).toBe('chucknorris');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('creates axios instance with default config', () => {
|
|
37
|
+
expect(axios.create).toHaveBeenCalledWith({
|
|
38
|
+
baseURL: 'https://api.chucknorris.io',
|
|
39
|
+
timeout: 10000,
|
|
40
|
+
headers: { Accept: 'application/json' },
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('accepts custom baseURL and timeout', () => {
|
|
45
|
+
vi.clearAllMocks();
|
|
46
|
+
new ChuckNorrisClient({
|
|
47
|
+
baseURL: 'http://localhost:3000',
|
|
48
|
+
timeout: 5000,
|
|
49
|
+
});
|
|
50
|
+
expect(axios.create).toHaveBeenCalledWith({
|
|
51
|
+
baseURL: 'http://localhost:3000',
|
|
52
|
+
timeout: 5000,
|
|
53
|
+
headers: { Accept: 'application/json' },
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('getJoke', () => {
|
|
59
|
+
it('returns a valid TLJoke with SINGLE type and GENERAL category', async () => {
|
|
60
|
+
const mockGet = getMockAxios();
|
|
61
|
+
mockGet.mockResolvedValueOnce({
|
|
62
|
+
data: {
|
|
63
|
+
icon_url: 'https://api.chucknorris.io/img/avatar/chuck-norris.png',
|
|
64
|
+
id: 'abc123',
|
|
65
|
+
url: '',
|
|
66
|
+
value: 'Chuck Norris can divide by zero.',
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const joke = await client.getJoke();
|
|
71
|
+
|
|
72
|
+
expect(joke.type).toBe(EJokeType.SINGLE);
|
|
73
|
+
expect(joke.category).toBe(EJokeCategory.GENERAL);
|
|
74
|
+
expect(joke.joke).toBe('Chuck Norris can divide by zero.');
|
|
75
|
+
expect(joke.safe).toBe(false);
|
|
76
|
+
expect(joke.provider).toBe('chucknorris');
|
|
77
|
+
expect(joke.id).toBeDefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('generates a deterministic id from joke text', async () => {
|
|
81
|
+
const mockGet = getMockAxios();
|
|
82
|
+
const jokeText = 'Test joke';
|
|
83
|
+
mockGet.mockResolvedValue({
|
|
84
|
+
data: {
|
|
85
|
+
icon_url: 'https://example.com/icon.png',
|
|
86
|
+
id: 'raw-id',
|
|
87
|
+
url: '',
|
|
88
|
+
value: jokeText,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const joke1 = await client.getJoke();
|
|
93
|
+
const joke2 = await client.getJoke();
|
|
94
|
+
|
|
95
|
+
expect(joke1.id).toBe(joke2.id);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('calls GET /jokes/random on the API', async () => {
|
|
99
|
+
const mockGet = getMockAxios();
|
|
100
|
+
mockGet.mockResolvedValueOnce({
|
|
101
|
+
data: {
|
|
102
|
+
icon_url: '',
|
|
103
|
+
id: 'abc',
|
|
104
|
+
url: '',
|
|
105
|
+
value: 'A joke',
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
await client.getJoke();
|
|
110
|
+
|
|
111
|
+
expect(mockGet).toHaveBeenCalledWith('/jokes/random');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('propagates API errors', async () => {
|
|
115
|
+
const mockGet = getMockAxios();
|
|
116
|
+
mockGet.mockRejectedValueOnce(new Error('Network error'));
|
|
117
|
+
|
|
118
|
+
await expect(client.getJoke()).rejects.toThrow('Network error');
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"moduleResolution": "node"
|
|
11
|
+
},
|
|
12
|
+
"include": ["src"],
|
|
13
|
+
"exclude": ["node_modules", "dist"]
|
|
14
|
+
}
|