@igniter-js/caller 0.1.3 → 0.1.4
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/AGENTS.md +2275 -172
- package/CHANGELOG.md +13 -0
- package/README.md +108 -14
- package/dist/adapters/index.d.mts +1 -0
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.js +91 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/index.mjs +89 -0
- package/dist/adapters/index.mjs.map +1 -0
- package/dist/index-COZVROi_.d.mts +121 -0
- package/dist/index-COZVROi_.d.ts +121 -0
- package/dist/index.d.mts +754 -280
- package/dist/index.d.ts +754 -280
- package/dist/index.js +992 -241
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +989 -242
- package/dist/index.mjs.map +1 -1
- package/dist/telemetry/index.d.mts +100 -0
- package/dist/telemetry/index.d.ts +100 -0
- package/dist/telemetry/index.js +54 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/index.mjs +52 -0
- package/dist/telemetry/index.mjs.map +1 -0
- package/package.json +24 -4
package/dist/index.mjs
CHANGED
|
@@ -1,110 +1,13 @@
|
|
|
1
1
|
import { IgniterError } from '@igniter-js/core';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
|
|
3
|
-
// src/
|
|
4
|
-
var
|
|
5
|
-
constructor(state, factory) {
|
|
6
|
-
this.state = state;
|
|
7
|
-
this.factory = factory;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Creates a new builder instance.
|
|
11
|
-
*/
|
|
12
|
-
static create(factory) {
|
|
13
|
-
return new _IgniterCallerBuilder({}, factory);
|
|
14
|
-
}
|
|
15
|
-
/** Sets the base URL for all requests. */
|
|
16
|
-
withBaseUrl(baseURL) {
|
|
17
|
-
return new _IgniterCallerBuilder({ ...this.state, baseURL }, this.factory);
|
|
18
|
-
}
|
|
19
|
-
/** Merges default headers for all requests. */
|
|
20
|
-
withHeaders(headers) {
|
|
21
|
-
return new _IgniterCallerBuilder({ ...this.state, headers }, this.factory);
|
|
22
|
-
}
|
|
23
|
-
/** Sets default cookies (sent as the `Cookie` header). */
|
|
24
|
-
withCookies(cookies) {
|
|
25
|
-
return new _IgniterCallerBuilder({ ...this.state, cookies }, this.factory);
|
|
26
|
-
}
|
|
27
|
-
/** Attaches a logger instance. */
|
|
28
|
-
withLogger(logger) {
|
|
29
|
-
return new _IgniterCallerBuilder({ ...this.state, logger }, this.factory);
|
|
30
|
-
}
|
|
31
|
-
/** Adds a request interceptor that runs before each request. */
|
|
32
|
-
withRequestInterceptor(interceptor) {
|
|
33
|
-
const requestInterceptors = [
|
|
34
|
-
...this.state.requestInterceptors || [],
|
|
35
|
-
interceptor
|
|
36
|
-
];
|
|
37
|
-
return new _IgniterCallerBuilder(
|
|
38
|
-
{ ...this.state, requestInterceptors },
|
|
39
|
-
this.factory
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
/** Adds a response interceptor that runs after each request. */
|
|
43
|
-
withResponseInterceptor(interceptor) {
|
|
44
|
-
const responseInterceptors = [
|
|
45
|
-
...this.state.responseInterceptors || [],
|
|
46
|
-
interceptor
|
|
47
|
-
];
|
|
48
|
-
return new _IgniterCallerBuilder(
|
|
49
|
-
{ ...this.state, responseInterceptors },
|
|
50
|
-
this.factory
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Configures a persistent store adapter for caching.
|
|
55
|
-
*
|
|
56
|
-
* When configured, cache operations will use the store (e.g., Redis)
|
|
57
|
-
* instead of in-memory cache, enabling persistent cache across deployments.
|
|
58
|
-
*/
|
|
59
|
-
withStore(store, options) {
|
|
60
|
-
return new _IgniterCallerBuilder(
|
|
61
|
-
{ ...this.state, store, storeOptions: options },
|
|
62
|
-
this.factory
|
|
63
|
-
);
|
|
64
|
-
}
|
|
4
|
+
// src/errors/caller.error.ts
|
|
5
|
+
var IgniterCallerError = class _IgniterCallerError extends IgniterError {
|
|
65
6
|
/**
|
|
66
|
-
*
|
|
7
|
+
* Creates a new typed caller error.
|
|
67
8
|
*
|
|
68
|
-
*
|
|
69
|
-
* route and method, with optional runtime validation via Zod.
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```ts
|
|
73
|
-
* const api = IgniterCaller.create()
|
|
74
|
-
* .withSchemas({
|
|
75
|
-
* '/users': {
|
|
76
|
-
* GET: {
|
|
77
|
-
* responses: {
|
|
78
|
-
* 200: z.array(UserSchema),
|
|
79
|
-
* 401: ErrorSchema,
|
|
80
|
-
* },
|
|
81
|
-
* },
|
|
82
|
-
* POST: {
|
|
83
|
-
* request: CreateUserSchema,
|
|
84
|
-
* responses: {
|
|
85
|
-
* 201: UserSchema,
|
|
86
|
-
* 400: ValidationErrorSchema,
|
|
87
|
-
* },
|
|
88
|
-
* },
|
|
89
|
-
* },
|
|
90
|
-
* })
|
|
91
|
-
* .build()
|
|
92
|
-
* ```
|
|
9
|
+
* @param payload - Error payload with code, message, and metadata.
|
|
93
10
|
*/
|
|
94
|
-
withSchemas(schemas, validation) {
|
|
95
|
-
return new _IgniterCallerBuilder(
|
|
96
|
-
{ ...this.state, schemas, schemaValidation: validation },
|
|
97
|
-
this.factory
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Builds the `IgniterCaller` instance.
|
|
102
|
-
*/
|
|
103
|
-
build() {
|
|
104
|
-
return this.factory(this.state);
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
var IgniterCallerError = class _IgniterCallerError extends IgniterError {
|
|
108
11
|
constructor(payload) {
|
|
109
12
|
const metadata = {
|
|
110
13
|
...payload.metadata,
|
|
@@ -119,13 +22,19 @@ var IgniterCallerError = class _IgniterCallerError extends IgniterError {
|
|
|
119
22
|
causer: "@igniter-js/caller",
|
|
120
23
|
details,
|
|
121
24
|
metadata,
|
|
122
|
-
logger: payload.logger
|
|
25
|
+
logger: payload.logger,
|
|
26
|
+
cause: payload.cause
|
|
123
27
|
});
|
|
124
28
|
this.name = "IgniterCallerError";
|
|
125
29
|
this.operation = payload.operation;
|
|
126
30
|
this.statusText = payload.statusText;
|
|
127
31
|
this.cause = payload.cause;
|
|
128
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Type guard for `IgniterCallerError`.
|
|
35
|
+
*
|
|
36
|
+
* @param error - Value to check.
|
|
37
|
+
*/
|
|
129
38
|
static is(error) {
|
|
130
39
|
return error instanceof _IgniterCallerError;
|
|
131
40
|
}
|
|
@@ -135,6 +44,9 @@ var IgniterCallerError = class _IgniterCallerError extends IgniterError {
|
|
|
135
44
|
var IgniterCallerBodyUtils = class {
|
|
136
45
|
/**
|
|
137
46
|
* Returns true when the request body should be passed to `fetch` as-is.
|
|
47
|
+
*
|
|
48
|
+
* @param body - Request body to inspect.
|
|
49
|
+
* @returns True if the body should be sent as raw data.
|
|
138
50
|
*/
|
|
139
51
|
static isRawBody(body) {
|
|
140
52
|
if (!body) return false;
|
|
@@ -153,6 +65,10 @@ var IgniterCallerBodyUtils = class {
|
|
|
153
65
|
}
|
|
154
66
|
/**
|
|
155
67
|
* Removes Content-Type for FormData so fetch can set boundaries automatically.
|
|
68
|
+
*
|
|
69
|
+
* @param headers - Request headers map.
|
|
70
|
+
* @param body - Request body.
|
|
71
|
+
* @returns Updated headers without Content-Type when needed.
|
|
156
72
|
*/
|
|
157
73
|
static normalizeHeadersForBody(headers, body) {
|
|
158
74
|
if (!headers) return headers;
|
|
@@ -171,6 +87,9 @@ var _IgniterCallerCacheUtils = class _IgniterCallerCacheUtils {
|
|
|
171
87
|
*
|
|
172
88
|
* When configured, cache operations will use the store (e.g., Redis)
|
|
173
89
|
* instead of in-memory cache, enabling persistent cache across deployments.
|
|
90
|
+
*
|
|
91
|
+
* @param store - Store adapter implementation.
|
|
92
|
+
* @param options - Store options such as ttl and key prefix.
|
|
174
93
|
*/
|
|
175
94
|
static setStore(store, options) {
|
|
176
95
|
_IgniterCallerCacheUtils.store = store;
|
|
@@ -183,12 +102,18 @@ var _IgniterCallerCacheUtils = class _IgniterCallerCacheUtils {
|
|
|
183
102
|
}
|
|
184
103
|
/**
|
|
185
104
|
* Gets the configured store adapter.
|
|
105
|
+
*
|
|
106
|
+
* @returns Store adapter or null when unset.
|
|
186
107
|
*/
|
|
187
108
|
static getStore() {
|
|
188
109
|
return _IgniterCallerCacheUtils.store;
|
|
189
110
|
}
|
|
190
111
|
/**
|
|
191
112
|
* Gets cached data if it exists and is not stale.
|
|
113
|
+
*
|
|
114
|
+
* @param key - Cache key (without prefix).
|
|
115
|
+
* @param staleTime - Optional stale time in milliseconds.
|
|
116
|
+
* @returns Cached value or undefined when missing/stale.
|
|
192
117
|
*/
|
|
193
118
|
static async get(key, staleTime) {
|
|
194
119
|
const prefixedKey = _IgniterCallerCacheUtils.getPrefixedKey(key);
|
|
@@ -212,6 +137,10 @@ var _IgniterCallerCacheUtils = class _IgniterCallerCacheUtils {
|
|
|
212
137
|
}
|
|
213
138
|
/**
|
|
214
139
|
* Stores data in cache with current timestamp.
|
|
140
|
+
*
|
|
141
|
+
* @param key - Cache key (without prefix).
|
|
142
|
+
* @param data - Data to cache.
|
|
143
|
+
* @param ttl - Optional TTL override in seconds.
|
|
215
144
|
*/
|
|
216
145
|
static async set(key, data, ttl) {
|
|
217
146
|
const prefixedKey = _IgniterCallerCacheUtils.getPrefixedKey(key);
|
|
@@ -233,6 +162,8 @@ var _IgniterCallerCacheUtils = class _IgniterCallerCacheUtils {
|
|
|
233
162
|
}
|
|
234
163
|
/**
|
|
235
164
|
* Clears a specific cache entry.
|
|
165
|
+
*
|
|
166
|
+
* @param key - Cache key (without prefix).
|
|
236
167
|
*/
|
|
237
168
|
static async clear(key) {
|
|
238
169
|
const prefixedKey = _IgniterCallerCacheUtils.getPrefixedKey(key);
|
|
@@ -266,6 +197,8 @@ var _IgniterCallerCacheUtils = class _IgniterCallerCacheUtils {
|
|
|
266
197
|
}
|
|
267
198
|
/**
|
|
268
199
|
* Clears all cache entries.
|
|
200
|
+
*
|
|
201
|
+
* @returns Promise that resolves when in-memory cache is cleared.
|
|
269
202
|
*/
|
|
270
203
|
static async clearAll() {
|
|
271
204
|
_IgniterCallerCacheUtils.cache.clear();
|
|
@@ -304,6 +237,10 @@ var IgniterCallerSchemaUtils = class _IgniterCallerSchemaUtils {
|
|
|
304
237
|
/**
|
|
305
238
|
* Matches a URL path against schema map paths (supports path parameters).
|
|
306
239
|
*
|
|
240
|
+
* @param actualPath - Incoming request path.
|
|
241
|
+
* @param schemaPath - Schema path pattern.
|
|
242
|
+
* @returns Match result with params when matched.
|
|
243
|
+
*
|
|
307
244
|
* @example
|
|
308
245
|
* ```ts
|
|
309
246
|
* matchPath('/users/123', '/users/:id') // { matched: true, params: { id: '123' } }
|
|
@@ -332,6 +269,11 @@ var IgniterCallerSchemaUtils = class _IgniterCallerSchemaUtils {
|
|
|
332
269
|
}
|
|
333
270
|
/**
|
|
334
271
|
* Finds the schema for a given path and method from the schema map.
|
|
272
|
+
*
|
|
273
|
+
* @param schemaMap - Schema map from the builder.
|
|
274
|
+
* @param path - Request path to match.
|
|
275
|
+
* @param method - HTTP method to match.
|
|
276
|
+
* @returns Matching schema and extracted params.
|
|
335
277
|
*/
|
|
336
278
|
static findSchema(schemaMap, path, method) {
|
|
337
279
|
if (!schemaMap) {
|
|
@@ -357,6 +299,10 @@ var IgniterCallerSchemaUtils = class _IgniterCallerSchemaUtils {
|
|
|
357
299
|
*
|
|
358
300
|
* If the schema provides `~standard.validate`, it will be used.
|
|
359
301
|
* Otherwise, returns the input as-is.
|
|
302
|
+
*
|
|
303
|
+
* @param schema - StandardSchema instance.
|
|
304
|
+
* @param input - Input value to validate.
|
|
305
|
+
* @returns Validated input value.
|
|
360
306
|
*/
|
|
361
307
|
static async validateWithStandardSchema(schema, input) {
|
|
362
308
|
const standard = schema?.["~standard"];
|
|
@@ -375,7 +321,12 @@ var IgniterCallerSchemaUtils = class _IgniterCallerSchemaUtils {
|
|
|
375
321
|
/**
|
|
376
322
|
* Validates request body against schema.
|
|
377
323
|
*
|
|
378
|
-
* @
|
|
324
|
+
* @param data - Request body data.
|
|
325
|
+
* @param schema - Request schema (if any).
|
|
326
|
+
* @param options - Validation options.
|
|
327
|
+
* @param context - Request context for error reporting.
|
|
328
|
+
* @param logger - Optional logger instance.
|
|
329
|
+
* @returns Validated data or throws/logs error based on validation mode.
|
|
379
330
|
*/
|
|
380
331
|
static async validateRequest(data, schema, options, context, logger) {
|
|
381
332
|
if (!schema || options?.mode === "off") {
|
|
@@ -408,7 +359,13 @@ var IgniterCallerSchemaUtils = class _IgniterCallerSchemaUtils {
|
|
|
408
359
|
/**
|
|
409
360
|
* Validates response data against schema.
|
|
410
361
|
*
|
|
411
|
-
* @
|
|
362
|
+
* @param data - Response payload to validate.
|
|
363
|
+
* @param schema - Response schema (if any).
|
|
364
|
+
* @param statusCode - HTTP status code.
|
|
365
|
+
* @param options - Validation options.
|
|
366
|
+
* @param context - Request context for error reporting.
|
|
367
|
+
* @param logger - Optional logger instance.
|
|
368
|
+
* @returns Validated data or throws/logs error based on validation mode.
|
|
412
369
|
*/
|
|
413
370
|
static async validateResponse(data, schema, statusCode, options, context, logger) {
|
|
414
371
|
if (!schema || options?.mode === "off") {
|
|
@@ -443,6 +400,12 @@ var IgniterCallerSchemaUtils = class _IgniterCallerSchemaUtils {
|
|
|
443
400
|
|
|
444
401
|
// src/utils/url.ts
|
|
445
402
|
var IgniterCallerUrlUtils = class {
|
|
403
|
+
/**
|
|
404
|
+
* Builds a full URL with optional base URL and query parameters.
|
|
405
|
+
*
|
|
406
|
+
* @param params - URL construction parameters.
|
|
407
|
+
* @returns Full URL string.
|
|
408
|
+
*/
|
|
446
409
|
static buildUrl(params) {
|
|
447
410
|
const { url, baseURL, query } = params;
|
|
448
411
|
let fullUrl = url;
|
|
@@ -459,7 +422,7 @@ var IgniterCallerUrlUtils = class {
|
|
|
459
422
|
}
|
|
460
423
|
};
|
|
461
424
|
|
|
462
|
-
// src/
|
|
425
|
+
// src/builders/request.builder.ts
|
|
463
426
|
var VALIDATABLE_CONTENT_TYPES = [
|
|
464
427
|
"json",
|
|
465
428
|
"xml",
|
|
@@ -507,6 +470,11 @@ async function parseResponseByContentType(response, contentType) {
|
|
|
507
470
|
}
|
|
508
471
|
}
|
|
509
472
|
var IgniterCallerRequestBuilder = class {
|
|
473
|
+
/**
|
|
474
|
+
* Creates a new request builder instance.
|
|
475
|
+
*
|
|
476
|
+
* @param params - Builder configuration from the manager.
|
|
477
|
+
*/
|
|
510
478
|
constructor(params) {
|
|
511
479
|
this.options = {
|
|
512
480
|
method: "GET",
|
|
@@ -529,6 +497,7 @@ var IgniterCallerRequestBuilder = class {
|
|
|
529
497
|
this.options.headers = { ...this.options.headers, Cookie: cookieStr };
|
|
530
498
|
}
|
|
531
499
|
this.logger = params.logger;
|
|
500
|
+
this.telemetry = params.telemetry;
|
|
532
501
|
this.requestInterceptors = params.requestInterceptors;
|
|
533
502
|
this.responseInterceptors = params.responseInterceptors;
|
|
534
503
|
this.eventEmitter = params.eventEmitter;
|
|
@@ -538,6 +507,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
538
507
|
/**
|
|
539
508
|
* Sets the HTTP method for this request.
|
|
540
509
|
* @internal Used by IgniterCaller.request() for generic requests.
|
|
510
|
+
*
|
|
511
|
+
* @param method - HTTP method for the request.
|
|
541
512
|
*/
|
|
542
513
|
_setMethod(method) {
|
|
543
514
|
this.options.method = method;
|
|
@@ -546,6 +517,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
546
517
|
/**
|
|
547
518
|
* Sets the URL for this request.
|
|
548
519
|
* @internal Used when URL is passed to HTTP method directly.
|
|
520
|
+
*
|
|
521
|
+
* @param url - Request URL or path.
|
|
549
522
|
*/
|
|
550
523
|
_setUrl(url) {
|
|
551
524
|
this.options.url = url;
|
|
@@ -553,6 +526,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
553
526
|
}
|
|
554
527
|
/**
|
|
555
528
|
* Overrides the logger for this request chain.
|
|
529
|
+
*
|
|
530
|
+
* @param logger - Logger implementation from `@igniter-js/core`.
|
|
556
531
|
*/
|
|
557
532
|
withLogger(logger) {
|
|
558
533
|
this.logger = logger;
|
|
@@ -560,6 +535,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
560
535
|
}
|
|
561
536
|
/**
|
|
562
537
|
* Sets the request URL.
|
|
538
|
+
*
|
|
539
|
+
* @param url - Request URL or path.
|
|
563
540
|
*/
|
|
564
541
|
url(url) {
|
|
565
542
|
this.options.url = url;
|
|
@@ -568,6 +545,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
568
545
|
/**
|
|
569
546
|
* Sets the request body.
|
|
570
547
|
* For GET/HEAD requests, body will be automatically converted to query params.
|
|
548
|
+
*
|
|
549
|
+
* @param body - Body payload for the request.
|
|
571
550
|
*/
|
|
572
551
|
body(body) {
|
|
573
552
|
this.options.body = body;
|
|
@@ -575,6 +554,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
575
554
|
}
|
|
576
555
|
/**
|
|
577
556
|
* Sets URL query parameters.
|
|
557
|
+
*
|
|
558
|
+
* @param params - Query string parameters.
|
|
578
559
|
*/
|
|
579
560
|
params(params) {
|
|
580
561
|
this.options.params = params;
|
|
@@ -582,6 +563,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
582
563
|
}
|
|
583
564
|
/**
|
|
584
565
|
* Merges additional headers into the request.
|
|
566
|
+
*
|
|
567
|
+
* @param headers - Header map merged into existing headers.
|
|
585
568
|
*/
|
|
586
569
|
headers(headers) {
|
|
587
570
|
this.options.headers = { ...this.options.headers, ...headers };
|
|
@@ -589,6 +572,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
589
572
|
}
|
|
590
573
|
/**
|
|
591
574
|
* Sets request timeout in milliseconds.
|
|
575
|
+
*
|
|
576
|
+
* @param timeout - Timeout in milliseconds.
|
|
592
577
|
*/
|
|
593
578
|
timeout(timeout) {
|
|
594
579
|
this.options.timeout = timeout;
|
|
@@ -596,6 +581,9 @@ var IgniterCallerRequestBuilder = class {
|
|
|
596
581
|
}
|
|
597
582
|
/**
|
|
598
583
|
* Sets cache strategy and optional cache key.
|
|
584
|
+
*
|
|
585
|
+
* @param cache - Cache strategy for the request.
|
|
586
|
+
* @param key - Optional cache key override.
|
|
599
587
|
*/
|
|
600
588
|
cache(cache, key) {
|
|
601
589
|
this.options.cache = cache;
|
|
@@ -604,6 +592,9 @@ var IgniterCallerRequestBuilder = class {
|
|
|
604
592
|
}
|
|
605
593
|
/**
|
|
606
594
|
* Configures retry behavior for failed requests.
|
|
595
|
+
*
|
|
596
|
+
* @param maxAttempts - Maximum number of attempts.
|
|
597
|
+
* @param options - Retry options excluding `maxAttempts`.
|
|
607
598
|
*/
|
|
608
599
|
retry(maxAttempts, options) {
|
|
609
600
|
this.retryOptions = { maxAttempts, ...options };
|
|
@@ -611,6 +602,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
611
602
|
}
|
|
612
603
|
/**
|
|
613
604
|
* Provides a fallback value if the request fails.
|
|
605
|
+
*
|
|
606
|
+
* @param fn - Fallback factory called when the request fails.
|
|
614
607
|
*/
|
|
615
608
|
fallback(fn) {
|
|
616
609
|
this.fallbackFn = fn;
|
|
@@ -618,6 +611,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
618
611
|
}
|
|
619
612
|
/**
|
|
620
613
|
* Sets cache stale time in milliseconds.
|
|
614
|
+
*
|
|
615
|
+
* @param milliseconds - Stale time in milliseconds.
|
|
621
616
|
*/
|
|
622
617
|
stale(milliseconds) {
|
|
623
618
|
this.staleTime = milliseconds;
|
|
@@ -631,6 +626,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
631
626
|
*
|
|
632
627
|
* The actual parsing is based on Content-Type headers, not this setting.
|
|
633
628
|
*
|
|
629
|
+
* @param schema - Zod/StandardSchema instance for validation (optional).
|
|
630
|
+
*
|
|
634
631
|
* @example
|
|
635
632
|
* ```ts
|
|
636
633
|
* // With Zod schema (validates JSON response)
|
|
@@ -649,6 +646,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
649
646
|
/**
|
|
650
647
|
* Downloads a file via GET request.
|
|
651
648
|
* @deprecated Use `.responseType<File>().execute()` instead. The response type is auto-detected.
|
|
649
|
+
*
|
|
650
|
+
* @param url - URL or path to download.
|
|
652
651
|
*/
|
|
653
652
|
getFile(url) {
|
|
654
653
|
this.options.method = "GET";
|
|
@@ -723,7 +722,7 @@ var IgniterCallerRequestBuilder = class {
|
|
|
723
722
|
statusCode: 408,
|
|
724
723
|
logger: this.logger,
|
|
725
724
|
metadata: { url: finalUrl },
|
|
726
|
-
cause: error
|
|
725
|
+
cause: error instanceof Error ? error : void 0
|
|
727
726
|
})
|
|
728
727
|
};
|
|
729
728
|
}
|
|
@@ -735,7 +734,7 @@ var IgniterCallerRequestBuilder = class {
|
|
|
735
734
|
message: error?.message || "Failed to download file",
|
|
736
735
|
logger: this.logger,
|
|
737
736
|
metadata: { url: finalUrl },
|
|
738
|
-
cause: error
|
|
737
|
+
cause: error instanceof Error ? error : void 0
|
|
739
738
|
})
|
|
740
739
|
};
|
|
741
740
|
}
|
|
@@ -754,8 +753,32 @@ var IgniterCallerRequestBuilder = class {
|
|
|
754
753
|
* - `application/octet-stream` → returned as Blob
|
|
755
754
|
*
|
|
756
755
|
* Schema validation (if configured) only runs for validatable content types (JSON, XML, CSV).
|
|
756
|
+
*
|
|
757
|
+
* @returns Response envelope with data or error.
|
|
757
758
|
*/
|
|
758
759
|
async execute() {
|
|
760
|
+
const startTime = Date.now();
|
|
761
|
+
const { safeUrl } = this.resolveUrl();
|
|
762
|
+
const method = this.options.method;
|
|
763
|
+
const baseURL = this.options.baseURL;
|
|
764
|
+
const timeoutMs = this.options.timeout;
|
|
765
|
+
this.telemetry?.emit(
|
|
766
|
+
"igniter.caller.request.execute.started",
|
|
767
|
+
{
|
|
768
|
+
level: "debug",
|
|
769
|
+
attributes: {
|
|
770
|
+
"ctx.request.method": method,
|
|
771
|
+
"ctx.request.url": safeUrl,
|
|
772
|
+
"ctx.request.baseUrl": baseURL,
|
|
773
|
+
"ctx.request.timeoutMs": timeoutMs
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
);
|
|
777
|
+
this.logger?.debug("IgniterCaller.request.execute started", {
|
|
778
|
+
method,
|
|
779
|
+
url: safeUrl,
|
|
780
|
+
baseURL
|
|
781
|
+
});
|
|
759
782
|
const effectiveCacheKey = this.cacheKey || this.options.url;
|
|
760
783
|
if (effectiveCacheKey && this.staleTime) {
|
|
761
784
|
const cached = await IgniterCallerCacheUtils.get(
|
|
@@ -763,8 +786,36 @@ var IgniterCallerRequestBuilder = class {
|
|
|
763
786
|
this.staleTime
|
|
764
787
|
);
|
|
765
788
|
if (cached !== void 0) {
|
|
766
|
-
this.
|
|
767
|
-
|
|
789
|
+
this.telemetry?.emit(
|
|
790
|
+
"igniter.caller.cache.read.hit",
|
|
791
|
+
{
|
|
792
|
+
level: "debug",
|
|
793
|
+
attributes: {
|
|
794
|
+
"ctx.request.method": method,
|
|
795
|
+
"ctx.request.url": safeUrl,
|
|
796
|
+
"ctx.cache.key": effectiveCacheKey,
|
|
797
|
+
"ctx.cache.staleTime": this.staleTime
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
);
|
|
801
|
+
const durationMs2 = Date.now() - startTime;
|
|
802
|
+
this.telemetry?.emit(
|
|
803
|
+
"igniter.caller.request.execute.success",
|
|
804
|
+
{
|
|
805
|
+
level: "info",
|
|
806
|
+
attributes: {
|
|
807
|
+
"ctx.request.method": method,
|
|
808
|
+
"ctx.request.url": safeUrl,
|
|
809
|
+
"ctx.request.durationMs": durationMs2,
|
|
810
|
+
"ctx.cache.hit": true
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
);
|
|
814
|
+
this.logger?.info("IgniterCaller.request.execute success (cache)", {
|
|
815
|
+
key: effectiveCacheKey,
|
|
816
|
+
method,
|
|
817
|
+
url: safeUrl,
|
|
818
|
+
durationMs: durationMs2
|
|
768
819
|
});
|
|
769
820
|
const cachedResult = {
|
|
770
821
|
data: cached,
|
|
@@ -776,13 +827,33 @@ var IgniterCallerRequestBuilder = class {
|
|
|
776
827
|
}
|
|
777
828
|
const result = await this.executeWithRetry();
|
|
778
829
|
if (result.error && this.fallbackFn) {
|
|
779
|
-
this.logger?.debug("IgniterCaller.execute applying fallback", {
|
|
830
|
+
this.logger?.debug("IgniterCaller.request.execute applying fallback", {
|
|
831
|
+
method,
|
|
832
|
+
url: safeUrl,
|
|
780
833
|
error: result.error
|
|
781
834
|
});
|
|
782
835
|
const fallbackResult = {
|
|
783
836
|
data: this.fallbackFn(),
|
|
784
837
|
error: void 0
|
|
785
838
|
};
|
|
839
|
+
const durationMs2 = Date.now() - startTime;
|
|
840
|
+
this.telemetry?.emit(
|
|
841
|
+
"igniter.caller.request.execute.success",
|
|
842
|
+
{
|
|
843
|
+
level: "info",
|
|
844
|
+
attributes: {
|
|
845
|
+
"ctx.request.method": method,
|
|
846
|
+
"ctx.request.url": safeUrl,
|
|
847
|
+
"ctx.request.durationMs": durationMs2,
|
|
848
|
+
"ctx.request.fallback": true
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
);
|
|
852
|
+
this.logger?.info("IgniterCaller.request.execute success (fallback)", {
|
|
853
|
+
method,
|
|
854
|
+
url: safeUrl,
|
|
855
|
+
durationMs: durationMs2
|
|
856
|
+
});
|
|
786
857
|
await this.emitEvent(fallbackResult);
|
|
787
858
|
return fallbackResult;
|
|
788
859
|
}
|
|
@@ -793,12 +864,57 @@ var IgniterCallerRequestBuilder = class {
|
|
|
793
864
|
this.staleTime
|
|
794
865
|
);
|
|
795
866
|
}
|
|
867
|
+
const durationMs = Date.now() - startTime;
|
|
868
|
+
if (result.error) {
|
|
869
|
+
this.telemetry?.emit(
|
|
870
|
+
"igniter.caller.request.execute.error",
|
|
871
|
+
{
|
|
872
|
+
level: "error",
|
|
873
|
+
attributes: {
|
|
874
|
+
"ctx.request.method": method,
|
|
875
|
+
"ctx.request.url": safeUrl,
|
|
876
|
+
"ctx.request.durationMs": durationMs,
|
|
877
|
+
"ctx.error.code": result.error instanceof IgniterCallerError ? result.error.code : "IGNITER_CALLER_UNKNOWN_ERROR",
|
|
878
|
+
"ctx.error.message": result.error.message,
|
|
879
|
+
"ctx.response.status": result.status
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
);
|
|
883
|
+
this.logger?.error("IgniterCaller.request.execute failed", {
|
|
884
|
+
method,
|
|
885
|
+
url: safeUrl,
|
|
886
|
+
durationMs,
|
|
887
|
+
error: result.error
|
|
888
|
+
});
|
|
889
|
+
} else {
|
|
890
|
+
const contentType = result.headers?.get("content-type") || void 0;
|
|
891
|
+
this.telemetry?.emit(
|
|
892
|
+
"igniter.caller.request.execute.success",
|
|
893
|
+
{
|
|
894
|
+
level: "info",
|
|
895
|
+
attributes: {
|
|
896
|
+
"ctx.request.method": method,
|
|
897
|
+
"ctx.request.url": safeUrl,
|
|
898
|
+
"ctx.request.durationMs": durationMs,
|
|
899
|
+
"ctx.response.status": result.status,
|
|
900
|
+
"ctx.response.contentType": contentType,
|
|
901
|
+
"ctx.cache.hit": false
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
);
|
|
905
|
+
this.logger?.info("IgniterCaller.request.execute success", {
|
|
906
|
+
method,
|
|
907
|
+
url: safeUrl,
|
|
908
|
+
durationMs,
|
|
909
|
+
status: result.status
|
|
910
|
+
});
|
|
911
|
+
}
|
|
796
912
|
await this.emitEvent(result);
|
|
797
913
|
return result;
|
|
798
914
|
}
|
|
799
915
|
async executeWithRetry() {
|
|
800
916
|
const maxAttempts = this.retryOptions?.maxAttempts || 1;
|
|
801
|
-
const baseDelay = this.retryOptions?.baseDelay
|
|
917
|
+
const baseDelay = this.retryOptions?.baseDelay ?? 1e3;
|
|
802
918
|
const backoff = this.retryOptions?.backoff || "linear";
|
|
803
919
|
const retryOnStatus = this.retryOptions?.retryOnStatus || [
|
|
804
920
|
408,
|
|
@@ -808,13 +924,30 @@ var IgniterCallerRequestBuilder = class {
|
|
|
808
924
|
503,
|
|
809
925
|
504
|
|
810
926
|
];
|
|
927
|
+
const { safeUrl } = this.resolveUrl();
|
|
928
|
+
const method = this.options.method;
|
|
811
929
|
let lastError;
|
|
812
930
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
813
931
|
if (attempt > 0) {
|
|
814
932
|
const delay = backoff === "exponential" ? baseDelay * 2 ** (attempt - 1) : baseDelay * attempt;
|
|
815
|
-
this.
|
|
816
|
-
attempt,
|
|
817
|
-
|
|
933
|
+
this.telemetry?.emit(
|
|
934
|
+
"igniter.caller.retry.attempt.started",
|
|
935
|
+
{
|
|
936
|
+
level: "debug",
|
|
937
|
+
attributes: {
|
|
938
|
+
"ctx.request.method": method,
|
|
939
|
+
"ctx.request.url": safeUrl,
|
|
940
|
+
"ctx.retry.attempt": attempt + 1,
|
|
941
|
+
"ctx.retry.maxAttempts": maxAttempts,
|
|
942
|
+
"ctx.retry.delayMs": delay
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
);
|
|
946
|
+
this.logger?.debug("IgniterCaller.request.execute retrying", {
|
|
947
|
+
method,
|
|
948
|
+
url: safeUrl,
|
|
949
|
+
attempt: attempt + 1,
|
|
950
|
+
delayMs: delay
|
|
818
951
|
});
|
|
819
952
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
820
953
|
}
|
|
@@ -835,10 +968,8 @@ var IgniterCallerRequestBuilder = class {
|
|
|
835
968
|
}
|
|
836
969
|
async executeSingleRequest() {
|
|
837
970
|
let { url, requestInit, controller, timeoutId } = this.buildRequest();
|
|
838
|
-
this.
|
|
839
|
-
|
|
840
|
-
url
|
|
841
|
-
});
|
|
971
|
+
const { safeUrl } = this.resolveUrl();
|
|
972
|
+
const method = this.options.method;
|
|
842
973
|
if (this.requestInterceptors && this.requestInterceptors.length > 0) {
|
|
843
974
|
let modifiedOptions = { ...this.options, url };
|
|
844
975
|
for (const interceptor of this.requestInterceptors) {
|
|
@@ -868,9 +999,27 @@ var IgniterCallerRequestBuilder = class {
|
|
|
868
999
|
);
|
|
869
1000
|
} catch (error) {
|
|
870
1001
|
clearTimeout(timeoutId);
|
|
1002
|
+
const err = error;
|
|
1003
|
+
this.telemetry?.emit(
|
|
1004
|
+
"igniter.caller.validation.request.error",
|
|
1005
|
+
{
|
|
1006
|
+
level: "error",
|
|
1007
|
+
attributes: {
|
|
1008
|
+
"ctx.request.method": method,
|
|
1009
|
+
"ctx.request.url": safeUrl,
|
|
1010
|
+
"ctx.validation.type": "request",
|
|
1011
|
+
"ctx.validation.error": err.message
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
);
|
|
1015
|
+
this.logger?.error("IgniterCaller.request.validation failed", {
|
|
1016
|
+
method,
|
|
1017
|
+
url: safeUrl,
|
|
1018
|
+
error: err
|
|
1019
|
+
});
|
|
871
1020
|
return {
|
|
872
1021
|
data: void 0,
|
|
873
|
-
error
|
|
1022
|
+
error: err
|
|
874
1023
|
};
|
|
875
1024
|
}
|
|
876
1025
|
}
|
|
@@ -924,9 +1073,29 @@ var IgniterCallerRequestBuilder = class {
|
|
|
924
1073
|
this.logger
|
|
925
1074
|
);
|
|
926
1075
|
} catch (error) {
|
|
1076
|
+
const err = error;
|
|
1077
|
+
this.telemetry?.emit(
|
|
1078
|
+
"igniter.caller.validation.response.error",
|
|
1079
|
+
{
|
|
1080
|
+
level: "error",
|
|
1081
|
+
attributes: {
|
|
1082
|
+
"ctx.request.method": method,
|
|
1083
|
+
"ctx.request.url": safeUrl,
|
|
1084
|
+
"ctx.validation.type": "response",
|
|
1085
|
+
"ctx.validation.error": err.message,
|
|
1086
|
+
"ctx.response.status": httpResponse.status
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
);
|
|
1090
|
+
this.logger?.error("IgniterCaller.response.validation failed", {
|
|
1091
|
+
method,
|
|
1092
|
+
url: safeUrl,
|
|
1093
|
+
status: httpResponse.status,
|
|
1094
|
+
error: err
|
|
1095
|
+
});
|
|
927
1096
|
return {
|
|
928
1097
|
data: void 0,
|
|
929
|
-
error,
|
|
1098
|
+
error: err,
|
|
930
1099
|
status: httpResponse.status,
|
|
931
1100
|
headers: httpResponse.headers
|
|
932
1101
|
};
|
|
@@ -938,20 +1107,40 @@ var IgniterCallerRequestBuilder = class {
|
|
|
938
1107
|
const zodSchema = this.responseTypeSchema;
|
|
939
1108
|
const result = zodSchema.safeParse(data);
|
|
940
1109
|
if (!result.success) {
|
|
1110
|
+
const err = new IgniterCallerError({
|
|
1111
|
+
code: "IGNITER_CALLER_RESPONSE_VALIDATION_FAILED",
|
|
1112
|
+
operation: "parseResponse",
|
|
1113
|
+
message: `Response validation failed: ${result.error.message}`,
|
|
1114
|
+
logger: this.logger,
|
|
1115
|
+
statusCode: httpResponse.status,
|
|
1116
|
+
metadata: {
|
|
1117
|
+
method: this.options.method,
|
|
1118
|
+
url
|
|
1119
|
+
},
|
|
1120
|
+
cause: result.error
|
|
1121
|
+
});
|
|
1122
|
+
this.telemetry?.emit(
|
|
1123
|
+
"igniter.caller.validation.response.error",
|
|
1124
|
+
{
|
|
1125
|
+
level: "error",
|
|
1126
|
+
attributes: {
|
|
1127
|
+
"ctx.request.method": method,
|
|
1128
|
+
"ctx.request.url": safeUrl,
|
|
1129
|
+
"ctx.validation.type": "response",
|
|
1130
|
+
"ctx.validation.error": err.message,
|
|
1131
|
+
"ctx.response.status": httpResponse.status
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
);
|
|
1135
|
+
this.logger?.error("IgniterCaller.response.validation failed", {
|
|
1136
|
+
method,
|
|
1137
|
+
url: safeUrl,
|
|
1138
|
+
status: httpResponse.status,
|
|
1139
|
+
error: err
|
|
1140
|
+
});
|
|
941
1141
|
return {
|
|
942
1142
|
data: void 0,
|
|
943
|
-
error:
|
|
944
|
-
code: "IGNITER_CALLER_RESPONSE_VALIDATION_FAILED",
|
|
945
|
-
operation: "parseResponse",
|
|
946
|
-
message: `Response validation failed: ${result.error.message}`,
|
|
947
|
-
logger: this.logger,
|
|
948
|
-
statusCode: httpResponse.status,
|
|
949
|
-
metadata: {
|
|
950
|
-
method: this.options.method,
|
|
951
|
-
url
|
|
952
|
-
},
|
|
953
|
-
cause: result.error
|
|
954
|
-
}),
|
|
1143
|
+
error: err,
|
|
955
1144
|
status: httpResponse.status,
|
|
956
1145
|
headers: httpResponse.headers
|
|
957
1146
|
};
|
|
@@ -962,40 +1151,80 @@ var IgniterCallerRequestBuilder = class {
|
|
|
962
1151
|
const standardSchema = this.responseTypeSchema;
|
|
963
1152
|
const result = await standardSchema["~standard"].validate(data);
|
|
964
1153
|
if (result.issues) {
|
|
1154
|
+
const err = new IgniterCallerError({
|
|
1155
|
+
code: "IGNITER_CALLER_RESPONSE_VALIDATION_FAILED",
|
|
1156
|
+
operation: "parseResponse",
|
|
1157
|
+
message: `Response validation failed`,
|
|
1158
|
+
logger: this.logger,
|
|
1159
|
+
statusCode: httpResponse.status,
|
|
1160
|
+
metadata: {
|
|
1161
|
+
method: this.options.method,
|
|
1162
|
+
url,
|
|
1163
|
+
issues: result.issues
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
this.telemetry?.emit(
|
|
1167
|
+
"igniter.caller.validation.response.error",
|
|
1168
|
+
{
|
|
1169
|
+
level: "error",
|
|
1170
|
+
attributes: {
|
|
1171
|
+
"ctx.request.method": method,
|
|
1172
|
+
"ctx.request.url": safeUrl,
|
|
1173
|
+
"ctx.validation.type": "response",
|
|
1174
|
+
"ctx.validation.error": err.message,
|
|
1175
|
+
"ctx.response.status": httpResponse.status
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
);
|
|
1179
|
+
this.logger?.error("IgniterCaller.response.validation failed", {
|
|
1180
|
+
method,
|
|
1181
|
+
url: safeUrl,
|
|
1182
|
+
status: httpResponse.status,
|
|
1183
|
+
error: err
|
|
1184
|
+
});
|
|
965
1185
|
return {
|
|
966
1186
|
data: void 0,
|
|
967
|
-
error:
|
|
968
|
-
code: "IGNITER_CALLER_RESPONSE_VALIDATION_FAILED",
|
|
969
|
-
operation: "parseResponse",
|
|
970
|
-
message: `Response validation failed`,
|
|
971
|
-
logger: this.logger,
|
|
972
|
-
statusCode: httpResponse.status,
|
|
973
|
-
metadata: {
|
|
974
|
-
method: this.options.method,
|
|
975
|
-
url,
|
|
976
|
-
issues: result.issues
|
|
977
|
-
}
|
|
978
|
-
}),
|
|
1187
|
+
error: err,
|
|
979
1188
|
status: httpResponse.status,
|
|
980
1189
|
headers: httpResponse.headers
|
|
981
1190
|
};
|
|
982
1191
|
}
|
|
983
1192
|
data = result.value;
|
|
984
1193
|
} catch (error) {
|
|
1194
|
+
const err = new IgniterCallerError({
|
|
1195
|
+
code: "IGNITER_CALLER_RESPONSE_VALIDATION_FAILED",
|
|
1196
|
+
operation: "parseResponse",
|
|
1197
|
+
message: error?.message || "Response validation failed",
|
|
1198
|
+
logger: this.logger,
|
|
1199
|
+
statusCode: httpResponse.status,
|
|
1200
|
+
metadata: {
|
|
1201
|
+
method: this.options.method,
|
|
1202
|
+
url
|
|
1203
|
+
},
|
|
1204
|
+
cause: error instanceof Error ? error : void 0
|
|
1205
|
+
});
|
|
1206
|
+
this.telemetry?.emit(
|
|
1207
|
+
"igniter.caller.validation.response.error",
|
|
1208
|
+
{
|
|
1209
|
+
level: "error",
|
|
1210
|
+
attributes: {
|
|
1211
|
+
"ctx.request.method": method,
|
|
1212
|
+
"ctx.request.url": safeUrl,
|
|
1213
|
+
"ctx.validation.type": "response",
|
|
1214
|
+
"ctx.validation.error": err.message,
|
|
1215
|
+
"ctx.response.status": httpResponse.status
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
);
|
|
1219
|
+
this.logger?.error("IgniterCaller.response.validation failed", {
|
|
1220
|
+
method,
|
|
1221
|
+
url: safeUrl,
|
|
1222
|
+
status: httpResponse.status,
|
|
1223
|
+
error: err
|
|
1224
|
+
});
|
|
985
1225
|
return {
|
|
986
1226
|
data: void 0,
|
|
987
|
-
error:
|
|
988
|
-
code: "IGNITER_CALLER_RESPONSE_VALIDATION_FAILED",
|
|
989
|
-
operation: "parseResponse",
|
|
990
|
-
message: error?.message || "Response validation failed",
|
|
991
|
-
logger: this.logger,
|
|
992
|
-
statusCode: httpResponse.status,
|
|
993
|
-
metadata: {
|
|
994
|
-
method: this.options.method,
|
|
995
|
-
url
|
|
996
|
-
},
|
|
997
|
-
cause: error
|
|
998
|
-
}),
|
|
1227
|
+
error: err,
|
|
999
1228
|
status: httpResponse.status,
|
|
1000
1229
|
headers: httpResponse.headers
|
|
1001
1230
|
};
|
|
@@ -1018,20 +1247,38 @@ var IgniterCallerRequestBuilder = class {
|
|
|
1018
1247
|
} catch (error) {
|
|
1019
1248
|
clearTimeout(timeoutId);
|
|
1020
1249
|
if (error instanceof Error && error.name === "AbortError") {
|
|
1250
|
+
const err = new IgniterCallerError({
|
|
1251
|
+
code: "IGNITER_CALLER_TIMEOUT",
|
|
1252
|
+
operation: "execute",
|
|
1253
|
+
message: `Request timeout after ${this.options.timeout || 3e4}ms`,
|
|
1254
|
+
statusCode: 408,
|
|
1255
|
+
logger: this.logger,
|
|
1256
|
+
metadata: {
|
|
1257
|
+
method: this.options.method,
|
|
1258
|
+
url
|
|
1259
|
+
},
|
|
1260
|
+
cause: error instanceof Error ? error : void 0
|
|
1261
|
+
});
|
|
1262
|
+
this.telemetry?.emit(
|
|
1263
|
+
"igniter.caller.request.timeout.error",
|
|
1264
|
+
{
|
|
1265
|
+
level: "error",
|
|
1266
|
+
attributes: {
|
|
1267
|
+
"ctx.request.method": method,
|
|
1268
|
+
"ctx.request.url": safeUrl,
|
|
1269
|
+
"ctx.request.timeoutMs": this.options.timeout || 3e4
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
);
|
|
1273
|
+
this.logger?.error("IgniterCaller.request.execute timeout", {
|
|
1274
|
+
method,
|
|
1275
|
+
url: safeUrl,
|
|
1276
|
+
timeoutMs: this.options.timeout || 3e4,
|
|
1277
|
+
error: err
|
|
1278
|
+
});
|
|
1021
1279
|
return {
|
|
1022
1280
|
data: void 0,
|
|
1023
|
-
error:
|
|
1024
|
-
code: "IGNITER_CALLER_TIMEOUT",
|
|
1025
|
-
operation: "execute",
|
|
1026
|
-
message: `Request timeout after ${this.options.timeout || 3e4}ms`,
|
|
1027
|
-
statusCode: 408,
|
|
1028
|
-
logger: this.logger,
|
|
1029
|
-
metadata: {
|
|
1030
|
-
method: this.options.method,
|
|
1031
|
-
url
|
|
1032
|
-
},
|
|
1033
|
-
cause: error
|
|
1034
|
-
})
|
|
1281
|
+
error: err
|
|
1035
1282
|
};
|
|
1036
1283
|
}
|
|
1037
1284
|
return {
|
|
@@ -1046,13 +1293,13 @@ var IgniterCallerRequestBuilder = class {
|
|
|
1046
1293
|
method: this.options.method,
|
|
1047
1294
|
url
|
|
1048
1295
|
},
|
|
1049
|
-
cause: error
|
|
1296
|
+
cause: error instanceof Error ? error : void 0
|
|
1050
1297
|
})
|
|
1051
1298
|
};
|
|
1052
1299
|
}
|
|
1053
1300
|
}
|
|
1054
|
-
|
|
1055
|
-
const { method, url, body, params,
|
|
1301
|
+
resolveUrl() {
|
|
1302
|
+
const { method, url, body, params, baseURL } = this.options;
|
|
1056
1303
|
let finalParams = params;
|
|
1057
1304
|
if ((method === "GET" || method === "HEAD") && body && typeof body === "object") {
|
|
1058
1305
|
const bodyParams = {};
|
|
@@ -1068,6 +1315,14 @@ var IgniterCallerRequestBuilder = class {
|
|
|
1068
1315
|
baseURL,
|
|
1069
1316
|
query: finalParams
|
|
1070
1317
|
});
|
|
1318
|
+
return {
|
|
1319
|
+
url: fullUrl,
|
|
1320
|
+
safeUrl: fullUrl.split("?")[0]
|
|
1321
|
+
};
|
|
1322
|
+
}
|
|
1323
|
+
buildRequest() {
|
|
1324
|
+
const { method, body, headers, timeout, cache } = this.options;
|
|
1325
|
+
const { url } = this.resolveUrl();
|
|
1071
1326
|
const shouldIncludeBody = body && method !== "GET" && method !== "HEAD";
|
|
1072
1327
|
const rawBody = shouldIncludeBody && IgniterCallerBodyUtils.isRawBody(body);
|
|
1073
1328
|
const finalHeaders = IgniterCallerBodyUtils.normalizeHeadersForBody(
|
|
@@ -1083,7 +1338,7 @@ var IgniterCallerRequestBuilder = class {
|
|
|
1083
1338
|
const controller = new AbortController();
|
|
1084
1339
|
const timeoutId = setTimeout(() => controller.abort(), timeout || 3e4);
|
|
1085
1340
|
return {
|
|
1086
|
-
url
|
|
1341
|
+
url,
|
|
1087
1342
|
requestInit,
|
|
1088
1343
|
controller,
|
|
1089
1344
|
timeoutId
|
|
@@ -1103,7 +1358,7 @@ var IgniterCallerRequestBuilder = class {
|
|
|
1103
1358
|
}
|
|
1104
1359
|
};
|
|
1105
1360
|
|
|
1106
|
-
// src/core/
|
|
1361
|
+
// src/core/events.ts
|
|
1107
1362
|
var IgniterCallerEvents = class {
|
|
1108
1363
|
constructor() {
|
|
1109
1364
|
this.listeners = /* @__PURE__ */ new Map();
|
|
@@ -1170,6 +1425,9 @@ var IgniterCallerEvents = class {
|
|
|
1170
1425
|
}
|
|
1171
1426
|
/**
|
|
1172
1427
|
* Removes a specific listener or all listeners for a pattern.
|
|
1428
|
+
*
|
|
1429
|
+
* @param pattern - URL string or RegExp pattern.
|
|
1430
|
+
* @param callback - Optional specific callback to remove.
|
|
1173
1431
|
*/
|
|
1174
1432
|
off(pattern, callback) {
|
|
1175
1433
|
if (typeof pattern === "string") {
|
|
@@ -1190,6 +1448,10 @@ var IgniterCallerEvents = class {
|
|
|
1190
1448
|
* Emits an event to all matching listeners.
|
|
1191
1449
|
*
|
|
1192
1450
|
* @internal
|
|
1451
|
+
*
|
|
1452
|
+
* @param url - Request URL to match listeners against.
|
|
1453
|
+
* @param method - HTTP method.
|
|
1454
|
+
* @param result - Response envelope.
|
|
1193
1455
|
*/
|
|
1194
1456
|
async emit(url, method, result) {
|
|
1195
1457
|
const context = {
|
|
@@ -1221,6 +1483,8 @@ var IgniterCallerEvents = class {
|
|
|
1221
1483
|
}
|
|
1222
1484
|
/**
|
|
1223
1485
|
* Removes all listeners.
|
|
1486
|
+
*
|
|
1487
|
+
* @returns Nothing.
|
|
1224
1488
|
*/
|
|
1225
1489
|
clear() {
|
|
1226
1490
|
this.listeners.clear();
|
|
@@ -1228,65 +1492,25 @@ var IgniterCallerEvents = class {
|
|
|
1228
1492
|
}
|
|
1229
1493
|
};
|
|
1230
1494
|
|
|
1231
|
-
// src/core/
|
|
1232
|
-
var
|
|
1495
|
+
// src/core/manager.ts
|
|
1496
|
+
var _IgniterCallerManager = class _IgniterCallerManager {
|
|
1497
|
+
/**
|
|
1498
|
+
* Creates a new manager instance.
|
|
1499
|
+
*
|
|
1500
|
+
* @param baseURL - Base URL prefix for requests.
|
|
1501
|
+
* @param opts - Optional configuration (headers, cookies, telemetry, schemas).
|
|
1502
|
+
*/
|
|
1233
1503
|
constructor(baseURL, opts) {
|
|
1234
1504
|
this.baseURL = baseURL;
|
|
1235
1505
|
this.headers = opts?.headers;
|
|
1236
1506
|
this.cookies = opts?.cookies;
|
|
1237
1507
|
this.logger = opts?.logger;
|
|
1508
|
+
this.telemetry = opts?.telemetry;
|
|
1238
1509
|
this.requestInterceptors = opts?.requestInterceptors;
|
|
1239
1510
|
this.responseInterceptors = opts?.responseInterceptors;
|
|
1240
1511
|
this.schemas = opts?.schemas;
|
|
1241
1512
|
this.schemaValidation = opts?.schemaValidation;
|
|
1242
1513
|
}
|
|
1243
|
-
/**
|
|
1244
|
-
* Canonical initialization entrypoint.
|
|
1245
|
-
*
|
|
1246
|
-
* This is designed to remain stable when extracted to `@igniter-js/caller`.
|
|
1247
|
-
*/
|
|
1248
|
-
static create() {
|
|
1249
|
-
return IgniterCallerBuilder.create((state) => {
|
|
1250
|
-
if (state.store) {
|
|
1251
|
-
IgniterCallerCacheUtils.setStore(state.store, state.storeOptions);
|
|
1252
|
-
}
|
|
1253
|
-
return new _IgniterCaller(state.baseURL, {
|
|
1254
|
-
headers: state.headers,
|
|
1255
|
-
cookies: state.cookies,
|
|
1256
|
-
logger: state.logger,
|
|
1257
|
-
requestInterceptors: state.requestInterceptors,
|
|
1258
|
-
responseInterceptors: state.responseInterceptors,
|
|
1259
|
-
schemas: state.schemas,
|
|
1260
|
-
schemaValidation: state.schemaValidation
|
|
1261
|
-
});
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
/**
|
|
1265
|
-
* Returns a new client with the same config and a new logger.
|
|
1266
|
-
*/
|
|
1267
|
-
withLogger(logger) {
|
|
1268
|
-
return new _IgniterCaller(this.baseURL, {
|
|
1269
|
-
headers: this.headers,
|
|
1270
|
-
cookies: this.cookies,
|
|
1271
|
-
logger,
|
|
1272
|
-
requestInterceptors: this.requestInterceptors,
|
|
1273
|
-
responseInterceptors: this.responseInterceptors,
|
|
1274
|
-
schemas: this.schemas,
|
|
1275
|
-
schemaValidation: this.schemaValidation
|
|
1276
|
-
});
|
|
1277
|
-
}
|
|
1278
|
-
setBaseURL(baseURL) {
|
|
1279
|
-
this.baseURL = baseURL;
|
|
1280
|
-
return this;
|
|
1281
|
-
}
|
|
1282
|
-
setHeaders(headers) {
|
|
1283
|
-
this.headers = headers;
|
|
1284
|
-
return this;
|
|
1285
|
-
}
|
|
1286
|
-
setCookies(cookies) {
|
|
1287
|
-
this.cookies = cookies;
|
|
1288
|
-
return this;
|
|
1289
|
-
}
|
|
1290
1514
|
/**
|
|
1291
1515
|
* Creates common request builder params.
|
|
1292
1516
|
*/
|
|
@@ -1296,24 +1520,16 @@ var _IgniterCaller = class _IgniterCaller {
|
|
|
1296
1520
|
defaultHeaders: this.headers,
|
|
1297
1521
|
defaultCookies: this.cookies,
|
|
1298
1522
|
logger: this.logger,
|
|
1523
|
+
telemetry: this.telemetry,
|
|
1299
1524
|
requestInterceptors: this.requestInterceptors,
|
|
1300
1525
|
responseInterceptors: this.responseInterceptors,
|
|
1301
1526
|
eventEmitter: async (url, method, result) => {
|
|
1302
|
-
await
|
|
1527
|
+
await _IgniterCallerManager.emitEvent(url, method, result);
|
|
1303
1528
|
},
|
|
1304
1529
|
schemas: this.schemas,
|
|
1305
1530
|
schemaValidation: this.schemaValidation
|
|
1306
1531
|
};
|
|
1307
1532
|
}
|
|
1308
|
-
/**
|
|
1309
|
-
* Resolves the full URL path by prepending baseURL if needed.
|
|
1310
|
-
*/
|
|
1311
|
-
resolveSchemaPath(url) {
|
|
1312
|
-
if (this.baseURL && !url.startsWith("http")) {
|
|
1313
|
-
return `${this.baseURL}${url}`;
|
|
1314
|
-
}
|
|
1315
|
-
return url;
|
|
1316
|
-
}
|
|
1317
1533
|
get(url) {
|
|
1318
1534
|
const builder = new IgniterCallerRequestBuilder(this.createBuilderParams());
|
|
1319
1535
|
builder._setMethod("GET");
|
|
@@ -1356,6 +1572,9 @@ var _IgniterCaller = class _IgniterCaller {
|
|
|
1356
1572
|
* This is a convenience method for making requests without using the builder pattern.
|
|
1357
1573
|
* Useful for dynamic requests where options are constructed programmatically.
|
|
1358
1574
|
*
|
|
1575
|
+
* @param options - Request configuration for method, url, and behavior.
|
|
1576
|
+
* @returns Response envelope with data or error.
|
|
1577
|
+
*
|
|
1359
1578
|
* @example
|
|
1360
1579
|
* ```ts
|
|
1361
1580
|
* const result = await api.request({
|
|
@@ -1422,6 +1641,9 @@ var _IgniterCaller = class _IgniterCaller {
|
|
|
1422
1641
|
* Executes multiple requests in parallel and returns results as an array.
|
|
1423
1642
|
*
|
|
1424
1643
|
* This is useful for batching independent API calls.
|
|
1644
|
+
*
|
|
1645
|
+
* @param requests - Array of request promises.
|
|
1646
|
+
* @returns Array of resolved results in the same order.
|
|
1425
1647
|
*/
|
|
1426
1648
|
static async batch(requests) {
|
|
1427
1649
|
return Promise.all(requests);
|
|
@@ -1442,7 +1664,7 @@ var _IgniterCaller = class _IgniterCaller {
|
|
|
1442
1664
|
* @example
|
|
1443
1665
|
* ```ts
|
|
1444
1666
|
* // Listen to all user endpoints
|
|
1445
|
-
* const cleanup =
|
|
1667
|
+
* const cleanup = IgniterCallerManager.on(/^\/users/, (result, context) => {
|
|
1446
1668
|
* console.log(`${context.method} ${context.url}`, result)
|
|
1447
1669
|
* })
|
|
1448
1670
|
*
|
|
@@ -1451,24 +1673,29 @@ var _IgniterCaller = class _IgniterCaller {
|
|
|
1451
1673
|
* ```
|
|
1452
1674
|
*/
|
|
1453
1675
|
static on(pattern, callback) {
|
|
1454
|
-
return
|
|
1676
|
+
return _IgniterCallerManager.events.on(pattern, callback);
|
|
1455
1677
|
}
|
|
1456
1678
|
/**
|
|
1457
1679
|
* Removes event listeners for a pattern.
|
|
1680
|
+
*
|
|
1681
|
+
* @param pattern - URL string or RegExp pattern.
|
|
1682
|
+
* @param callback - Callback to remove (optional).
|
|
1458
1683
|
*/
|
|
1459
1684
|
static off(pattern, callback) {
|
|
1460
|
-
|
|
1685
|
+
_IgniterCallerManager.events.off(pattern, callback);
|
|
1461
1686
|
}
|
|
1462
1687
|
/**
|
|
1463
1688
|
* Invalidates a specific cache entry.
|
|
1464
1689
|
*
|
|
1465
1690
|
* This is useful after mutations to ensure fresh data on next fetch.
|
|
1466
1691
|
*
|
|
1692
|
+
* @param key - Cache key to invalidate.
|
|
1693
|
+
*
|
|
1467
1694
|
* @example
|
|
1468
1695
|
* ```ts
|
|
1469
1696
|
* // After creating a user
|
|
1470
1697
|
* await api.post('/users').body(newUser).execute()
|
|
1471
|
-
* await
|
|
1698
|
+
* await IgniterCallerManager.invalidate('/users') // Clear users list cache
|
|
1472
1699
|
* ```
|
|
1473
1700
|
*/
|
|
1474
1701
|
static async invalidate(key) {
|
|
@@ -1478,11 +1705,12 @@ var _IgniterCaller = class _IgniterCaller {
|
|
|
1478
1705
|
* Invalidates all cache entries matching a pattern.
|
|
1479
1706
|
*
|
|
1480
1707
|
* @param pattern Glob pattern (e.g., '/users/*') or exact key
|
|
1708
|
+
* @returns Promise that resolves when invalidation completes.
|
|
1481
1709
|
*
|
|
1482
1710
|
* @example
|
|
1483
1711
|
* ```ts
|
|
1484
1712
|
* // Invalidate all user-related caches
|
|
1485
|
-
* await
|
|
1713
|
+
* await IgniterCallerManager.invalidatePattern('/users/*')
|
|
1486
1714
|
* ```
|
|
1487
1715
|
*/
|
|
1488
1716
|
static async invalidatePattern(pattern) {
|
|
@@ -1492,25 +1720,539 @@ var _IgniterCaller = class _IgniterCaller {
|
|
|
1492
1720
|
* Emits an event to all registered listeners.
|
|
1493
1721
|
*
|
|
1494
1722
|
* @internal
|
|
1723
|
+
*
|
|
1724
|
+
* @param url - Request URL (resolved).
|
|
1725
|
+
* @param method - HTTP method.
|
|
1726
|
+
* @param result - Response envelope.
|
|
1495
1727
|
*/
|
|
1496
1728
|
static async emitEvent(url, method, result) {
|
|
1497
|
-
await
|
|
1729
|
+
await _IgniterCallerManager.events.emit(url, method, result);
|
|
1498
1730
|
}
|
|
1499
1731
|
};
|
|
1500
1732
|
/** Global event emitter for observing HTTP responses */
|
|
1501
|
-
|
|
1502
|
-
var
|
|
1733
|
+
_IgniterCallerManager.events = new IgniterCallerEvents();
|
|
1734
|
+
var IgniterCallerManager = _IgniterCallerManager;
|
|
1735
|
+
|
|
1736
|
+
// src/builders/main.builder.ts
|
|
1737
|
+
var IgniterCallerBuilder = class _IgniterCallerBuilder {
|
|
1738
|
+
constructor(state) {
|
|
1739
|
+
this.state = state;
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Creates a new builder instance.
|
|
1743
|
+
*
|
|
1744
|
+
* @returns New builder instance with empty state.
|
|
1745
|
+
*/
|
|
1746
|
+
static create() {
|
|
1747
|
+
return new _IgniterCallerBuilder({});
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Sets the base URL for all requests.
|
|
1751
|
+
*
|
|
1752
|
+
* @param baseURL - Base URL prefix for outgoing requests.
|
|
1753
|
+
*/
|
|
1754
|
+
withBaseUrl(baseURL) {
|
|
1755
|
+
return new _IgniterCallerBuilder({ ...this.state, baseURL });
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* Merges default headers for all requests.
|
|
1759
|
+
*
|
|
1760
|
+
* @param headers - Header map merged into every request.
|
|
1761
|
+
*/
|
|
1762
|
+
withHeaders(headers) {
|
|
1763
|
+
return new _IgniterCallerBuilder({ ...this.state, headers });
|
|
1764
|
+
}
|
|
1765
|
+
/**
|
|
1766
|
+
* Sets default cookies (sent as the `Cookie` header).
|
|
1767
|
+
*
|
|
1768
|
+
* @param cookies - Cookie key/value pairs.
|
|
1769
|
+
*/
|
|
1770
|
+
withCookies(cookies) {
|
|
1771
|
+
return new _IgniterCallerBuilder({ ...this.state, cookies });
|
|
1772
|
+
}
|
|
1773
|
+
/**
|
|
1774
|
+
* Attaches a logger instance.
|
|
1775
|
+
*
|
|
1776
|
+
* @param logger - Logger implementation from `@igniter-js/core`.
|
|
1777
|
+
*/
|
|
1778
|
+
withLogger(logger) {
|
|
1779
|
+
return new _IgniterCallerBuilder({ ...this.state, logger });
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Adds a request interceptor that runs before each request.
|
|
1783
|
+
*
|
|
1784
|
+
* @param interceptor - Interceptor called with request options.
|
|
1785
|
+
*/
|
|
1786
|
+
withRequestInterceptor(interceptor) {
|
|
1787
|
+
const requestInterceptors = [
|
|
1788
|
+
...this.state.requestInterceptors || [],
|
|
1789
|
+
interceptor
|
|
1790
|
+
];
|
|
1791
|
+
return new _IgniterCallerBuilder({ ...this.state, requestInterceptors });
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* Adds a response interceptor that runs after each request.
|
|
1795
|
+
*
|
|
1796
|
+
* @param interceptor - Interceptor called with the response result.
|
|
1797
|
+
*/
|
|
1798
|
+
withResponseInterceptor(interceptor) {
|
|
1799
|
+
const responseInterceptors = [
|
|
1800
|
+
...this.state.responseInterceptors || [],
|
|
1801
|
+
interceptor
|
|
1802
|
+
];
|
|
1803
|
+
return new _IgniterCallerBuilder({ ...this.state, responseInterceptors });
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Configures a persistent store adapter for caching.
|
|
1807
|
+
*
|
|
1808
|
+
* When configured, cache operations will use the store (e.g., Redis)
|
|
1809
|
+
* instead of in-memory cache, enabling persistent cache across deployments.
|
|
1810
|
+
*
|
|
1811
|
+
* @param store - Store adapter implementation.
|
|
1812
|
+
* @param options - Store options (ttl, keyPrefix, fallback).
|
|
1813
|
+
*/
|
|
1814
|
+
withStore(store, options) {
|
|
1815
|
+
return new _IgniterCallerBuilder({
|
|
1816
|
+
...this.state,
|
|
1817
|
+
store,
|
|
1818
|
+
storeOptions: options
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
/**
|
|
1822
|
+
* Configures schema-based type safety and validation.
|
|
1823
|
+
*
|
|
1824
|
+
* Enables automatic type inference for requests/responses based on
|
|
1825
|
+
* route and method, with optional runtime validation via StandardSchemaV1
|
|
1826
|
+
* (Zod is supported).
|
|
1827
|
+
*
|
|
1828
|
+
* @param schemas - Schema map keyed by URL path and method.
|
|
1829
|
+
* @param validation - Validation options for request/response checks.
|
|
1830
|
+
*
|
|
1831
|
+
* @example
|
|
1832
|
+
* ```ts
|
|
1833
|
+
* const api = IgniterCaller.create()
|
|
1834
|
+
* .withSchemas({
|
|
1835
|
+
* '/users': {
|
|
1836
|
+
* GET: {
|
|
1837
|
+
* responses: {
|
|
1838
|
+
* 200: z.array(UserSchema),
|
|
1839
|
+
* 401: ErrorSchema,
|
|
1840
|
+
* },
|
|
1841
|
+
* },
|
|
1842
|
+
* POST: {
|
|
1843
|
+
* request: CreateUserSchema,
|
|
1844
|
+
* responses: {
|
|
1845
|
+
* 201: UserSchema,
|
|
1846
|
+
* 400: ValidationErrorSchema,
|
|
1847
|
+
* },
|
|
1848
|
+
* },
|
|
1849
|
+
* },
|
|
1850
|
+
* })
|
|
1851
|
+
* .build()
|
|
1852
|
+
* ```
|
|
1853
|
+
*/
|
|
1854
|
+
withSchemas(schemas, validation) {
|
|
1855
|
+
const nextState = {
|
|
1856
|
+
...this.state,
|
|
1857
|
+
schemas,
|
|
1858
|
+
schemaValidation: validation
|
|
1859
|
+
};
|
|
1860
|
+
return new _IgniterCallerBuilder(nextState);
|
|
1861
|
+
}
|
|
1862
|
+
/**
|
|
1863
|
+
* Attaches telemetry for request monitoring and observability.
|
|
1864
|
+
*
|
|
1865
|
+
* Telemetry is optional and only emits events when a manager is provided.
|
|
1866
|
+
*
|
|
1867
|
+
* Telemetry events emitted by the caller package include:
|
|
1868
|
+
* - `request.execute.started`
|
|
1869
|
+
* - `request.execute.success`
|
|
1870
|
+
* - `request.execute.error`
|
|
1871
|
+
* - `request.timeout.error`
|
|
1872
|
+
* - `cache.read.hit`
|
|
1873
|
+
* - `retry.attempt.started`
|
|
1874
|
+
* - `validation.request.error`
|
|
1875
|
+
* - `validation.response.error`
|
|
1876
|
+
*
|
|
1877
|
+
* @param telemetry - Telemetry manager instance.
|
|
1878
|
+
*
|
|
1879
|
+
* @example
|
|
1880
|
+
* ```ts
|
|
1881
|
+
* import { IgniterTelemetry } from '@igniter-js/telemetry'
|
|
1882
|
+
* import { IgniterCallerTelemetryEvents } from '@igniter-js/caller/telemetry'
|
|
1883
|
+
*
|
|
1884
|
+
* const telemetry = IgniterTelemetry.create()
|
|
1885
|
+
* .withService('my-api')
|
|
1886
|
+
* .addEvents(IgniterCallerTelemetryEvents)
|
|
1887
|
+
* .build()
|
|
1888
|
+
*
|
|
1889
|
+
* const api = IgniterCaller.create()
|
|
1890
|
+
* .withBaseUrl('https://api.example.com')
|
|
1891
|
+
* .withTelemetry(telemetry)
|
|
1892
|
+
* .build()
|
|
1893
|
+
* ```
|
|
1894
|
+
*/
|
|
1895
|
+
withTelemetry(telemetry) {
|
|
1896
|
+
return new _IgniterCallerBuilder({ ...this.state, telemetry });
|
|
1897
|
+
}
|
|
1898
|
+
/**
|
|
1899
|
+
* Builds the `IgniterCaller` instance.
|
|
1900
|
+
*
|
|
1901
|
+
* @returns Configured manager instance.
|
|
1902
|
+
*/
|
|
1903
|
+
build() {
|
|
1904
|
+
if (this.state.store) {
|
|
1905
|
+
IgniterCallerCacheUtils.setStore(this.state.store, this.state.storeOptions);
|
|
1906
|
+
}
|
|
1907
|
+
const manager = new IgniterCallerManager(this.state.baseURL, {
|
|
1908
|
+
headers: this.state.headers,
|
|
1909
|
+
cookies: this.state.cookies,
|
|
1910
|
+
logger: this.state.logger,
|
|
1911
|
+
telemetry: this.state.telemetry,
|
|
1912
|
+
requestInterceptors: this.state.requestInterceptors,
|
|
1913
|
+
responseInterceptors: this.state.responseInterceptors,
|
|
1914
|
+
schemas: this.state.schemas,
|
|
1915
|
+
schemaValidation: this.state.schemaValidation
|
|
1916
|
+
});
|
|
1917
|
+
this.state.logger?.info("IgniterCaller initialized", {
|
|
1918
|
+
baseURL: this.state.baseURL,
|
|
1919
|
+
hasTelemetry: Boolean(this.state.telemetry),
|
|
1920
|
+
hasStore: Boolean(this.state.store),
|
|
1921
|
+
hasSchemas: Boolean(this.state.schemas)
|
|
1922
|
+
});
|
|
1923
|
+
return manager;
|
|
1924
|
+
}
|
|
1925
|
+
};
|
|
1926
|
+
var IgniterCaller = {
|
|
1927
|
+
create: IgniterCallerBuilder.create
|
|
1928
|
+
};
|
|
1929
|
+
var IgniterCallerSchemaPathBuilder = class _IgniterCallerSchemaPathBuilder {
|
|
1930
|
+
constructor(methods, registry) {
|
|
1931
|
+
this.methods = methods;
|
|
1932
|
+
this.registry = registry;
|
|
1933
|
+
}
|
|
1934
|
+
/**
|
|
1935
|
+
* Creates a new path builder for the provided registry.
|
|
1936
|
+
*/
|
|
1937
|
+
static create(registry) {
|
|
1938
|
+
return new _IgniterCallerSchemaPathBuilder({}, registry);
|
|
1939
|
+
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Returns a registry reference helper for a given key.
|
|
1942
|
+
* The helper exposes optional Zod-based wrappers (array/optional/nullable/record).
|
|
1943
|
+
*/
|
|
1944
|
+
ref(key) {
|
|
1945
|
+
const schema = this.registry[key];
|
|
1946
|
+
const zodSchema = schema;
|
|
1947
|
+
return {
|
|
1948
|
+
schema,
|
|
1949
|
+
array: () => z.array(zodSchema),
|
|
1950
|
+
nullable: () => zodSchema.nullable(),
|
|
1951
|
+
optional: () => zodSchema.optional(),
|
|
1952
|
+
record: (keyType) => z.record(
|
|
1953
|
+
z.any(),
|
|
1954
|
+
zodSchema
|
|
1955
|
+
)
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* Defines a GET endpoint.
|
|
1960
|
+
*/
|
|
1961
|
+
get(config) {
|
|
1962
|
+
return this.addMethod("GET", config);
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Defines a POST endpoint.
|
|
1966
|
+
*/
|
|
1967
|
+
post(config) {
|
|
1968
|
+
return this.addMethod("POST", config);
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Defines a PUT endpoint.
|
|
1972
|
+
*/
|
|
1973
|
+
put(config) {
|
|
1974
|
+
return this.addMethod("PUT", config);
|
|
1975
|
+
}
|
|
1976
|
+
/**
|
|
1977
|
+
* Defines a PATCH endpoint.
|
|
1978
|
+
*/
|
|
1979
|
+
patch(config) {
|
|
1980
|
+
return this.addMethod("PATCH", config);
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Defines a DELETE endpoint.
|
|
1984
|
+
*/
|
|
1985
|
+
delete(config) {
|
|
1986
|
+
return this.addMethod("DELETE", config);
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* Defines a HEAD endpoint.
|
|
1990
|
+
*/
|
|
1991
|
+
head(config) {
|
|
1992
|
+
return this.addMethod("HEAD", config);
|
|
1993
|
+
}
|
|
1994
|
+
/**
|
|
1995
|
+
* Builds the accumulated method map for the path.
|
|
1996
|
+
*/
|
|
1997
|
+
build() {
|
|
1998
|
+
return this.methods;
|
|
1999
|
+
}
|
|
2000
|
+
addMethod(method, config) {
|
|
2001
|
+
if (method in this.methods) {
|
|
2002
|
+
throw new IgniterCallerError({
|
|
2003
|
+
code: "IGNITER_CALLER_SCHEMA_DUPLICATE",
|
|
2004
|
+
operation: "buildSchema",
|
|
2005
|
+
message: `Schema for method "${method}" is already defined on this path.`,
|
|
2006
|
+
statusCode: 400,
|
|
2007
|
+
metadata: { method }
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
return new _IgniterCallerSchemaPathBuilder(
|
|
2011
|
+
{
|
|
2012
|
+
...this.methods,
|
|
2013
|
+
[method]: {
|
|
2014
|
+
...config
|
|
2015
|
+
}
|
|
2016
|
+
},
|
|
2017
|
+
this.registry
|
|
2018
|
+
);
|
|
2019
|
+
}
|
|
2020
|
+
};
|
|
2021
|
+
|
|
2022
|
+
// src/builders/schema.builder.ts
|
|
2023
|
+
var IgniterCallerSchema = class _IgniterCallerSchema {
|
|
2024
|
+
constructor(schemas, registry) {
|
|
2025
|
+
this.schemas = schemas;
|
|
2026
|
+
this.registry = registry;
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
* Creates a new empty schema builder.
|
|
2030
|
+
*/
|
|
2031
|
+
static create() {
|
|
2032
|
+
return new _IgniterCallerSchema({}, {});
|
|
2033
|
+
}
|
|
2034
|
+
/**
|
|
2035
|
+
* Registers a reusable schema in the registry.
|
|
2036
|
+
*/
|
|
2037
|
+
schema(key, schema, options) {
|
|
2038
|
+
ensureValidSchemaKey(key);
|
|
2039
|
+
if (key in this.registry) {
|
|
2040
|
+
throw new IgniterCallerError({
|
|
2041
|
+
code: "IGNITER_CALLER_SCHEMA_DUPLICATE",
|
|
2042
|
+
operation: "buildSchema",
|
|
2043
|
+
message: `Schema registry key "${key}" is already defined.`,
|
|
2044
|
+
statusCode: 400,
|
|
2045
|
+
metadata: { key }
|
|
2046
|
+
});
|
|
2047
|
+
}
|
|
2048
|
+
const nextRegistry = {
|
|
2049
|
+
...this.registry,
|
|
2050
|
+
[key]: schema
|
|
2051
|
+
};
|
|
2052
|
+
void options?.internal;
|
|
2053
|
+
return new _IgniterCallerSchema(this.schemas, nextRegistry);
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* Defines a path with its methods using a fluent builder.
|
|
2057
|
+
*/
|
|
2058
|
+
path(path, builder) {
|
|
2059
|
+
ensureValidPath(path);
|
|
2060
|
+
const pathBuilder = IgniterCallerSchemaPathBuilder.create(this.registry);
|
|
2061
|
+
const builtMethods = builder(pathBuilder).build();
|
|
2062
|
+
const existing = this.schemas[path] ?? {};
|
|
2063
|
+
for (const method of Object.keys(
|
|
2064
|
+
builtMethods
|
|
2065
|
+
)) {
|
|
2066
|
+
if (method in existing) {
|
|
2067
|
+
throw new IgniterCallerError({
|
|
2068
|
+
code: "IGNITER_CALLER_SCHEMA_DUPLICATE",
|
|
2069
|
+
operation: "buildSchema",
|
|
2070
|
+
message: `Schema for "${path}" with method "${method}" is already defined.`,
|
|
2071
|
+
statusCode: 400,
|
|
2072
|
+
metadata: { path, method }
|
|
2073
|
+
});
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
const merged = {
|
|
2077
|
+
...existing,
|
|
2078
|
+
...builtMethods
|
|
2079
|
+
};
|
|
2080
|
+
const nextSchemas = {
|
|
2081
|
+
...this.schemas,
|
|
2082
|
+
[path]: merged
|
|
2083
|
+
};
|
|
2084
|
+
return new _IgniterCallerSchema(nextSchemas, this.registry);
|
|
2085
|
+
}
|
|
2086
|
+
/**
|
|
2087
|
+
* Builds the schema map and attaches inference + runtime helpers.
|
|
2088
|
+
*/
|
|
2089
|
+
build() {
|
|
2090
|
+
const result = {
|
|
2091
|
+
...this.schemas
|
|
2092
|
+
};
|
|
2093
|
+
const inferHelpers = createInferHelpers();
|
|
2094
|
+
const getHelpers = createGetHelpers(this.schemas, this.registry);
|
|
2095
|
+
Object.defineProperty(result, "$Infer", {
|
|
2096
|
+
value: inferHelpers,
|
|
2097
|
+
enumerable: false
|
|
2098
|
+
});
|
|
2099
|
+
Object.defineProperty(result, "get", {
|
|
2100
|
+
value: getHelpers,
|
|
2101
|
+
enumerable: false
|
|
2102
|
+
});
|
|
2103
|
+
return result;
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
function createInferHelpers() {
|
|
2107
|
+
return {
|
|
2108
|
+
Path: void 0,
|
|
2109
|
+
Endpoint: (() => void 0),
|
|
2110
|
+
Request: (() => void 0),
|
|
2111
|
+
Response: (() => void 0),
|
|
2112
|
+
Responses: (() => void 0),
|
|
2113
|
+
Schema: (() => void 0)
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
function createGetHelpers(schemas, registry) {
|
|
2117
|
+
return {
|
|
2118
|
+
path: (path) => schemas[path],
|
|
2119
|
+
endpoint: (path, method) => schemas[path][method],
|
|
2120
|
+
request: (path, method) => schemas[path][method]?.request,
|
|
2121
|
+
response: (path, method, status) => schemas[path][method]?.responses?.[status],
|
|
2122
|
+
schema: (key) => registry[key]
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
function ensureValidPath(path) {
|
|
2126
|
+
if (!path || path.trim().length === 0) {
|
|
2127
|
+
throw new IgniterCallerError({
|
|
2128
|
+
code: "IGNITER_CALLER_SCHEMA_INVALID",
|
|
2129
|
+
operation: "buildSchema",
|
|
2130
|
+
message: "Path cannot be empty.",
|
|
2131
|
+
statusCode: 400
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
2134
|
+
if (!path.startsWith("/")) {
|
|
2135
|
+
throw new IgniterCallerError({
|
|
2136
|
+
code: "IGNITER_CALLER_SCHEMA_INVALID",
|
|
2137
|
+
operation: "buildSchema",
|
|
2138
|
+
message: `Path "${path}" must start with "/".`,
|
|
2139
|
+
statusCode: 400,
|
|
2140
|
+
metadata: { path }
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
function ensureValidSchemaKey(key) {
|
|
2145
|
+
if (!key || key.trim().length === 0) {
|
|
2146
|
+
throw new IgniterCallerError({
|
|
2147
|
+
code: "IGNITER_CALLER_SCHEMA_INVALID",
|
|
2148
|
+
operation: "buildSchema",
|
|
2149
|
+
message: "Schema registry key cannot be empty.",
|
|
2150
|
+
statusCode: 400
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
// src/adapters/mock.adapter.ts
|
|
2156
|
+
var MockCallerStoreAdapter = class _MockCallerStoreAdapter {
|
|
2157
|
+
constructor() {
|
|
2158
|
+
/** Underlying in-memory store. */
|
|
2159
|
+
this.client = /* @__PURE__ */ new Map();
|
|
2160
|
+
/** Tracks all calls for assertions. */
|
|
2161
|
+
this.calls = {
|
|
2162
|
+
get: 0,
|
|
2163
|
+
set: 0,
|
|
2164
|
+
delete: 0,
|
|
2165
|
+
has: 0
|
|
2166
|
+
};
|
|
2167
|
+
/** Captures recent operations. */
|
|
2168
|
+
this.history = {
|
|
2169
|
+
get: [],
|
|
2170
|
+
set: [],
|
|
2171
|
+
delete: [],
|
|
2172
|
+
has: []
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
/** Creates a new mock adapter instance. */
|
|
2176
|
+
static create() {
|
|
2177
|
+
return new _MockCallerStoreAdapter();
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* Retrieves a cached value by key.
|
|
2181
|
+
*
|
|
2182
|
+
* @param key - Cache key (without prefix).
|
|
2183
|
+
* @returns Cached value or null.
|
|
2184
|
+
*/
|
|
2185
|
+
async get(key) {
|
|
2186
|
+
this.calls.get += 1;
|
|
2187
|
+
this.history.get.push(key);
|
|
2188
|
+
return this.client.has(key) ? this.client.get(key) : null;
|
|
2189
|
+
}
|
|
2190
|
+
/**
|
|
2191
|
+
* Stores a cached value.
|
|
2192
|
+
*
|
|
2193
|
+
* @param key - Cache key (without prefix).
|
|
2194
|
+
* @param value - Value to store.
|
|
2195
|
+
* @param options - Cache options (ttl, etc).
|
|
2196
|
+
*/
|
|
2197
|
+
async set(key, value, options) {
|
|
2198
|
+
this.calls.set += 1;
|
|
2199
|
+
this.history.set.push({ key, value, options });
|
|
2200
|
+
this.client.set(key, value);
|
|
2201
|
+
}
|
|
2202
|
+
/**
|
|
2203
|
+
* Removes a cached value.
|
|
2204
|
+
*
|
|
2205
|
+
* @param key - Cache key (without prefix).
|
|
2206
|
+
*/
|
|
2207
|
+
async delete(key) {
|
|
2208
|
+
this.calls.delete += 1;
|
|
2209
|
+
this.history.delete.push(key);
|
|
2210
|
+
this.client.delete(key);
|
|
2211
|
+
}
|
|
2212
|
+
/**
|
|
2213
|
+
* Checks if a cached value exists.
|
|
2214
|
+
*
|
|
2215
|
+
* @param key - Cache key (without prefix).
|
|
2216
|
+
* @returns True when the key exists.
|
|
2217
|
+
*/
|
|
2218
|
+
async has(key) {
|
|
2219
|
+
this.calls.has += 1;
|
|
2220
|
+
this.history.has.push(key);
|
|
2221
|
+
return this.client.has(key);
|
|
2222
|
+
}
|
|
2223
|
+
/**
|
|
2224
|
+
* Clears all tracked state.
|
|
2225
|
+
*
|
|
2226
|
+
* @returns Nothing.
|
|
2227
|
+
*/
|
|
2228
|
+
clear() {
|
|
2229
|
+
this.client.clear();
|
|
2230
|
+
this.calls.get = 0;
|
|
2231
|
+
this.calls.set = 0;
|
|
2232
|
+
this.calls.delete = 0;
|
|
2233
|
+
this.calls.has = 0;
|
|
2234
|
+
this.history.get = [];
|
|
2235
|
+
this.history.set = [];
|
|
2236
|
+
this.history.delete = [];
|
|
2237
|
+
this.history.has = [];
|
|
2238
|
+
}
|
|
2239
|
+
};
|
|
1503
2240
|
|
|
1504
2241
|
// src/utils/testing.ts
|
|
1505
2242
|
var IgniterCallerMock = class {
|
|
1506
2243
|
/**
|
|
1507
2244
|
* Creates a successful mock response.
|
|
2245
|
+
*
|
|
2246
|
+
* @param data - Mock response data.
|
|
1508
2247
|
*/
|
|
1509
2248
|
static mockResponse(data) {
|
|
1510
2249
|
return { data, error: void 0 };
|
|
1511
2250
|
}
|
|
1512
2251
|
/**
|
|
1513
2252
|
* Creates an error mock response.
|
|
2253
|
+
*
|
|
2254
|
+
* @param code - Error code to use.
|
|
2255
|
+
* @param message - Optional error message.
|
|
1514
2256
|
*/
|
|
1515
2257
|
static mockError(code, message = "Mock error") {
|
|
1516
2258
|
return {
|
|
@@ -1524,6 +2266,9 @@ var IgniterCallerMock = class {
|
|
|
1524
2266
|
}
|
|
1525
2267
|
/**
|
|
1526
2268
|
* Creates a successful file download mock.
|
|
2269
|
+
*
|
|
2270
|
+
* @param filename - File name for the mock.
|
|
2271
|
+
* @param content - File contents as string or Blob.
|
|
1527
2272
|
*/
|
|
1528
2273
|
static mockFile(filename, content) {
|
|
1529
2274
|
const blob = typeof content === "string" ? new Blob([content]) : content;
|
|
@@ -1532,6 +2277,8 @@ var IgniterCallerMock = class {
|
|
|
1532
2277
|
}
|
|
1533
2278
|
/**
|
|
1534
2279
|
* Creates a failed file download mock.
|
|
2280
|
+
*
|
|
2281
|
+
* @param message - Optional error message.
|
|
1535
2282
|
*/
|
|
1536
2283
|
static mockFileError(message = "Mock file error") {
|
|
1537
2284
|
return {
|
|
@@ -1545,6 +2292,6 @@ var IgniterCallerMock = class {
|
|
|
1545
2292
|
}
|
|
1546
2293
|
};
|
|
1547
2294
|
|
|
1548
|
-
export { IgniterCaller, IgniterCallerBodyUtils, IgniterCallerBuilder, IgniterCallerCacheUtils, IgniterCallerError, IgniterCallerEvents, IgniterCallerMock, IgniterCallerRequestBuilder, IgniterCallerSchemaUtils, IgniterCallerUrlUtils };
|
|
2295
|
+
export { IgniterCaller, IgniterCallerBodyUtils, IgniterCallerBuilder, IgniterCallerCacheUtils, IgniterCallerError, IgniterCallerEvents, IgniterCallerManager, IgniterCallerMock, IgniterCallerRequestBuilder, IgniterCallerSchema, IgniterCallerSchemaPathBuilder, IgniterCallerSchemaUtils, IgniterCallerUrlUtils, MockCallerStoreAdapter };
|
|
1549
2296
|
//# sourceMappingURL=index.mjs.map
|
|
1550
2297
|
//# sourceMappingURL=index.mjs.map
|