@backendkit-labs/http-client 0.1.1 → 0.2.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/README.md CHANGED
@@ -1,328 +1,329 @@
1
- # @backendkit-labs/http-client
2
-
3
- [![npm version](https://img.shields.io/npm/v/@backendkit-labs/http-client?style=flat-square&color=cb3837)](https://www.npmjs.com/package/@backendkit-labs/http-client)
4
- [![CI](https://img.shields.io/github/actions/workflow/status/backendkit-dev/backendkit-monorepo/ci.yml?style=flat-square&label=CI)](https://github.com/backendkit-dev/backendkit-monorepo/actions/workflows/ci.yml)
5
- [![License](https://img.shields.io/npm/l/@backendkit-labs/http-client?style=flat-square)](LICENSE)
6
- [![Node](https://img.shields.io/node/v/@backendkit-labs/http-client?style=flat-square)](package.json)
7
-
8
- > Production-grade HTTP client for Node.js — built on axios with circuit breaker, retry with exponential backoff, typed `Result<T, E>` responses, request cancellation, pre-request pipeline middleware, and optional NestJS DI integration.
9
-
10
- Every method returns `Result<HttpResponse<T>, HttpClientError>` — no try/catch needed, no unhandled rejections, always typed.
11
-
12
- ---
13
-
14
- ## Installation
15
-
16
- ```bash
17
- npm install @backendkit-labs/http-client axios
18
- ```
19
-
20
- NestJS peer dependencies (only for the `/nestjs` subpath):
21
-
22
- ```bash
23
- npm install @nestjs/common @nestjs/core rxjs
24
- ```
25
-
26
- ---
27
-
28
- ## TypeScript Configuration
29
-
30
- ### Subpath exports (`/nestjs`)
31
-
32
- This package uses the `exports` field in `package.json` to expose the `/nestjs` subpath. TypeScript's ability to resolve it depends on the `moduleResolution` setting in your `tsconfig.json`.
33
-
34
- **Modern resolution (recommended) — no extra config needed:**
35
-
36
- ```json
37
- {
38
- "compilerOptions": {
39
- "moduleResolution": "bundler"
40
- }
41
- }
42
- ```
43
-
44
- `"bundler"`, `"node16"`, and `"nodenext"` all understand the `exports` field natively.
45
-
46
- **Legacy resolution (`"node"`) — add `paths` aliases:**
47
-
48
- ```json
49
- {
50
- "compilerOptions": {
51
- "moduleResolution": "node",
52
- "paths": {
53
- "@backendkit-labs/http-client/nestjs": [
54
- "./node_modules/@backendkit-labs/http-client/dist/nestjs/index.d.ts"
55
- ]
56
- }
57
- }
58
- }
59
- ```
60
-
61
- **NestJS decorator support:**
62
-
63
- ```json
64
- {
65
- "compilerOptions": {
66
- "experimentalDecorators": true,
67
- "emitDecoratorMetadata": true
68
- }
69
- }
70
- ```
71
-
72
- And in your `main.ts`, before anything else:
73
-
74
- ```typescript
75
- import 'reflect-metadata';
76
- ```
77
-
78
- ---
79
-
80
- ## Quick Start
81
-
82
- ```typescript
83
- import { HttpClient } from '@backendkit-labs/http-client';
84
-
85
- const client = new HttpClient({
86
- baseURL: 'https://api.example.com',
87
- timeout: 5_000,
88
- });
89
-
90
- // All methods return Result<HttpResponse<T>, HttpClientError>
91
- const result = await client.get<User[]>('/users');
92
-
93
- if (result.ok) {
94
- console.log(result.value.data); // User[]
95
- console.log(result.value.status); // 200
96
- } else {
97
- console.error(result.error.type); // 'http' | 'network' | 'timeout' | 'cancelled' | 'circuit-open'
98
- console.error(result.error.status); // 404, 500, etc. (for 'http' type)
99
- }
100
- ```
101
-
102
- ---
103
-
104
- ## Configuration
105
-
106
- ```typescript
107
- const client = new HttpClient({
108
- baseURL: 'https://api.example.com',
109
- timeout: 10_000, // default: 10 000 ms
110
- headers: { 'X-API-Key': 'secret' },
111
-
112
- // Retry with exponential backoff + jitter
113
- retry: {
114
- attempts: 3, // retries after first failure
115
- delayMs: 100,
116
- maxDelayMs: 5_000,
117
- jitter: true,
118
- shouldRetry: (err) => err.type === 'network' || err.type === 'timeout',
119
- },
120
-
121
- // Circuit breaker
122
- circuitBreaker: {
123
- failureThreshold: 50, // % of calls that must fail to open the circuit
124
- minimumCalls: 5, // minimum calls before evaluating thresholds
125
- slidingWindowSize: 10,
126
- openTimeoutMs: 30_000,
127
- },
128
-
129
- // Pre-request middleware steps
130
- steps: [authStep, correlationIdStep],
131
- });
132
- ```
133
-
134
- ---
135
-
136
- ## HTTP Methods
137
-
138
- All methods accept an optional `RequestConfig`:
139
-
140
- ```typescript
141
- interface RequestConfig {
142
- headers?: Record<string, string>;
143
- params?: Record<string, unknown>; // query string parameters
144
- timeout?: number; // per-request override
145
- cancelKey?: string; // key to cancel this request
146
- correlationId?: string;
147
- }
148
- ```
149
-
150
- ```typescript
151
- client.get<T>(url, config?)
152
- client.post<T>(url, data?, config?)
153
- client.put<T>(url, data?, config?)
154
- client.patch<T>(url, data?, config?)
155
- client.delete<T>(url, config?)
156
- ```
157
-
158
- ---
159
-
160
- ## Error Types
161
-
162
- ```typescript
163
- type HttpErrorType = 'http' | 'network' | 'timeout' | 'cancelled' | 'circuit-open';
164
-
165
- interface HttpClientError {
166
- type: HttpErrorType;
167
- message: string;
168
- status?: number; // only for 'http'
169
- data?: unknown; // response body, only for 'http'
170
- cause?: unknown; // original axios error
171
- }
172
- ```
173
-
174
- ---
175
-
176
- ## Request Cancellation
177
-
178
- Register a `cancelKey` on the request and cancel by key at any time:
179
-
180
- ```typescript
181
- const promise = client.get('/long-poll', { cancelKey: 'my-poll' });
182
-
183
- // Cancel a specific request
184
- client.cancelRequest('my-poll');
185
-
186
- // Cancel all in-flight requests
187
- client.cancelAll();
188
-
189
- const result = await promise;
190
- if (!result.ok && result.error.type === 'cancelled') {
191
- // handle cancellation
192
- }
193
- ```
194
-
195
- ---
196
-
197
- ## Pipeline Middleware
198
-
199
- Pre-request middleware steps transform the `HttpCtx` before each request. Steps are powered by `@backendkit-labs/pipeline`.
200
-
201
- ```typescript
202
- import type { PipelineStep, StepResult } from '@backendkit-labs/pipeline';
203
- import { Ok } from '@backendkit-labs/pipeline';
204
- import type { HttpCtx, HttpClientError } from '@backendkit-labs/http-client';
205
-
206
- const authStep: PipelineStep<HttpCtx, HttpClientError> = {
207
- stepName: 'auth',
208
- async handle(ctx): Promise<StepResult<HttpCtx, HttpClientError>> {
209
- const token = await tokenStore.get();
210
- return Ok({ ...ctx, headers: { ...ctx.headers, Authorization: `Bearer ${token}` } });
211
- },
212
- };
213
-
214
- const client = new HttpClient({ steps: [authStep] });
215
- ```
216
-
217
- A step can abort the request by returning `Err(...)`:
218
-
219
- ```typescript
220
- import { Err } from '@backendkit-labs/pipeline';
221
-
222
- const rateLimitStep: PipelineStep<HttpCtx, HttpClientError> = {
223
- stepName: 'rate-limit',
224
- async handle(ctx): Promise<StepResult<HttpCtx, HttpClientError>> {
225
- if (await rateLimiter.isExceeded()) {
226
- return Err({ type: 'network', message: 'Rate limit exceeded' });
227
- }
228
- return Ok(ctx);
229
- },
230
- };
231
- ```
232
-
233
- ---
234
-
235
- ## Observability
236
-
237
- ```typescript
238
- // Snapshot of lifetime counters
239
- client.getMetrics();
240
- // → { requests, success, failed, cancelled, circuitOpen, retried }
241
-
242
- // Circuit breaker state and counters
243
- client.getCircuitBreakerState(); // 'closed' | 'open' | 'half_open' | undefined
244
- client.getCircuitBreakerMetrics(); // detailed metrics or undefined
245
- ```
246
-
247
- ---
248
-
249
- ## NestJS Integration
250
-
251
- ### Module registration
252
-
253
- ```typescript
254
- // Define typed injection tokens
255
- export const PRIMARY_API = defineHttpClient('primary-api');
256
- export const PAYMENTS_API = defineHttpClient('payments-api');
257
- ```
258
-
259
- ```typescript
260
- import { HttpClientModule } from '@backendkit-labs/http-client/nestjs';
261
- import { PRIMARY_API, PAYMENTS_API } from './tokens';
262
-
263
- @Module({
264
- imports: [
265
- HttpClientModule.forRoot({
266
- clients: [
267
- { token: PRIMARY_API, config: { baseURL: 'https://api.example.com', retry: { attempts: 3, delayMs: 100 } } },
268
- { token: PAYMENTS_API, config: { baseURL: 'https://payments.example.com', circuitBreaker: { failureThreshold: 40, minimumCalls: 3 } } },
269
- ],
270
- }),
271
- ],
272
- })
273
- export class AppModule {}
274
- ```
275
-
276
- ### Injection
277
-
278
- ```typescript
279
- import { InjectHttpClient } from '@backendkit-labs/http-client/nestjs';
280
- import { PRIMARY_API } from './tokens';
281
-
282
- @Injectable()
283
- export class UserService {
284
- constructor(
285
- @InjectHttpClient(PRIMARY_API) private readonly http: HttpClient,
286
- ) {}
287
-
288
- async getUsers(): Promise<User[]> {
289
- const result = await this.http.get<User[]>('/users');
290
- if (!result.ok) throw new Error(result.error.message);
291
- return result.value.data;
292
- }
293
- }
294
- ```
295
-
296
- ### Async module registration
297
-
298
- ```typescript
299
- HttpClientModule.forRootAsync({
300
- imports: [ConfigModule],
301
- inject: [ConfigService],
302
- useFactory: (config: ConfigService) => ({
303
- clients: [{
304
- token: PRIMARY_API,
305
- config: { baseURL: config.get('API_URL'), timeout: config.get('API_TIMEOUT') },
306
- }],
307
- }),
308
- }),
309
- ```
310
-
311
- ---
312
-
313
- ## Named Clients
314
-
315
- ```typescript
316
- import { defineHttpClient, HttpClientToken } from '@backendkit-labs/http-client';
317
-
318
- export const GITHUB_API: HttpClientToken = defineHttpClient('github-api');
319
-
320
- // Provides the token's symbol as the NestJS DI token:
321
- // Inject with @InjectHttpClient(GITHUB_API)
322
- ```
323
-
324
- ---
325
-
326
- ## License
327
-
328
- Apache-2.0
1
+ # @backendkit-labs/http-client
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@backendkit-labs/http-client?style=flat-square&color=cb3837)](https://www.npmjs.com/package/@backendkit-labs/http-client)
4
+ [![CI](https://img.shields.io/github/actions/workflow/status/BackendKit-labs/backendkit-monorepo/ci.yml?style=flat-square&label=CI)](https://github.com/BackendKit-labs/backendkit-monorepo/actions/workflows/ci.yml)
5
+ [![License](https://img.shields.io/npm/l/@backendkit-labs/http-client?style=flat-square)](LICENSE)
6
+ [![Node](https://img.shields.io/node/v/@backendkit-labs/http-client?style=flat-square)](package.json)
7
+ [![Docs](https://img.shields.io/badge/docs-backendkitlabs.dev-4f7eff?style=flat-square)](https://backendkitlabs.dev/docs/http-client/)
8
+
9
+ > Production-grade HTTP client for Node.js — built on axios with circuit breaker, retry with exponential backoff, typed `Result<T, E>` responses, request cancellation, pre-request pipeline middleware, and optional NestJS DI integration.
10
+
11
+ Every method returns `Result<HttpResponse<T>, HttpClientError>` — no try/catch needed, no unhandled rejections, always typed.
12
+
13
+ ---
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @backendkit-labs/http-client axios
19
+ ```
20
+
21
+ NestJS peer dependencies (only for the `/nestjs` subpath):
22
+
23
+ ```bash
24
+ npm install @nestjs/common @nestjs/core rxjs
25
+ ```
26
+
27
+ ---
28
+
29
+ ## TypeScript Configuration
30
+
31
+ ### Subpath exports (`/nestjs`)
32
+
33
+ This package uses the `exports` field in `package.json` to expose the `/nestjs` subpath. TypeScript's ability to resolve it depends on the `moduleResolution` setting in your `tsconfig.json`.
34
+
35
+ **Modern resolution (recommended) — no extra config needed:**
36
+
37
+ ```json
38
+ {
39
+ "compilerOptions": {
40
+ "moduleResolution": "bundler"
41
+ }
42
+ }
43
+ ```
44
+
45
+ `"bundler"`, `"node16"`, and `"nodenext"` all understand the `exports` field natively.
46
+
47
+ **Legacy resolution (`"node"`) — add `paths` aliases:**
48
+
49
+ ```json
50
+ {
51
+ "compilerOptions": {
52
+ "moduleResolution": "node",
53
+ "paths": {
54
+ "@backendkit-labs/http-client/nestjs": [
55
+ "./node_modules/@backendkit-labs/http-client/dist/nestjs/index.d.ts"
56
+ ]
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ **NestJS decorator support:**
63
+
64
+ ```json
65
+ {
66
+ "compilerOptions": {
67
+ "experimentalDecorators": true,
68
+ "emitDecoratorMetadata": true
69
+ }
70
+ }
71
+ ```
72
+
73
+ And in your `main.ts`, before anything else:
74
+
75
+ ```typescript
76
+ import 'reflect-metadata';
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Quick Start
82
+
83
+ ```typescript
84
+ import { HttpClient } from '@backendkit-labs/http-client';
85
+
86
+ const client = new HttpClient({
87
+ baseURL: 'https://api.example.com',
88
+ timeout: 5_000,
89
+ });
90
+
91
+ // All methods return Result<HttpResponse<T>, HttpClientError>
92
+ const result = await client.get<User[]>('/users');
93
+
94
+ if (result.ok) {
95
+ console.log(result.value.data); // User[]
96
+ console.log(result.value.status); // 200
97
+ } else {
98
+ console.error(result.error.type); // 'http' | 'network' | 'timeout' | 'cancelled' | 'circuit-open'
99
+ console.error(result.error.status); // 404, 500, etc. (for 'http' type)
100
+ }
101
+ ```
102
+
103
+ ---
104
+
105
+ ## Configuration
106
+
107
+ ```typescript
108
+ const client = new HttpClient({
109
+ baseURL: 'https://api.example.com',
110
+ timeout: 10_000, // default: 10 000 ms
111
+ headers: { 'X-API-Key': 'secret' },
112
+
113
+ // Retry with exponential backoff + jitter
114
+ retry: {
115
+ attempts: 3, // retries after first failure
116
+ delayMs: 100,
117
+ maxDelayMs: 5_000,
118
+ jitter: true,
119
+ shouldRetry: (err) => err.type === 'network' || err.type === 'timeout',
120
+ },
121
+
122
+ // Circuit breaker
123
+ circuitBreaker: {
124
+ failureThreshold: 50, // % of calls that must fail to open the circuit
125
+ minimumCalls: 5, // minimum calls before evaluating thresholds
126
+ slidingWindowSize: 10,
127
+ openTimeoutMs: 30_000,
128
+ },
129
+
130
+ // Pre-request middleware steps
131
+ steps: [authStep, correlationIdStep],
132
+ });
133
+ ```
134
+
135
+ ---
136
+
137
+ ## HTTP Methods
138
+
139
+ All methods accept an optional `RequestConfig`:
140
+
141
+ ```typescript
142
+ interface RequestConfig {
143
+ headers?: Record<string, string>;
144
+ params?: Record<string, unknown>; // query string parameters
145
+ timeout?: number; // per-request override
146
+ cancelKey?: string; // key to cancel this request
147
+ correlationId?: string;
148
+ }
149
+ ```
150
+
151
+ ```typescript
152
+ client.get<T>(url, config?)
153
+ client.post<T>(url, data?, config?)
154
+ client.put<T>(url, data?, config?)
155
+ client.patch<T>(url, data?, config?)
156
+ client.delete<T>(url, config?)
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Error Types
162
+
163
+ ```typescript
164
+ type HttpErrorType = 'http' | 'network' | 'timeout' | 'cancelled' | 'circuit-open';
165
+
166
+ interface HttpClientError {
167
+ type: HttpErrorType;
168
+ message: string;
169
+ status?: number; // only for 'http'
170
+ data?: unknown; // response body, only for 'http'
171
+ cause?: unknown; // original axios error
172
+ }
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Request Cancellation
178
+
179
+ Register a `cancelKey` on the request and cancel by key at any time:
180
+
181
+ ```typescript
182
+ const promise = client.get('/long-poll', { cancelKey: 'my-poll' });
183
+
184
+ // Cancel a specific request
185
+ client.cancelRequest('my-poll');
186
+
187
+ // Cancel all in-flight requests
188
+ client.cancelAll();
189
+
190
+ const result = await promise;
191
+ if (!result.ok && result.error.type === 'cancelled') {
192
+ // handle cancellation
193
+ }
194
+ ```
195
+
196
+ ---
197
+
198
+ ## Pipeline Middleware
199
+
200
+ Pre-request middleware steps transform the `HttpCtx` before each request. Steps are powered by `@backendkit-labs/pipeline`.
201
+
202
+ ```typescript
203
+ import type { PipelineStep, StepResult } from '@backendkit-labs/pipeline';
204
+ import { Ok } from '@backendkit-labs/pipeline';
205
+ import type { HttpCtx, HttpClientError } from '@backendkit-labs/http-client';
206
+
207
+ const authStep: PipelineStep<HttpCtx, HttpClientError> = {
208
+ stepName: 'auth',
209
+ async handle(ctx): Promise<StepResult<HttpCtx, HttpClientError>> {
210
+ const token = await tokenStore.get();
211
+ return Ok({ ...ctx, headers: { ...ctx.headers, Authorization: `Bearer ${token}` } });
212
+ },
213
+ };
214
+
215
+ const client = new HttpClient({ steps: [authStep] });
216
+ ```
217
+
218
+ A step can abort the request by returning `Err(...)`:
219
+
220
+ ```typescript
221
+ import { Err } from '@backendkit-labs/pipeline';
222
+
223
+ const rateLimitStep: PipelineStep<HttpCtx, HttpClientError> = {
224
+ stepName: 'rate-limit',
225
+ async handle(ctx): Promise<StepResult<HttpCtx, HttpClientError>> {
226
+ if (await rateLimiter.isExceeded()) {
227
+ return Err({ type: 'network', message: 'Rate limit exceeded' });
228
+ }
229
+ return Ok(ctx);
230
+ },
231
+ };
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Observability
237
+
238
+ ```typescript
239
+ // Snapshot of lifetime counters
240
+ client.getMetrics();
241
+ // → { requests, success, failed, cancelled, circuitOpen, retried }
242
+
243
+ // Circuit breaker state and counters
244
+ client.getCircuitBreakerState(); // 'closed' | 'open' | 'half_open' | undefined
245
+ client.getCircuitBreakerMetrics(); // detailed metrics or undefined
246
+ ```
247
+
248
+ ---
249
+
250
+ ## NestJS Integration
251
+
252
+ ### Module registration
253
+
254
+ ```typescript
255
+ // Define typed injection tokens
256
+ export const PRIMARY_API = defineHttpClient('primary-api');
257
+ export const PAYMENTS_API = defineHttpClient('payments-api');
258
+ ```
259
+
260
+ ```typescript
261
+ import { HttpClientModule } from '@backendkit-labs/http-client/nestjs';
262
+ import { PRIMARY_API, PAYMENTS_API } from './tokens';
263
+
264
+ @Module({
265
+ imports: [
266
+ HttpClientModule.forRoot({
267
+ clients: [
268
+ { token: PRIMARY_API, config: { baseURL: 'https://api.example.com', retry: { attempts: 3, delayMs: 100 } } },
269
+ { token: PAYMENTS_API, config: { baseURL: 'https://payments.example.com', circuitBreaker: { failureThreshold: 40, minimumCalls: 3 } } },
270
+ ],
271
+ }),
272
+ ],
273
+ })
274
+ export class AppModule {}
275
+ ```
276
+
277
+ ### Injection
278
+
279
+ ```typescript
280
+ import { InjectHttpClient } from '@backendkit-labs/http-client/nestjs';
281
+ import { PRIMARY_API } from './tokens';
282
+
283
+ @Injectable()
284
+ export class UserService {
285
+ constructor(
286
+ @InjectHttpClient(PRIMARY_API) private readonly http: HttpClient,
287
+ ) {}
288
+
289
+ async getUsers(): Promise<User[]> {
290
+ const result = await this.http.get<User[]>('/users');
291
+ if (!result.ok) throw new Error(result.error.message);
292
+ return result.value.data;
293
+ }
294
+ }
295
+ ```
296
+
297
+ ### Async module registration
298
+
299
+ ```typescript
300
+ HttpClientModule.forRootAsync({
301
+ imports: [ConfigModule],
302
+ inject: [ConfigService],
303
+ useFactory: (config: ConfigService) => ({
304
+ clients: [{
305
+ token: PRIMARY_API,
306
+ config: { baseURL: config.get('API_URL'), timeout: config.get('API_TIMEOUT') },
307
+ }],
308
+ }),
309
+ }),
310
+ ```
311
+
312
+ ---
313
+
314
+ ## Named Clients
315
+
316
+ ```typescript
317
+ import { defineHttpClient, HttpClientToken } from '@backendkit-labs/http-client';
318
+
319
+ export const GITHUB_API: HttpClientToken = defineHttpClient('github-api');
320
+
321
+ // Provides the token's symbol as the NestJS DI token:
322
+ // Inject with @InjectHttpClient(GITHUB_API)
323
+ ```
324
+
325
+ ---
326
+
327
+ ## License
328
+
329
+ Apache-2.0
@@ -18,20 +18,18 @@ exports.HttpClientModule = class HttpClientModule {
18
18
  }
19
19
  static forRootAsync(options) {
20
20
  const asyncProvider = exports.HttpClientModule._asyncOptionsProvider(options);
21
- const clientsProvider = {
22
- provide: "HTTP_CLIENT_INSTANCES",
21
+ const clientProviders = options.clients.map((token) => ({
22
+ provide: token.symbol,
23
23
  useFactory: (opts) => {
24
- return opts.clients.map(({ token, config }) => ({
25
- token,
26
- instance: new chunkGZWQJKYR_cjs.HttpClient(config)
27
- }));
24
+ const def = opts.clients.find((c) => c.token.symbol === token.symbol);
25
+ if (!def) throw new Error(
26
+ `HttpClient config not found for '${token.description}'. The factory must return a config entry for every token declared in 'clients'.`
27
+ );
28
+ return new chunkGZWQJKYR_cjs.HttpClient(def.config);
28
29
  },
29
30
  inject: [HTTP_CLIENT_MODULE_OPTIONS]
30
- };
31
- const allProviders = [
32
- asyncProvider,
33
- clientsProvider
34
- ];
31
+ }));
32
+ const allProviders = [asyncProvider, ...clientProviders];
35
33
  return {
36
34
  module: exports.HttpClientModule,
37
35
  imports: options.imports ?? [],
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/nestjs/http-client.module.ts","../../src/nestjs/http-client.decorator.ts"],"names":["HttpClientModule","HttpClient","__decorateClass","Module","Inject"],"mappings":";;;;;AAUA,IAAM,0BAAA,GAA6B,4BAAA;AAGtBA,2BAAN,sBAAA,CAAuB;AAAA,EAC5B,OAAO,QAAQ,OAAA,EAAiD;AAC9D,IAAA,MAAM,SAAA,GAAwB,QAAQ,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,EAAE,KAAA,EAAO,MAAA,OAC1DA,wBAAA,CAAiB,eAAA,CAAgB,OAAO,MAAM;AAAA,KAChD;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAUA,wBAAA;AAAA,MACV,SAAA;AAAA,MACA,OAAA,EAAU,SAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,OAAA,EAAsD;AACxE,IAAA,MAAM,aAAA,GAAgBA,wBAAA,CAAiB,qBAAA,CAAsB,OAAO,CAAA;AAEpE,IAAA,MAAM,eAAA,GAA4B;AAAA,MAChC,OAAA,EAAY,uBAAA;AAAA,MACZ,UAAA,EAAY,CAAC,IAAA,KAAkC;AAC7C,QAAA,OAAO,KAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,EAAE,KAAA,EAAO,QAAO,MAAO;AAAA,UAC9C,KAAA;AAAA,UACA,QAAA,EAAU,IAAIC,4BAAA,CAAW,MAAM;AAAA,SACjC,CAAE,CAAA;AAAA,MACJ,CAAA;AAAA,MACA,MAAA,EAAQ,CAAC,0BAA0B;AAAA,KACrC;AAEA,IAAA,MAAM,YAAA,GAA2B;AAAA,MAC/B,aAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAUD,wBAAA;AAAA,MACV,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAW,EAAC;AAAA,MAC9B,SAAA,EAAW,YAAA;AAAA,MACX,OAAA,EAAU,YAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAe,eAAA,CAAgB,KAAA,EAAwB,MAAA,EAAoC;AACzF,IAAA,OAAO;AAAA,MACL,SAAY,KAAA,CAAM,MAAA;AAAA,MAClB,UAAA,EAAY,MAAM,IAAIC,4BAAA,CAAW,MAAM;AAAA,KACzC;AAAA,EACF;AAAA,EAEA,OAAe,sBAAsB,OAAA,EAAiD;AACpF,IAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,MAAA,EAAa,OAAA,CAAQ,MAAA,IAAU;AAAC,OAClC;AAAA,IACF;AAEA,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,WAAA,IAAe,OAAA,CAAQ,QAAA;AAC3C,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,UAAA,EAAY,CAAC,OAAA,KAAsC,OAAA,CAAQ,uBAAA,EAAwB;AAAA,QACnF,MAAA,EAAY,CAAC,GAAqC;AAAA,OACpD;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,OAAA,EAAU,0BAAA;AAAA,MACV,QAAA,EAAU,EAAE,OAAA,EAAS,EAAC;AAAE,KAC1B;AAAA,EACF;AACF;AAxEaD,wBAAA,GAANE,iCAAA,CAAA;AAAA,EADNC,aAAA,CAAO,EAAE;AAAA,CAAA,EACGH,wBAAA,CAAA;ACVN,IAAM,gBAAA,GAAmB,CAC9B,KAAA,KAC8BI,aAAA,CAAO,MAAM,MAAM","file":"index.cjs","sourcesContent":["import { Module, DynamicModule, Provider } from '@nestjs/common';\nimport type { Type, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';\nimport { HttpClient } from '../core/http-client.js';\nimport type { HttpClientConfig, HttpClientToken } from '../core/types.js';\nimport type {\n HttpClientModuleOptions,\n HttpClientModuleAsyncOptions,\n HttpClientOptionsFactory,\n} from './http-client.options.js';\n\nconst HTTP_CLIENT_MODULE_OPTIONS = 'HTTP_CLIENT_MODULE_OPTIONS';\n\n@Module({})\nexport class HttpClientModule {\n static forRoot(options: HttpClientModuleOptions): DynamicModule {\n const providers: Provider[] = options.clients.map(({ token, config }) =>\n HttpClientModule._clientProvider(token, config),\n );\n\n return {\n module: HttpClientModule,\n providers,\n exports: providers,\n global: true,\n };\n }\n\n static forRootAsync(options: HttpClientModuleAsyncOptions): DynamicModule {\n const asyncProvider = HttpClientModule._asyncOptionsProvider(options);\n\n const clientsProvider: Provider = {\n provide: 'HTTP_CLIENT_INSTANCES',\n useFactory: (opts: HttpClientModuleOptions) => {\n return opts.clients.map(({ token, config }) => ({\n token,\n instance: new HttpClient(config),\n }));\n },\n inject: [HTTP_CLIENT_MODULE_OPTIONS],\n };\n\n const allProviders: Provider[] = [\n asyncProvider,\n clientsProvider,\n ];\n\n return {\n module: HttpClientModule,\n imports: options.imports ?? [],\n providers: allProviders,\n exports: allProviders,\n global: true,\n };\n }\n\n private static _clientProvider(token: HttpClientToken, config: HttpClientConfig): Provider {\n return {\n provide: token.symbol,\n useFactory: () => new HttpClient(config),\n };\n }\n\n private static _asyncOptionsProvider(options: HttpClientModuleAsyncOptions): Provider {\n if (options.useFactory) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: options.useFactory as (...args: unknown[]) => HttpClientModuleOptions | Promise<HttpClientModuleOptions>,\n inject: (options.inject ?? []) as (InjectionToken | OptionalFactoryDependency)[],\n };\n }\n\n const cls = options.useExisting ?? options.useClass;\n if (cls) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: (factory: HttpClientOptionsFactory) => factory.createHttpClientOptions(),\n inject: [cls as Type<HttpClientOptionsFactory>],\n };\n }\n\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useValue: { clients: [] } satisfies HttpClientModuleOptions,\n };\n }\n}\n","import { Inject } from '@nestjs/common';\nimport type { HttpClientToken } from '../core/types.js';\n\nexport const InjectHttpClient = (\n token: HttpClientToken,\n): ReturnType<typeof Inject> => Inject(token.symbol);\n"]}
1
+ {"version":3,"sources":["../../src/nestjs/http-client.module.ts","../../src/nestjs/http-client.decorator.ts"],"names":["HttpClientModule","HttpClient","__decorateClass","Module","Inject"],"mappings":";;;;;AAUA,IAAM,0BAAA,GAA6B,4BAAA;AAGtBA,2BAAN,sBAAA,CAAuB;AAAA,EAC5B,OAAO,QAAQ,OAAA,EAAiD;AAC9D,IAAA,MAAM,SAAA,GAAwB,QAAQ,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,EAAE,KAAA,EAAO,MAAA,OAC1DA,wBAAA,CAAiB,eAAA,CAAgB,OAAO,MAAM;AAAA,KAChD;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAUA,wBAAA;AAAA,MACV,SAAA;AAAA,MACA,OAAA,EAAU,SAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,OAAA,EAAsD;AACxE,IAAA,MAAM,aAAA,GAAgBA,wBAAA,CAAiB,qBAAA,CAAsB,OAAO,CAAA;AAEpE,IAAA,MAAM,eAAA,GAA8B,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,CAAA,KAAA,MAAU;AAAA,MAChE,SAAY,KAAA,CAAM,MAAA;AAAA,MAClB,UAAA,EAAY,CAAC,IAAA,KAAkC;AAC7C,QAAA,MAAM,GAAA,GAAM,KAAK,OAAA,CAAQ,IAAA,CAAK,OAAK,CAAA,CAAE,KAAA,CAAM,MAAA,KAAW,KAAA,CAAM,MAAM,CAAA;AAClE,QAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA;AAAA,UAClB,CAAA,iCAAA,EAAoC,MAAM,WAAW,CAAA,gFAAA;AAAA,SAEvD;AACA,QAAA,OAAO,IAAIC,4BAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AAAA,MAClC,CAAA;AAAA,MACA,MAAA,EAAQ,CAAC,0BAA0B;AAAA,KACrC,CAAE,CAAA;AAEF,IAAA,MAAM,YAAA,GAA2B,CAAC,aAAA,EAAe,GAAG,eAAe,CAAA;AAEnE,IAAA,OAAO;AAAA,MACL,MAAA,EAAUD,wBAAA;AAAA,MACV,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAW,EAAC;AAAA,MAC9B,SAAA,EAAW,YAAA;AAAA,MACX,OAAA,EAAU,YAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAe,eAAA,CAAgB,KAAA,EAAwB,MAAA,EAAoC;AACzF,IAAA,OAAO;AAAA,MACL,SAAY,KAAA,CAAM,MAAA;AAAA,MAClB,UAAA,EAAY,MAAM,IAAIC,4BAAA,CAAW,MAAM;AAAA,KACzC;AAAA,EACF;AAAA,EAEA,OAAe,sBAAsB,OAAA,EAAiD;AACpF,IAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,MAAA,EAAa,OAAA,CAAQ,MAAA,IAAU;AAAC,OAClC;AAAA,IACF;AAEA,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,WAAA,IAAe,OAAA,CAAQ,QAAA;AAC3C,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,UAAA,EAAY,CAAC,OAAA,KAAsC,OAAA,CAAQ,uBAAA,EAAwB;AAAA,QACnF,MAAA,EAAY,CAAC,GAAqC;AAAA,OACpD;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,OAAA,EAAU,0BAAA;AAAA,MACV,QAAA,EAAU,EAAE,OAAA,EAAS,EAAC;AAAE,KAC1B;AAAA,EACF;AACF;AAvEaD,wBAAA,GAANE,iCAAA,CAAA;AAAA,EADNC,aAAA,CAAO,EAAE;AAAA,CAAA,EACGH,wBAAA,CAAA;ACVN,IAAM,gBAAA,GAAmB,CAC9B,KAAA,KAC8BI,aAAA,CAAO,MAAM,MAAM","file":"index.cjs","sourcesContent":["import { Module, DynamicModule, Provider } from '@nestjs/common';\nimport type { Type, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';\nimport { HttpClient } from '../core/http-client.js';\nimport type { HttpClientConfig, HttpClientToken } from '../core/types.js';\nimport type {\n HttpClientModuleOptions,\n HttpClientModuleAsyncOptions,\n HttpClientOptionsFactory,\n} from './http-client.options.js';\n\nconst HTTP_CLIENT_MODULE_OPTIONS = 'HTTP_CLIENT_MODULE_OPTIONS';\n\n@Module({})\nexport class HttpClientModule {\n static forRoot(options: HttpClientModuleOptions): DynamicModule {\n const providers: Provider[] = options.clients.map(({ token, config }) =>\n HttpClientModule._clientProvider(token, config),\n );\n\n return {\n module: HttpClientModule,\n providers,\n exports: providers,\n global: true,\n };\n }\n\n static forRootAsync(options: HttpClientModuleAsyncOptions): DynamicModule {\n const asyncProvider = HttpClientModule._asyncOptionsProvider(options);\n\n const clientProviders: Provider[] = options.clients.map(token => ({\n provide: token.symbol,\n useFactory: (opts: HttpClientModuleOptions) => {\n const def = opts.clients.find(c => c.token.symbol === token.symbol);\n if (!def) throw new Error(\n `HttpClient config not found for '${token.description}'. ` +\n `The factory must return a config entry for every token declared in 'clients'.`,\n );\n return new HttpClient(def.config);\n },\n inject: [HTTP_CLIENT_MODULE_OPTIONS],\n }));\n\n const allProviders: Provider[] = [asyncProvider, ...clientProviders];\n\n return {\n module: HttpClientModule,\n imports: options.imports ?? [],\n providers: allProviders,\n exports: allProviders,\n global: true,\n };\n }\n\n private static _clientProvider(token: HttpClientToken, config: HttpClientConfig): Provider {\n return {\n provide: token.symbol,\n useFactory: () => new HttpClient(config),\n };\n }\n\n private static _asyncOptionsProvider(options: HttpClientModuleAsyncOptions): Provider {\n if (options.useFactory) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: options.useFactory as (...args: unknown[]) => HttpClientModuleOptions | Promise<HttpClientModuleOptions>,\n inject: (options.inject ?? []) as (InjectionToken | OptionalFactoryDependency)[],\n };\n }\n\n const cls = options.useExisting ?? options.useClass;\n if (cls) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: (factory: HttpClientOptionsFactory) => factory.createHttpClientOptions(),\n inject: [cls as Type<HttpClientOptionsFactory>],\n };\n }\n\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useValue: { clients: [] } satisfies HttpClientModuleOptions,\n };\n }\n}\n","import { Inject } from '@nestjs/common';\nimport type { HttpClientToken } from '../core/types.js';\n\nexport const InjectHttpClient = (\n token: HttpClientToken,\n): ReturnType<typeof Inject> => Inject(token.symbol);\n"]}
@@ -14,6 +14,12 @@ interface HttpClientOptionsFactory {
14
14
  createHttpClientOptions(): Promise<HttpClientModuleOptions> | HttpClientModuleOptions;
15
15
  }
16
16
  interface HttpClientModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
17
+ /**
18
+ * Declare the client tokens that the factory will configure.
19
+ * Each token listed here gets its own provider, so `@InjectHttpClient(token)` works.
20
+ * The factory must return a config entry for every token declared here.
21
+ */
22
+ clients: HttpClientToken[];
17
23
  useFactory?: (...args: unknown[]) => Promise<HttpClientModuleOptions> | HttpClientModuleOptions;
18
24
  useClass?: Type<HttpClientOptionsFactory>;
19
25
  useExisting?: Type<HttpClientOptionsFactory>;
@@ -14,6 +14,12 @@ interface HttpClientOptionsFactory {
14
14
  createHttpClientOptions(): Promise<HttpClientModuleOptions> | HttpClientModuleOptions;
15
15
  }
16
16
  interface HttpClientModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
17
+ /**
18
+ * Declare the client tokens that the factory will configure.
19
+ * Each token listed here gets its own provider, so `@InjectHttpClient(token)` works.
20
+ * The factory must return a config entry for every token declared here.
21
+ */
22
+ clients: HttpClientToken[];
17
23
  useFactory?: (...args: unknown[]) => Promise<HttpClientModuleOptions> | HttpClientModuleOptions;
18
24
  useClass?: Type<HttpClientOptionsFactory>;
19
25
  useExisting?: Type<HttpClientOptionsFactory>;
@@ -16,20 +16,18 @@ var HttpClientModule = class {
16
16
  }
17
17
  static forRootAsync(options) {
18
18
  const asyncProvider = HttpClientModule._asyncOptionsProvider(options);
19
- const clientsProvider = {
20
- provide: "HTTP_CLIENT_INSTANCES",
19
+ const clientProviders = options.clients.map((token) => ({
20
+ provide: token.symbol,
21
21
  useFactory: (opts) => {
22
- return opts.clients.map(({ token, config }) => ({
23
- token,
24
- instance: new HttpClient(config)
25
- }));
22
+ const def = opts.clients.find((c) => c.token.symbol === token.symbol);
23
+ if (!def) throw new Error(
24
+ `HttpClient config not found for '${token.description}'. The factory must return a config entry for every token declared in 'clients'.`
25
+ );
26
+ return new HttpClient(def.config);
26
27
  },
27
28
  inject: [HTTP_CLIENT_MODULE_OPTIONS]
28
- };
29
- const allProviders = [
30
- asyncProvider,
31
- clientsProvider
32
- ];
29
+ }));
30
+ const allProviders = [asyncProvider, ...clientProviders];
33
31
  return {
34
32
  module: HttpClientModule,
35
33
  imports: options.imports ?? [],
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/nestjs/http-client.module.ts","../../src/nestjs/http-client.decorator.ts"],"names":[],"mappings":";;;AAUA,IAAM,0BAAA,GAA6B,4BAAA;AAG5B,IAAM,mBAAN,MAAuB;AAAA,EAC5B,OAAO,QAAQ,OAAA,EAAiD;AAC9D,IAAA,MAAM,SAAA,GAAwB,QAAQ,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,EAAE,KAAA,EAAO,MAAA,OAC1D,gBAAA,CAAiB,eAAA,CAAgB,OAAO,MAAM;AAAA,KAChD;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAU,gBAAA;AAAA,MACV,SAAA;AAAA,MACA,OAAA,EAAU,SAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,OAAA,EAAsD;AACxE,IAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,qBAAA,CAAsB,OAAO,CAAA;AAEpE,IAAA,MAAM,eAAA,GAA4B;AAAA,MAChC,OAAA,EAAY,uBAAA;AAAA,MACZ,UAAA,EAAY,CAAC,IAAA,KAAkC;AAC7C,QAAA,OAAO,KAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,EAAE,KAAA,EAAO,QAAO,MAAO;AAAA,UAC9C,KAAA;AAAA,UACA,QAAA,EAAU,IAAI,UAAA,CAAW,MAAM;AAAA,SACjC,CAAE,CAAA;AAAA,MACJ,CAAA;AAAA,MACA,MAAA,EAAQ,CAAC,0BAA0B;AAAA,KACrC;AAEA,IAAA,MAAM,YAAA,GAA2B;AAAA,MAC/B,aAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAU,gBAAA;AAAA,MACV,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAW,EAAC;AAAA,MAC9B,SAAA,EAAW,YAAA;AAAA,MACX,OAAA,EAAU,YAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAe,eAAA,CAAgB,KAAA,EAAwB,MAAA,EAAoC;AACzF,IAAA,OAAO;AAAA,MACL,SAAY,KAAA,CAAM,MAAA;AAAA,MAClB,UAAA,EAAY,MAAM,IAAI,UAAA,CAAW,MAAM;AAAA,KACzC;AAAA,EACF;AAAA,EAEA,OAAe,sBAAsB,OAAA,EAAiD;AACpF,IAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,MAAA,EAAa,OAAA,CAAQ,MAAA,IAAU;AAAC,OAClC;AAAA,IACF;AAEA,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,WAAA,IAAe,OAAA,CAAQ,QAAA;AAC3C,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,UAAA,EAAY,CAAC,OAAA,KAAsC,OAAA,CAAQ,uBAAA,EAAwB;AAAA,QACnF,MAAA,EAAY,CAAC,GAAqC;AAAA,OACpD;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,OAAA,EAAU,0BAAA;AAAA,MACV,QAAA,EAAU,EAAE,OAAA,EAAS,EAAC;AAAE,KAC1B;AAAA,EACF;AACF;AAxEa,gBAAA,GAAN,eAAA,CAAA;AAAA,EADN,MAAA,CAAO,EAAE;AAAA,CAAA,EACG,gBAAA,CAAA;ACVN,IAAM,gBAAA,GAAmB,CAC9B,KAAA,KAC8B,MAAA,CAAO,MAAM,MAAM","file":"index.js","sourcesContent":["import { Module, DynamicModule, Provider } from '@nestjs/common';\nimport type { Type, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';\nimport { HttpClient } from '../core/http-client.js';\nimport type { HttpClientConfig, HttpClientToken } from '../core/types.js';\nimport type {\n HttpClientModuleOptions,\n HttpClientModuleAsyncOptions,\n HttpClientOptionsFactory,\n} from './http-client.options.js';\n\nconst HTTP_CLIENT_MODULE_OPTIONS = 'HTTP_CLIENT_MODULE_OPTIONS';\n\n@Module({})\nexport class HttpClientModule {\n static forRoot(options: HttpClientModuleOptions): DynamicModule {\n const providers: Provider[] = options.clients.map(({ token, config }) =>\n HttpClientModule._clientProvider(token, config),\n );\n\n return {\n module: HttpClientModule,\n providers,\n exports: providers,\n global: true,\n };\n }\n\n static forRootAsync(options: HttpClientModuleAsyncOptions): DynamicModule {\n const asyncProvider = HttpClientModule._asyncOptionsProvider(options);\n\n const clientsProvider: Provider = {\n provide: 'HTTP_CLIENT_INSTANCES',\n useFactory: (opts: HttpClientModuleOptions) => {\n return opts.clients.map(({ token, config }) => ({\n token,\n instance: new HttpClient(config),\n }));\n },\n inject: [HTTP_CLIENT_MODULE_OPTIONS],\n };\n\n const allProviders: Provider[] = [\n asyncProvider,\n clientsProvider,\n ];\n\n return {\n module: HttpClientModule,\n imports: options.imports ?? [],\n providers: allProviders,\n exports: allProviders,\n global: true,\n };\n }\n\n private static _clientProvider(token: HttpClientToken, config: HttpClientConfig): Provider {\n return {\n provide: token.symbol,\n useFactory: () => new HttpClient(config),\n };\n }\n\n private static _asyncOptionsProvider(options: HttpClientModuleAsyncOptions): Provider {\n if (options.useFactory) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: options.useFactory as (...args: unknown[]) => HttpClientModuleOptions | Promise<HttpClientModuleOptions>,\n inject: (options.inject ?? []) as (InjectionToken | OptionalFactoryDependency)[],\n };\n }\n\n const cls = options.useExisting ?? options.useClass;\n if (cls) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: (factory: HttpClientOptionsFactory) => factory.createHttpClientOptions(),\n inject: [cls as Type<HttpClientOptionsFactory>],\n };\n }\n\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useValue: { clients: [] } satisfies HttpClientModuleOptions,\n };\n }\n}\n","import { Inject } from '@nestjs/common';\nimport type { HttpClientToken } from '../core/types.js';\n\nexport const InjectHttpClient = (\n token: HttpClientToken,\n): ReturnType<typeof Inject> => Inject(token.symbol);\n"]}
1
+ {"version":3,"sources":["../../src/nestjs/http-client.module.ts","../../src/nestjs/http-client.decorator.ts"],"names":[],"mappings":";;;AAUA,IAAM,0BAAA,GAA6B,4BAAA;AAG5B,IAAM,mBAAN,MAAuB;AAAA,EAC5B,OAAO,QAAQ,OAAA,EAAiD;AAC9D,IAAA,MAAM,SAAA,GAAwB,QAAQ,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,EAAE,KAAA,EAAO,MAAA,OAC1D,gBAAA,CAAiB,eAAA,CAAgB,OAAO,MAAM;AAAA,KAChD;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAU,gBAAA;AAAA,MACV,SAAA;AAAA,MACA,OAAA,EAAU,SAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,OAAA,EAAsD;AACxE,IAAA,MAAM,aAAA,GAAgB,gBAAA,CAAiB,qBAAA,CAAsB,OAAO,CAAA;AAEpE,IAAA,MAAM,eAAA,GAA8B,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,CAAA,KAAA,MAAU;AAAA,MAChE,SAAY,KAAA,CAAM,MAAA;AAAA,MAClB,UAAA,EAAY,CAAC,IAAA,KAAkC;AAC7C,QAAA,MAAM,GAAA,GAAM,KAAK,OAAA,CAAQ,IAAA,CAAK,OAAK,CAAA,CAAE,KAAA,CAAM,MAAA,KAAW,KAAA,CAAM,MAAM,CAAA;AAClE,QAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA;AAAA,UAClB,CAAA,iCAAA,EAAoC,MAAM,WAAW,CAAA,gFAAA;AAAA,SAEvD;AACA,QAAA,OAAO,IAAI,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AAAA,MAClC,CAAA;AAAA,MACA,MAAA,EAAQ,CAAC,0BAA0B;AAAA,KACrC,CAAE,CAAA;AAEF,IAAA,MAAM,YAAA,GAA2B,CAAC,aAAA,EAAe,GAAG,eAAe,CAAA;AAEnE,IAAA,OAAO;AAAA,MACL,MAAA,EAAU,gBAAA;AAAA,MACV,OAAA,EAAU,OAAA,CAAQ,OAAA,IAAW,EAAC;AAAA,MAC9B,SAAA,EAAW,YAAA;AAAA,MACX,OAAA,EAAU,YAAA;AAAA,MACV,MAAA,EAAU;AAAA,KACZ;AAAA,EACF;AAAA,EAEA,OAAe,eAAA,CAAgB,KAAA,EAAwB,MAAA,EAAoC;AACzF,IAAA,OAAO;AAAA,MACL,SAAY,KAAA,CAAM,MAAA;AAAA,MAClB,UAAA,EAAY,MAAM,IAAI,UAAA,CAAW,MAAM;AAAA,KACzC;AAAA,EACF;AAAA,EAEA,OAAe,sBAAsB,OAAA,EAAiD;AACpF,IAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,MAAA,EAAa,OAAA,CAAQ,MAAA,IAAU;AAAC,OAClC;AAAA,IACF;AAEA,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,WAAA,IAAe,OAAA,CAAQ,QAAA;AAC3C,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,OAAO;AAAA,QACL,OAAA,EAAY,0BAAA;AAAA,QACZ,UAAA,EAAY,CAAC,OAAA,KAAsC,OAAA,CAAQ,uBAAA,EAAwB;AAAA,QACnF,MAAA,EAAY,CAAC,GAAqC;AAAA,OACpD;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,OAAA,EAAU,0BAAA;AAAA,MACV,QAAA,EAAU,EAAE,OAAA,EAAS,EAAC;AAAE,KAC1B;AAAA,EACF;AACF;AAvEa,gBAAA,GAAN,eAAA,CAAA;AAAA,EADN,MAAA,CAAO,EAAE;AAAA,CAAA,EACG,gBAAA,CAAA;ACVN,IAAM,gBAAA,GAAmB,CAC9B,KAAA,KAC8B,MAAA,CAAO,MAAM,MAAM","file":"index.js","sourcesContent":["import { Module, DynamicModule, Provider } from '@nestjs/common';\nimport type { Type, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';\nimport { HttpClient } from '../core/http-client.js';\nimport type { HttpClientConfig, HttpClientToken } from '../core/types.js';\nimport type {\n HttpClientModuleOptions,\n HttpClientModuleAsyncOptions,\n HttpClientOptionsFactory,\n} from './http-client.options.js';\n\nconst HTTP_CLIENT_MODULE_OPTIONS = 'HTTP_CLIENT_MODULE_OPTIONS';\n\n@Module({})\nexport class HttpClientModule {\n static forRoot(options: HttpClientModuleOptions): DynamicModule {\n const providers: Provider[] = options.clients.map(({ token, config }) =>\n HttpClientModule._clientProvider(token, config),\n );\n\n return {\n module: HttpClientModule,\n providers,\n exports: providers,\n global: true,\n };\n }\n\n static forRootAsync(options: HttpClientModuleAsyncOptions): DynamicModule {\n const asyncProvider = HttpClientModule._asyncOptionsProvider(options);\n\n const clientProviders: Provider[] = options.clients.map(token => ({\n provide: token.symbol,\n useFactory: (opts: HttpClientModuleOptions) => {\n const def = opts.clients.find(c => c.token.symbol === token.symbol);\n if (!def) throw new Error(\n `HttpClient config not found for '${token.description}'. ` +\n `The factory must return a config entry for every token declared in 'clients'.`,\n );\n return new HttpClient(def.config);\n },\n inject: [HTTP_CLIENT_MODULE_OPTIONS],\n }));\n\n const allProviders: Provider[] = [asyncProvider, ...clientProviders];\n\n return {\n module: HttpClientModule,\n imports: options.imports ?? [],\n providers: allProviders,\n exports: allProviders,\n global: true,\n };\n }\n\n private static _clientProvider(token: HttpClientToken, config: HttpClientConfig): Provider {\n return {\n provide: token.symbol,\n useFactory: () => new HttpClient(config),\n };\n }\n\n private static _asyncOptionsProvider(options: HttpClientModuleAsyncOptions): Provider {\n if (options.useFactory) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: options.useFactory as (...args: unknown[]) => HttpClientModuleOptions | Promise<HttpClientModuleOptions>,\n inject: (options.inject ?? []) as (InjectionToken | OptionalFactoryDependency)[],\n };\n }\n\n const cls = options.useExisting ?? options.useClass;\n if (cls) {\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useFactory: (factory: HttpClientOptionsFactory) => factory.createHttpClientOptions(),\n inject: [cls as Type<HttpClientOptionsFactory>],\n };\n }\n\n return {\n provide: HTTP_CLIENT_MODULE_OPTIONS,\n useValue: { clients: [] } satisfies HttpClientModuleOptions,\n };\n }\n}\n","import { Inject } from '@nestjs/common';\nimport type { HttpClientToken } from '../core/types.js';\n\nexport const InjectHttpClient = (\n token: HttpClientToken,\n): ReturnType<typeof Inject> => Inject(token.symbol);\n"]}
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@backendkit-labs/http-client",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "license": "Apache-2.0",
5
5
  "author": {
6
6
  "name": "BackendKit Labs",
7
- "email": "backendkit.dev@gmail.com"
7
+ "email": "hello@backendkitlabs.dev"
8
8
  },
9
9
  "description": "Production-grade HTTP client for Node.js — built on axios with circuit breaker, retry with backoff, request cancellation, typed Result responses, pipeline middleware, and optional NestJS integration",
10
10
  "type": "module",
@@ -50,14 +50,14 @@
50
50
  "node",
51
51
  "typescript"
52
52
  ],
53
- "homepage": "https://github.com/backendkit-dev/backendkit-monorepo/tree/master/packages/http-client#readme",
53
+ "homepage": "https://backendkitlabs.dev/docs/http-client/",
54
54
  "repository": {
55
55
  "type": "git",
56
- "url": "git+https://github.com/backendkit-dev/backendkit-monorepo.git",
56
+ "url": "git+https://github.com/BackendKit-labs/backendkit-monorepo.git",
57
57
  "directory": "packages/http-client"
58
58
  },
59
59
  "bugs": {
60
- "url": "https://github.com/backendkit-dev/backendkit-monorepo/issues"
60
+ "url": "https://github.com/BackendKit-labs/backendkit-monorepo/issues"
61
61
  },
62
62
  "publishConfig": {
63
63
  "access": "public"
@@ -103,4 +103,4 @@
103
103
  "typescript-eslint": "^8.59.3",
104
104
  "vitest": "^2.0.0"
105
105
  }
106
- }
106
+ }