@lucaapp/service-utils 5.4.2 → 5.5.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/dist/lib/kafka/index.d.ts +1 -1
- package/dist/lib/kafka/kafkaClient.d.ts +22 -1
- package/dist/lib/kafka/kafkaClient.js +127 -0
- package/dist/lib/kafka/types.d.ts +15 -2
- package/dist/lib/serviceIdentity/index.d.ts +2 -1
- package/dist/lib/serviceIdentity/index.js +3 -1
- package/dist/lib/serviceIdentity/serviceIdentity.d.ts +21 -2
- package/dist/lib/serviceIdentity/serviceIdentity.js +63 -19
- package/package.json +5 -2
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { KafkaClient } from './kafkaClient';
|
|
2
2
|
export { KafkaTopic } from './events';
|
|
3
|
-
export type { KafkaEvent, EventPayloadHandler, KafkaConfiguration, } from './types';
|
|
3
|
+
export type { KafkaEvent, GenericKafkaEvent, EventPayloadHandler, GenericEventPayloadHandler, KafkaConfiguration, CustomTopicConfig, } from './types';
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Consumer } from 'kafkajs';
|
|
2
2
|
import { Logger } from 'pino';
|
|
3
3
|
import { ServiceIdentity } from '../serviceIdentity';
|
|
4
|
-
import type { EventPayloadHandler, KafkaConfiguration, KafkaEvent } from './types';
|
|
4
|
+
import type { EventPayloadHandler, GenericEventPayloadHandler, KafkaConfiguration, KafkaEvent, GenericKafkaEvent, CustomTopicConfig } from './types';
|
|
5
5
|
import { KafkaTopic } from './events';
|
|
6
6
|
declare class KafkaClient {
|
|
7
7
|
private readonly environment;
|
|
8
8
|
private readonly kafkaClient;
|
|
9
9
|
private readonly logger;
|
|
10
10
|
private readonly topicSecrets;
|
|
11
|
+
private readonly customTopics;
|
|
11
12
|
private readonly admin;
|
|
12
13
|
private readonly producer;
|
|
13
14
|
private readonly consumers;
|
|
@@ -25,6 +26,26 @@ declare class KafkaClient {
|
|
|
25
26
|
private ensureTopics;
|
|
26
27
|
consume: <T extends KafkaTopic>(kafkaTopic: T, handler: EventPayloadHandler<T>, fromBeginning?: boolean) => Promise<Consumer>;
|
|
27
28
|
produce: <T extends KafkaTopic>(kafkaTopic: T, key: string, value: KafkaEvent<T>) => Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Register a custom topic (not in KafkaTopic enum)
|
|
31
|
+
* This allows services to define their own topics without modifying service-utils
|
|
32
|
+
*/
|
|
33
|
+
registerCustomTopic: (config: CustomTopicConfig) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Get full topic name for custom topic
|
|
36
|
+
*/
|
|
37
|
+
private getCustomTopic;
|
|
38
|
+
/**
|
|
39
|
+
* Produce message to custom topic
|
|
40
|
+
*/
|
|
41
|
+
produceCustom: <T = unknown>(topicName: string, key: string, value: GenericKafkaEvent<T>) => Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Consume messages from custom topic
|
|
44
|
+
*/
|
|
45
|
+
consumeCustom: <T = unknown>(topicName: string, handler: GenericEventPayloadHandler<T>, fromBeginning?: boolean) => Promise<Consumer>;
|
|
46
|
+
private encryptCustomValue;
|
|
47
|
+
private decryptCustomValue;
|
|
48
|
+
private parseCustomValue;
|
|
28
49
|
shutdown: () => Promise<void>;
|
|
29
50
|
}
|
|
30
51
|
export { KafkaClient };
|
|
@@ -245,6 +245,132 @@ class KafkaClient {
|
|
|
245
245
|
throw (0, utils_1.logAndGetError)(this.logger, `Could not produce message for topic=${topic}`, error);
|
|
246
246
|
}
|
|
247
247
|
};
|
|
248
|
+
/**
|
|
249
|
+
* Register a custom topic (not in KafkaTopic enum)
|
|
250
|
+
* This allows services to define their own topics without modifying service-utils
|
|
251
|
+
*/
|
|
252
|
+
this.registerCustomTopic = (config) => {
|
|
253
|
+
this.customTopics.set(config.topic, config);
|
|
254
|
+
this.logger.info({ topic: config.topic, issuer: config.issuer }, 'Registered custom Kafka topic');
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Get full topic name for custom topic
|
|
258
|
+
*/
|
|
259
|
+
this.getCustomTopic = async (topicName) => {
|
|
260
|
+
const config = this.customTopics.get(topicName);
|
|
261
|
+
if (!config) {
|
|
262
|
+
throw (0, utils_1.logAndGetError)(this.logger, `Custom topic ${topicName} not registered. Call registerCustomTopic() first.`);
|
|
263
|
+
}
|
|
264
|
+
const topic = `${this.environment}_${config.issuer}_${topicName}`;
|
|
265
|
+
await this.ensureTopics(topic);
|
|
266
|
+
return topic;
|
|
267
|
+
};
|
|
268
|
+
/**
|
|
269
|
+
* Produce message to custom topic
|
|
270
|
+
*/
|
|
271
|
+
this.produceCustom = async (topicName, key, value) => {
|
|
272
|
+
const topic = await this.getCustomTopic(topicName);
|
|
273
|
+
const serializedValue = JSON.stringify(value);
|
|
274
|
+
// For custom topics, encryption is optional (skip if no secret provided)
|
|
275
|
+
const config = this.customTopics.get(topicName);
|
|
276
|
+
const encryptedValue = config.secret && this.encryptionEnabled
|
|
277
|
+
? await this.encryptCustomValue(config.secret, serializedValue)
|
|
278
|
+
: serializedValue;
|
|
279
|
+
const signature = await this.generateSignature(serializedValue);
|
|
280
|
+
try {
|
|
281
|
+
const producerRecord = {
|
|
282
|
+
topic,
|
|
283
|
+
messages: [
|
|
284
|
+
{
|
|
285
|
+
key,
|
|
286
|
+
value: encryptedValue,
|
|
287
|
+
headers: { signature },
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
};
|
|
291
|
+
await this.producer.send(producerRecord);
|
|
292
|
+
this.logger.debug(producerRecord, 'Custom topic record sent');
|
|
293
|
+
messageProducedSizeCounter
|
|
294
|
+
.labels({ topic })
|
|
295
|
+
.observe(Buffer.byteLength(encryptedValue));
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
messageProduceError.labels({ topic }).inc();
|
|
299
|
+
throw (0, utils_1.logAndGetError)(this.logger, `Could not produce message for custom topic=${topicName}`, error);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* Consume messages from custom topic
|
|
304
|
+
*/
|
|
305
|
+
this.consumeCustom = async (topicName, handler, fromBeginning = false) => {
|
|
306
|
+
const topic = await this.getCustomTopic(topicName);
|
|
307
|
+
const groupId = `${this.environment.valueOf()}_${topicName}_${this.serviceIdentity.identityName}`;
|
|
308
|
+
try {
|
|
309
|
+
const consumer = this.kafkaClient.consumer({
|
|
310
|
+
groupId,
|
|
311
|
+
sessionTimeout: 20000,
|
|
312
|
+
heartbeatInterval: 3000,
|
|
313
|
+
});
|
|
314
|
+
this.consumers.push(consumer);
|
|
315
|
+
await consumer.connect();
|
|
316
|
+
await consumer.subscribe({ topic, fromBeginning });
|
|
317
|
+
await consumer.run({
|
|
318
|
+
autoCommit: true,
|
|
319
|
+
eachMessage: async ({ message }) => {
|
|
320
|
+
try {
|
|
321
|
+
messageConsumedCounter.labels({ topic: topicName, groupId }).inc();
|
|
322
|
+
// Decrypt if secret was provided
|
|
323
|
+
const config = this.customTopics.get(topicName);
|
|
324
|
+
const decryptedValue = config.secret && this.encryptionEnabled
|
|
325
|
+
? await this.decryptCustomValue(config.secret, message.value)
|
|
326
|
+
: message.value;
|
|
327
|
+
const value = this.parseCustomValue(decryptedValue);
|
|
328
|
+
this.logger.debug({
|
|
329
|
+
key: message.key?.toString(),
|
|
330
|
+
value,
|
|
331
|
+
timestamp: message.timestamp,
|
|
332
|
+
}, 'Custom topic record received');
|
|
333
|
+
try {
|
|
334
|
+
await handler({ ...message, value });
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
throw (0, utils_1.logAndGetError)(this.logger, `Could not consume message for custom topic=${topicName}`, error);
|
|
338
|
+
}
|
|
339
|
+
messageAcknowledgedCounter
|
|
340
|
+
.labels({ topic: topicName, groupId })
|
|
341
|
+
.inc();
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
messageConsumedErrorCounter
|
|
345
|
+
.labels({ topic: topicName, groupId })
|
|
346
|
+
.inc();
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
});
|
|
351
|
+
return consumer;
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
throw (0, utils_1.logAndGetError)(this.logger, `Could not create consumer for custom topic=${topicName}`, error);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
this.encryptCustomValue = async (secret, value) => {
|
|
358
|
+
const jwe = await new jose.CompactEncrypt(new util_1.TextEncoder().encode(value));
|
|
359
|
+
jwe.setProtectedHeader({ alg: 'A256GCMKW', enc: 'A256GCM' });
|
|
360
|
+
return jwe.encrypt(Buffer.from(secret));
|
|
361
|
+
};
|
|
362
|
+
this.decryptCustomValue = async (secret, jwe) => {
|
|
363
|
+
if (!jwe)
|
|
364
|
+
return null;
|
|
365
|
+
const { plaintext } = await jose.compactDecrypt(jwe, Buffer.from(secret));
|
|
366
|
+
return Buffer.from(plaintext);
|
|
367
|
+
};
|
|
368
|
+
this.parseCustomValue = (value) => {
|
|
369
|
+
if (!value) {
|
|
370
|
+
throw (0, utils_1.logAndGetError)(this.logger, 'Unexpected event format `null`');
|
|
371
|
+
}
|
|
372
|
+
return JSON.parse(value.toString());
|
|
373
|
+
};
|
|
248
374
|
this.shutdown = async () => {
|
|
249
375
|
try {
|
|
250
376
|
for (const consumer of this.consumers) {
|
|
@@ -269,6 +395,7 @@ class KafkaClient {
|
|
|
269
395
|
});
|
|
270
396
|
this.serviceIdentity = serviceIdentity;
|
|
271
397
|
this.topicSecrets = topicSecrets;
|
|
398
|
+
this.customTopics = new Map();
|
|
272
399
|
try {
|
|
273
400
|
this.kafkaClient = new kafkajs_1.Kafka({
|
|
274
401
|
brokers: [kafkaConfig.broker],
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { KafkaTopic, MessageFormats } from './events';
|
|
2
|
-
import { Environment } from '../serviceIdentity';
|
|
2
|
+
import { Environment, Service } from '../serviceIdentity';
|
|
3
3
|
import { KafkaMessage } from 'kafkajs';
|
|
4
4
|
type KafkaEvent<T extends KafkaTopic> = {
|
|
5
5
|
id: string;
|
|
6
6
|
type: 'create' | 'update' | 'soft-destroy' | 'destroy';
|
|
7
7
|
entity: MessageFormats[T];
|
|
8
8
|
};
|
|
9
|
+
type GenericKafkaEvent<T = unknown> = {
|
|
10
|
+
id: string;
|
|
11
|
+
type: 'create' | 'update' | 'soft-destroy' | 'destroy';
|
|
12
|
+
entity: T;
|
|
13
|
+
};
|
|
9
14
|
type KafkaConfiguration = {
|
|
10
15
|
environment: Environment;
|
|
11
16
|
broker: string;
|
|
@@ -18,4 +23,12 @@ type KafkaConfiguration = {
|
|
|
18
23
|
type EventPayloadHandler<T extends KafkaTopic> = (message: Omit<KafkaMessage, 'value'> & {
|
|
19
24
|
value: KafkaEvent<T>;
|
|
20
25
|
}) => Promise<void>;
|
|
21
|
-
|
|
26
|
+
type GenericEventPayloadHandler<T = unknown> = (message: Omit<KafkaMessage, 'value'> & {
|
|
27
|
+
value: GenericKafkaEvent<T>;
|
|
28
|
+
}) => Promise<void>;
|
|
29
|
+
type CustomTopicConfig = {
|
|
30
|
+
topic: string;
|
|
31
|
+
issuer: Service;
|
|
32
|
+
secret?: string;
|
|
33
|
+
};
|
|
34
|
+
export type { KafkaEvent, GenericKafkaEvent, KafkaConfiguration, EventPayloadHandler, GenericEventPayloadHandler, CustomTopicConfig, };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { ServiceIdentity } from './serviceIdentity';
|
|
1
|
+
export { ServiceIdentity, ServiceIdentityError, ServiceIdentityErrorType, } from './serviceIdentity';
|
|
2
|
+
export type { CallServiceOptions } from './serviceIdentity';
|
|
2
3
|
export { Environment } from './environment';
|
|
3
4
|
export { Service } from './service';
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Service = exports.Environment = exports.ServiceIdentity = void 0;
|
|
3
|
+
exports.Service = exports.Environment = exports.ServiceIdentityErrorType = exports.ServiceIdentityError = exports.ServiceIdentity = void 0;
|
|
4
4
|
var serviceIdentity_1 = require("./serviceIdentity");
|
|
5
5
|
Object.defineProperty(exports, "ServiceIdentity", { enumerable: true, get: function () { return serviceIdentity_1.ServiceIdentity; } });
|
|
6
|
+
Object.defineProperty(exports, "ServiceIdentityError", { enumerable: true, get: function () { return serviceIdentity_1.ServiceIdentityError; } });
|
|
7
|
+
Object.defineProperty(exports, "ServiceIdentityErrorType", { enumerable: true, get: function () { return serviceIdentity_1.ServiceIdentityErrorType; } });
|
|
6
8
|
var environment_1 = require("./environment");
|
|
7
9
|
Object.defineProperty(exports, "Environment", { enumerable: true, get: function () { return environment_1.Environment; } });
|
|
8
10
|
var service_1 = require("./service");
|
|
@@ -18,6 +18,18 @@ export declare class ServiceIdentityError extends Error {
|
|
|
18
18
|
meta?: object | undefined;
|
|
19
19
|
constructor(type: ServiceIdentityErrorType, message?: string, meta?: object | undefined);
|
|
20
20
|
}
|
|
21
|
+
type HttpMethodWithoutBody = 'GET' | 'HEAD' | 'DELETE' | 'OPTIONS';
|
|
22
|
+
export type CallServiceOptions<M extends HttpMethod = HttpMethod> = M extends HttpMethodWithoutBody ? {
|
|
23
|
+
data?: never;
|
|
24
|
+
responseType?: ResponseType;
|
|
25
|
+
customHeaders?: Record<string, string>;
|
|
26
|
+
params?: Record<string, string | number | Array<string | number> | undefined>;
|
|
27
|
+
} : {
|
|
28
|
+
data?: unknown;
|
|
29
|
+
responseType?: ResponseType;
|
|
30
|
+
customHeaders?: Record<string, string>;
|
|
31
|
+
params?: Record<string, string | number | Array<string | number> | undefined>;
|
|
32
|
+
};
|
|
21
33
|
declare class ServiceIdentity {
|
|
22
34
|
readonly identityName: string;
|
|
23
35
|
readonly identityKid: string;
|
|
@@ -31,8 +43,12 @@ declare class ServiceIdentity {
|
|
|
31
43
|
private getJwtVerifyOptions;
|
|
32
44
|
getIdentityPublicKey: () => Promise<jose.KeyLike>;
|
|
33
45
|
getIdentityPrivateKey: () => Promise<jose.KeyLike>;
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
callServiceV2<T>(service: Service, method: HttpMethodWithoutBody, url: string, options?: CallServiceOptions<HttpMethodWithoutBody>): Promise<T>;
|
|
47
|
+
callServiceV2<T>(service: Service, method: HttpMethod, url: string, options?: CallServiceOptions<HttpMethod>): Promise<T>;
|
|
48
|
+
callService<T>(service: Service, method: HttpMethodWithoutBody, url: string, options?: CallServiceOptions<HttpMethodWithoutBody>): Promise<T>;
|
|
49
|
+
callService<T>(service: Service, method: HttpMethod, url: string, options?: CallServiceOptions<HttpMethod>): Promise<T>;
|
|
50
|
+
callService<T>(service: Service, method: HttpMethod, url: string, data?: unknown, responseType?: ResponseType, customHeaders?: Record<string, string>, params?: Record<string, string | number | Array<string | number> | undefined>): Promise<T>;
|
|
51
|
+
signJWT: (service: string, method: HttpMethod, url: string, data?: unknown, params?: Record<string, string | number | Array<string | number> | undefined>) => Promise<string>;
|
|
36
52
|
verifyJWT: (request: Request, service: string) => Promise<{
|
|
37
53
|
payload: jose.JWTPayload;
|
|
38
54
|
}>;
|
|
@@ -46,9 +62,12 @@ declare class ServiceIdentity {
|
|
|
46
62
|
'x-identity': string;
|
|
47
63
|
}>, z.ZodObject<{
|
|
48
64
|
payload: z.ZodAny;
|
|
65
|
+
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber]>, "many">, z.ZodUndefined]>>>;
|
|
49
66
|
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
params?: Record<string, string | number | (string | number)[] | undefined> | undefined;
|
|
50
68
|
payload?: any;
|
|
51
69
|
}, {
|
|
70
|
+
params?: Record<string, string | number | (string | number)[] | undefined> | undefined;
|
|
52
71
|
payload?: any;
|
|
53
72
|
}>>;
|
|
54
73
|
identityJWKSRoute: RequestHandler;
|
|
@@ -86,27 +86,12 @@ class ServiceIdentity {
|
|
|
86
86
|
}
|
|
87
87
|
return this.keyCache.private;
|
|
88
88
|
};
|
|
89
|
-
this.
|
|
90
|
-
const jwt = await this.signJWT(service, method, url, data);
|
|
91
|
-
const request = {
|
|
92
|
-
headers: {
|
|
93
|
-
[JWT_HEADER_NAME]: jwt,
|
|
94
|
-
...(0, requestTracer_1.getRequestIdHeader)(),
|
|
95
|
-
...customHeaders,
|
|
96
|
-
},
|
|
97
|
-
baseURL: `http://${service}:8080/`,
|
|
98
|
-
url,
|
|
99
|
-
method,
|
|
100
|
-
responseType,
|
|
101
|
-
};
|
|
102
|
-
const response = await this.axiosClient.request(request);
|
|
103
|
-
return response.data;
|
|
104
|
-
};
|
|
105
|
-
this.signJWT = async (service, method, url, data) => {
|
|
89
|
+
this.signJWT = async (service, method, url, data, params) => {
|
|
106
90
|
return await new jose.SignJWT({
|
|
107
91
|
method,
|
|
108
92
|
url,
|
|
109
93
|
data,
|
|
94
|
+
params,
|
|
110
95
|
})
|
|
111
96
|
.setProtectedHeader({
|
|
112
97
|
alg: JWT_ALGORITHM,
|
|
@@ -141,6 +126,9 @@ class ServiceIdentity {
|
|
|
141
126
|
if (request.method !== payload.method)
|
|
142
127
|
throw (0, boom_1.forbidden)(`${request.method} !== ${payload.method}`);
|
|
143
128
|
request.body = payload.data;
|
|
129
|
+
if (payload.params) {
|
|
130
|
+
request.query = payload.params;
|
|
131
|
+
}
|
|
144
132
|
next();
|
|
145
133
|
};
|
|
146
134
|
this.requireServiceIdentityV3 = (...services) => (0, api_1.createMiddleware)({
|
|
@@ -148,7 +136,17 @@ class ServiceIdentity {
|
|
|
148
136
|
headers: zod_1.z.object({
|
|
149
137
|
'x-identity': zod_1.z.string().refine(value => validator_1.default.isJWT(value)),
|
|
150
138
|
}),
|
|
151
|
-
context: zod_1.z.object({
|
|
139
|
+
context: zod_1.z.object({
|
|
140
|
+
payload: zod_1.z.any(),
|
|
141
|
+
params: zod_1.z
|
|
142
|
+
.record(zod_1.z.string(), zod_1.z.union([
|
|
143
|
+
zod_1.z.string(),
|
|
144
|
+
zod_1.z.number(),
|
|
145
|
+
zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number()])),
|
|
146
|
+
zod_1.z.undefined(),
|
|
147
|
+
]))
|
|
148
|
+
.optional(),
|
|
149
|
+
}),
|
|
152
150
|
},
|
|
153
151
|
responses: [],
|
|
154
152
|
errors: {
|
|
@@ -179,7 +177,10 @@ class ServiceIdentity {
|
|
|
179
177
|
if (method !== payload.method) {
|
|
180
178
|
throw new ServiceIdentityError(ServiceIdentityErrorType.METHOD_MISMATCH, `${method} !== ${payload.method}`);
|
|
181
179
|
}
|
|
182
|
-
return next({
|
|
180
|
+
return next({
|
|
181
|
+
payload: payload.data,
|
|
182
|
+
params: payload.params,
|
|
183
|
+
});
|
|
183
184
|
});
|
|
184
185
|
this.identityJWKSRoute = async (_, response) => {
|
|
185
186
|
response.send(await this.getIdentityJWKS());
|
|
@@ -210,5 +211,48 @@ class ServiceIdentity {
|
|
|
210
211
|
});
|
|
211
212
|
}
|
|
212
213
|
}
|
|
214
|
+
// Implementation
|
|
215
|
+
async callServiceV2(service, method, url, options) {
|
|
216
|
+
const { data, responseType, customHeaders, params } = options || {};
|
|
217
|
+
// HTTP methods that should not have a request body
|
|
218
|
+
const methodsWithoutBody = ['GET', 'HEAD', 'DELETE', 'OPTIONS'];
|
|
219
|
+
const shouldIncludeBody = !methodsWithoutBody.includes(method);
|
|
220
|
+
const jwt = await this.signJWT(service, method, url, data, params);
|
|
221
|
+
const request = {
|
|
222
|
+
headers: {
|
|
223
|
+
[JWT_HEADER_NAME]: jwt,
|
|
224
|
+
...(0, requestTracer_1.getRequestIdHeader)(),
|
|
225
|
+
...customHeaders,
|
|
226
|
+
},
|
|
227
|
+
baseURL: `http://${service}:8080/`,
|
|
228
|
+
url,
|
|
229
|
+
method,
|
|
230
|
+
responseType,
|
|
231
|
+
...(params ? { params } : {}),
|
|
232
|
+
...(data && shouldIncludeBody ? { data } : {}),
|
|
233
|
+
};
|
|
234
|
+
const response = await this.axiosClient.request(request);
|
|
235
|
+
return response.data;
|
|
236
|
+
}
|
|
237
|
+
// Implementation
|
|
238
|
+
async callService(service, method, url, dataOrOptions, responseType, customHeaders, params) {
|
|
239
|
+
// Check if using new options object pattern
|
|
240
|
+
if (dataOrOptions &&
|
|
241
|
+
typeof dataOrOptions === 'object' &&
|
|
242
|
+
('data' in dataOrOptions ||
|
|
243
|
+
'responseType' in dataOrOptions ||
|
|
244
|
+
'customHeaders' in dataOrOptions ||
|
|
245
|
+
'params' in dataOrOptions)) {
|
|
246
|
+
// Delegate to V2 with options object
|
|
247
|
+
return this.callServiceV2(service, method, url, dataOrOptions);
|
|
248
|
+
}
|
|
249
|
+
// Old positional parameters pattern - delegate to V2
|
|
250
|
+
return this.callServiceV2(service, method, url, {
|
|
251
|
+
data: dataOrOptions,
|
|
252
|
+
responseType,
|
|
253
|
+
customHeaders,
|
|
254
|
+
params,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
213
257
|
}
|
|
214
258
|
exports.ServiceIdentity = ServiceIdentity;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucaapp/service-utils",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -81,5 +81,8 @@
|
|
|
81
81
|
"vite-tsconfig-paths": "4.3.2",
|
|
82
82
|
"vitest": "3.2.4"
|
|
83
83
|
},
|
|
84
|
-
"resolutions": {
|
|
84
|
+
"resolutions": {
|
|
85
|
+
"tar": "^7.5.7",
|
|
86
|
+
"lodash": "^4.17.23"
|
|
87
|
+
}
|
|
85
88
|
}
|