@infineit-nestjs/services 1.1.0-cursor-ai.21 → 1.1.0-cursor-ai.22
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/cjs/services/callservice/aggregator/enrichment.config.js +1 -1
- package/dist/cjs/services/callservice/observability/metrics.d.ts +3 -3
- package/dist/cjs/services/callservice/observability/metrics.js +1 -1
- package/dist/cjs/services/callservice/registry/registry.service.js +1 -1
- package/dist/cjs/services/callservice-13mar26/aggregator/batch.helper.d.ts +17 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/enrichment.config.d.ts +6 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/enrichment.service.d.ts +20 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/enrichment.types.d.ts +114 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/enrichment.worker.d.ts +1 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/erp-response.helper.d.ts +24 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/merge.helper.d.ts +8 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/policies.d.ts +15 -0
- package/dist/cjs/services/callservice-13mar26/aggregator/projection.helper.d.ts +3 -0
- package/dist/cjs/services/callservice-13mar26/callservice.module.d.ts +2 -0
- package/dist/cjs/services/callservice-13mar26/config/http.config.d.ts +21 -0
- package/dist/cjs/services/callservice-13mar26/http/breaker.registry.d.ts +3 -0
- package/dist/cjs/services/callservice-13mar26/http/client.d.ts +17 -0
- package/dist/cjs/services/callservice-13mar26/http/error.types.d.ts +16 -0
- package/dist/cjs/services/callservice-13mar26/http/p-queue.interop.d.ts +6 -0
- package/dist/cjs/services/callservice-13mar26/http/types.d.ts +8 -0
- package/dist/cjs/services/callservice-13mar26/observability/logger.d.ts +5 -0
- package/dist/cjs/services/callservice-13mar26/observability/metrics.d.ts +4 -0
- package/dist/cjs/services/callservice-13mar26/observability/tracing.d.ts +1 -0
- package/dist/cjs/services/callservice-13mar26/registry/registry.module.d.ts +2 -0
- package/dist/cjs/services/callservice-13mar26/registry/registry.service.d.ts +15 -0
- package/dist/cjs/services/callservice-13mar26/registry/registry.types.d.ts +14 -0
- package/dist/es/services/callservice/aggregator/enrichment.config.mjs +1 -1
- package/dist/es/services/callservice/observability/metrics.d.ts +3 -3
- package/dist/es/services/callservice/observability/metrics.mjs +1 -1
- package/dist/es/services/callservice/registry/registry.service.mjs +1 -1
- package/dist/es/services/callservice-13mar26/aggregator/batch.helper.d.ts +17 -0
- package/dist/es/services/callservice-13mar26/aggregator/enrichment.config.d.ts +6 -0
- package/dist/es/services/callservice-13mar26/aggregator/enrichment.service.d.ts +20 -0
- package/dist/es/services/callservice-13mar26/aggregator/enrichment.types.d.ts +114 -0
- package/dist/es/services/callservice-13mar26/aggregator/enrichment.worker.d.ts +1 -0
- package/dist/es/services/callservice-13mar26/aggregator/erp-response.helper.d.ts +24 -0
- package/dist/es/services/callservice-13mar26/aggregator/merge.helper.d.ts +8 -0
- package/dist/es/services/callservice-13mar26/aggregator/policies.d.ts +15 -0
- package/dist/es/services/callservice-13mar26/aggregator/projection.helper.d.ts +3 -0
- package/dist/es/services/callservice-13mar26/callservice.module.d.ts +2 -0
- package/dist/es/services/callservice-13mar26/config/http.config.d.ts +21 -0
- package/dist/es/services/callservice-13mar26/http/breaker.registry.d.ts +3 -0
- package/dist/es/services/callservice-13mar26/http/client.d.ts +17 -0
- package/dist/es/services/callservice-13mar26/http/error.types.d.ts +16 -0
- package/dist/es/services/callservice-13mar26/http/p-queue.interop.d.ts +6 -0
- package/dist/es/services/callservice-13mar26/http/types.d.ts +8 -0
- package/dist/es/services/callservice-13mar26/observability/logger.d.ts +5 -0
- package/dist/es/services/callservice-13mar26/observability/metrics.d.ts +4 -0
- package/dist/es/services/callservice-13mar26/observability/tracing.d.ts +1 -0
- package/dist/es/services/callservice-13mar26/registry/registry.module.d.ts +2 -0
- package/dist/es/services/callservice-13mar26/registry/registry.service.d.ts +15 -0
- package/dist/es/services/callservice-13mar26/registry/registry.types.d.ts +14 -0
- package/package.json +4 -4
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const e="degrade",t="first",r="skip";function i(e){return"string"==typeof e.key&&"string"==typeof e.serviceName}function o(i){const o=i.project_id?.trim();if(!o)throw new Error("project_id is required for legacy enrichment config");const a=i.mapTo??i.key;return{field:i.key,project_id:o,service:i.serviceName,api_version:"v1",method:"POST",filterMode:"global",pagination:null,query:null,map:{localKey:i.key,remoteKey:"id"},mapTo:a,scope:{type:"root",path:i.key},attach_as:{field:a,type:"object"},select:null,remove_local_key:!1,onFailure:e,isRequired:i.isRequired??!1,onDuplicate:t,onEmpty:r,fallback:null}}function a(e){const t=[],r=e.method??"GET";if(e.project_id?.trim()||t.push("project_id is required"),e.service?.trim()||t.push("service is required"),e.map?e.map.localKey?.trim()||t.push("map.localKey is required"):t.push("map is required"),e.method&&!["GET","POST"].includes(e.method)&&t.push('method must be "GET" or "POST"'),"GET"===r&&"body"in e&&void 0!==e.body&&t.push("GET enrichment must not send a body; use query params only"),"POST"===r&&(void 0!==e.pagination&&t.push("POST config cannot define pagination; use GET with pagination"),void 0!==e.query?.sort&&(e.query.sort?.length??0)>0&&t.push("POST config cannot define query.sort (query-only); use GET")),e.filterMode&&!["scoped","global"].includes(e.filterMode)&&t.push('filterMode must be "scoped" or "global"'),e.onFailure&&!["degrade","fail","fallback"].includes(e.onFailure)&&t.push('onFailure must be "degrade", "fail", or "fallback"'),e.onDuplicate&&!["error","first","last"].includes(e.onDuplicate)&&t.push('onDuplicate must be "error", "first", or "last"'),e.onEmpty&&!["skip","call","error"].includes(e.onEmpty)&&t.push('onEmpty must be "skip", "call", or "error"'),e.query){if(null!=e.query.filters)if(Array.isArray(e.query.filters))for(let r=0;r<e.query.filters.length;r++){const i=e.query.filters[r];i.field?.trim()||t.push(`query.filters[${r}].field is required`),["IN","EQ"].includes(i.operator)||t.push(`query.filters[${r}].operator must be IN or EQ`),i.valueFrom?.trim()||t.push(`query.filters[${r}].valueFrom is required`)}else t.push("query.filters must be an array");if(null!=e.query.sort&&Array.isArray(e.query.sort))for(let r=0;r<e.query.sort.length;r++){const i=e.query.sort[r];i.field?.trim()||t.push(`query.sort[${r}].field is required`),["ASC","DESC"].includes(i.direction)||t.push(`query.sort[${r}].direction must be ASC or DESC`)}}if(null!=e.pagination&&("all"!==e.pagination.pagination&&t.push('pagination.pagination must be "all"'),("number"!=typeof e.pagination.page||e.pagination.page<1)&&t.push("pagination.page must be a positive number"),("number"!=typeof e.pagination.limit||e.pagination.limit<1)&&t.push("pagination.limit must be a positive number")),null!=e.scope&&(["array","object","root"].includes(e.scope.type)||t.push('scope.type must be "array", "object", or "root"'),"array"!==e.scope.type&&"object"!==e.scope.type||e.scope.path?.trim()||t.push('scope.path is required when scope.type is "array" or "object"'),null==e.scope.mode||["single","batched"].includes(e.scope.mode)||t.push('scope.mode must be "single" or "batched"'),null!=e.scope.batch_size)){const r=Number(e.scope.batch_size);(!Number.isInteger(r)||r<1||r>100)&&t.push("scope.batch_size must be an integer between 1 and 100")}if(null!=e.attach_as&&(e.attach_as.field?.trim()||t.push("attach_as.field is required when attach_as is set"),["array","object","scalar"].includes(e.attach_as.type)||t.push('attach_as.type must be "array", "object", or "scalar"')),null!=e.select){
|
|
1
|
+
"use strict";const e="degrade",t="first",r="skip";function i(e){return"string"==typeof e.key&&"string"==typeof e.serviceName}function o(i){const o=i.project_id?.trim();if(!o)throw new Error("project_id is required for legacy enrichment config");const a=i.mapTo??i.key;return{field:i.key,project_id:o,service:i.serviceName,api_version:"v1",method:"POST",filterMode:"global",pagination:null,query:null,map:{localKey:i.key,remoteKey:"id"},mapTo:a,scope:{type:"root",path:i.key},attach_as:{field:a,type:"object"},select:null,remove_local_key:!1,onFailure:e,isRequired:i.isRequired??!1,onDuplicate:t,onEmpty:r,fallback:null}}function a(e){const t=[],r=e.method??"GET";if(e.project_id?.trim()||t.push("project_id is required"),e.service?.trim()||t.push("service is required"),e.map?e.map.localKey?.trim()||t.push("map.localKey is required"):t.push("map is required"),e.method&&!["GET","POST"].includes(e.method)&&t.push('method must be "GET" or "POST"'),"GET"===r&&"body"in e&&void 0!==e.body&&t.push("GET enrichment must not send a body; use query params only"),"POST"===r&&(void 0!==e.pagination&&t.push("POST config cannot define pagination; use GET with pagination"),void 0!==e.query?.sort&&(e.query.sort?.length??0)>0&&t.push("POST config cannot define query.sort (query-only); use GET")),e.filterMode&&!["scoped","global"].includes(e.filterMode)&&t.push('filterMode must be "scoped" or "global"'),e.onFailure&&!["degrade","fail","fallback"].includes(e.onFailure)&&t.push('onFailure must be "degrade", "fail", or "fallback"'),e.onDuplicate&&!["error","first","last"].includes(e.onDuplicate)&&t.push('onDuplicate must be "error", "first", or "last"'),e.onEmpty&&!["skip","call","error"].includes(e.onEmpty)&&t.push('onEmpty must be "skip", "call", or "error"'),e.query){if(null!=e.query.filters)if(Array.isArray(e.query.filters))for(let r=0;r<e.query.filters.length;r++){const i=e.query.filters[r];i.field?.trim()||t.push(`query.filters[${r}].field is required`),["IN","EQ"].includes(i.operator)||t.push(`query.filters[${r}].operator must be IN or EQ`),i.valueFrom?.trim()||t.push(`query.filters[${r}].valueFrom is required`)}else t.push("query.filters must be an array");if(null!=e.query.sort&&Array.isArray(e.query.sort))for(let r=0;r<e.query.sort.length;r++){const i=e.query.sort[r];i.field?.trim()||t.push(`query.sort[${r}].field is required`),["ASC","DESC"].includes(i.direction)||t.push(`query.sort[${r}].direction must be ASC or DESC`)}}if(null!=e.pagination&&("all"!==e.pagination.pagination&&t.push('pagination.pagination must be "all"'),("number"!=typeof e.pagination.page||e.pagination.page<1)&&t.push("pagination.page must be a positive number"),("number"!=typeof e.pagination.limit||e.pagination.limit<1)&&t.push("pagination.limit must be a positive number")),null!=e.scope&&(["array","object","root"].includes(e.scope.type)||t.push('scope.type must be "array", "object", or "root"'),"array"!==e.scope.type&&"object"!==e.scope.type||e.scope.path?.trim()||t.push('scope.path is required when scope.type is "array" or "object"'),null==e.scope.mode||["single","batched"].includes(e.scope.mode)||t.push('scope.mode must be "single" or "batched"'),null!=e.scope.batch_size)){const r=Number(e.scope.batch_size);(!Number.isInteger(r)||r<1||r>100)&&t.push("scope.batch_size must be an integer between 1 and 100")}if(null!=e.attach_as&&(e.attach_as.field?.trim()||t.push("attach_as.field is required when attach_as is set"),["array","object","scalar"].includes(e.attach_as.type)||t.push('attach_as.type must be "array", "object", or "scalar"')),null!=e.select){const r=e.select.include;if(null!=r&&Array.isArray(r)&&r.length>0){const i=new Set(r.filter(e=>"string"==typeof e&&e.trim()));if(null!=e.select.rename&&"object"==typeof e.select.rename)for(const r of Object.keys(e.select.rename))i.has(r)||t.push(`select.rename key "${r}" must be in select.include`)}}return t}function s(i){const o=i.mapTo??i.map.localKey;let a=i.scope??{type:"root",path:""};if("root"===a.type||"array"===a.type||"object"===a.type){const e=a.mode??"batched",t=Math.min(100,Math.max(1,a.batch_size??50));a={...a,mode:e,batch_size:t}}const s=i.attach_as??{field:o,type:"object"},n=i.remove_local_key??!0,l="root"===a.type?a.path?.trim()||i.map.localKey:a.path??i.map.localKey,c={localKey:i.map.localKey,remoteKey:i.map.remoteKey?.trim()?i.map.remoteKey:i.map.localKey};let u=null;if(null!=i.select?.include&&Array.isArray(i.select.include)&&i.select.include.length>0){const e=i.select.include.filter(e=>"string"==typeof e&&e.trim());if(e.length>0){u={include:e,rename:null!=i.select.rename&&"object"==typeof i.select.rename?i.select.rename:{}}}}const p=i.project_id?.trim();if(!p)throw new Error("project_id is required for enterprise enrichment config");return{field:l,project_id:p,service:i.service,api_version:i.api_version??"v1",method:i.method??"GET",filterMode:i.filterMode??"scoped",pagination:i.pagination??null,query:i.query??null,map:c,mapTo:o,scope:a,attach_as:s,select:u,remove_local_key:n,onFailure:i.onFailure??e,isRequired:i.isRequired??!1,onDuplicate:i.onDuplicate??t,onEmpty:i.onEmpty??r,fallback:i.fallback??null}}exports.isLegacyConfig=i,exports.normalizeEnrichConfig=function(e){if(i(e))return o(e);const t=a(e);if(t.length>0)throw new Error(`Invalid enrichment config: ${t.join("; ")}`);return s(e)},exports.normalizeEnterpriseConfig=s,exports.normalizeLegacyConfig=o,exports.validateEnterpriseConfig=a;
|
|
2
2
|
//# sourceMappingURL=enrichment.config.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Counter, Gauge, Histogram } from 'prom-client';
|
|
2
|
-
export declare const breakerState: Gauge<
|
|
3
|
-
export declare const enrichmentDegradedTotal: Counter<
|
|
4
|
-
export declare const enrichmentCallDurationSeconds: Histogram<
|
|
2
|
+
export declare const breakerState: Gauge<string>;
|
|
3
|
+
export declare const enrichmentDegradedTotal: Counter<string>;
|
|
4
|
+
export declare const enrichmentCallDurationSeconds: Histogram<string>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("prom-client");const r=new e.Gauge({name:"breaker_state",help:"Circuit breaker state (1=open,0=closed)",labelNames:["project_id","service"]}),t=new e.Counter({name:"enrichment_degraded_total",help:"Total number of degraded enrichment calls",labelNames:["project_id","service","type"]}),
|
|
1
|
+
"use strict";var e=require("prom-client");const t=function(t){const r=e.register.getSingleMetric(t.name);return r||new e.Gauge(t)}({name:"breaker_state",help:"Circuit breaker state (1=open,0=closed)",labelNames:["project_id","service"]}),r=function(t){const r=e.register.getSingleMetric(t.name);return r||new e.Counter(t)}({name:"enrichment_degraded_total",help:"Total number of degraded enrichment calls",labelNames:["project_id","service","type"]}),n=function(t){const r=e.register.getSingleMetric(t.name);return r||new e.Histogram(t)}({name:"enrichment_call_duration_seconds",help:"Duration of enrichment remote calls in seconds",labelNames:["service"],buckets:[.01,.05,.1,.25,.5,1,2.5,5]});exports.breakerState=t,exports.enrichmentCallDurationSeconds=n,exports.enrichmentDegradedTotal=r;
|
|
2
2
|
//# sourceMappingURL=metrics.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("../../../node_modules/tslib/tslib.es6.js"),
|
|
1
|
+
"use strict";var e=require("../../../node_modules/tslib/tslib.es6.js"),t=require("@nestjs/common"),r=require("@infineit/winston-logger"),s=require("../../redis.service.js");const i="REGISTRY_API_URL";exports.RegistryService=class{constructor(e,t){this.redisService=e,this.logger=t,this.l1=new Map}async resolve(e,t,r){const s=r??"v1",i=`${e}:${t}:${s}`;return(await this.resolveInternal(i,e,t,s)).base_url}async resolveFull(e,t,r){const s=r??"v1",i=`${e}:${t}:${s}`;return this.resolveInternal(i,e,t,s)}async resolveInternal(e,t,r,s){const i=Date.now(),o=this.l1.get(e);if(o&&o.expiresAt>i)return this.log("debug",`Registry L1 hit: ${e}`),o.value;o&&this.l1.delete(e);const n="registry:"+e,a=this.redisService.getPublisherClient();try{const t=await a.get(n);if(t){const r=JSON.parse(t);return this.log("debug",`Registry L2 hit: ${e}`),this.setL1(e,r),r}}catch(t){this.log("warn",`Registry L2 get error for ${e}`,t)}this.log("debug",`Registry cache miss: ${e}`);const l=await this.fetchFromRegistry(t,r,s);this.setL1(e,l);try{await a.setex(n,20,JSON.stringify(l))}catch(t){this.log("warn",`Registry L2 set error for ${e}`,t)}return l}setL1(e,t){this.l1.set(e,{value:t,expiresAt:Date.now()+4e3})}async fetchFromRegistry(e,t,r){const s=process.env[i];if(!s?.trim())throw new Error(`${i} environment variable is required for registry lookups. Set it to the central registry API base URL.`);const o=new URL(s);let n,a;o.pathname=o.pathname.replace(/\/?$/,"")+"/resolve",o.searchParams.set("project_id",encodeURIComponent(e)),this.log("debug",`Registry API call: ${o.toString()}`);try{n=await fetch(o.toString(),{method:"GET"})}catch(e){throw this.log("error",`Registry API fetch failed: ${o.toString()}`,e),e}if(!n.ok){const e=await n.text();throw this.log("error",`Registry API error ${n.status}: ${e}`),new Error(`Registry API returned ${n.status}: ${e}`)}try{a=await n.json()}catch(e){throw this.log("error","Registry API response not JSON",e),new Error("Registry API response was not valid JSON")}const l=(Array.isArray(a)?a:[a]).filter(e=>!1!==e.healthy&&e.base_url);if(0===l.length)throw this.log("warn",`No healthy instance for ${e}:${t}:${r}`),new Error(`No healthy instance found for ${e}:${t}:${r}. Check registry and health status.`);const g=l[0],c=(g.base_url||"").replace(/\/$/,""),h={base_url:c?`${c}/api/${r}/${t}`:`http://localhost/api/${r}/${t}`,version:g.version??r,timeout:"number"==typeof g.timeout?g.timeout:200,retry_policy:"number"==typeof g.retry_policy?g.retry_policy:2};return this.log("debug",`Registry resolved: ${h.base_url}`),h}log(e,t,r){"debug"===e?this.logger.debug?.(t):"warn"===e?this.logger.warn?.(t):this.logger.error?.(t,r)}},exports.RegistryService=e.__decorate([t.Injectable(),e.__metadata("design:paramtypes",[s.RedisService,r.LoggerService])],exports.RegistryService);
|
|
2
2
|
//# sourceMappingURL=registry.service.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function getValueByPath(obj: any, path: string): unknown;
|
|
2
|
+
export declare function extractValuesFromItem(item: any, field: string, valueFromKey?: string): unknown[];
|
|
3
|
+
export declare function extractValuesByField(items: any[], field: string, valueFromKey?: string, chunkSize?: number): unknown[][];
|
|
4
|
+
export declare function extractScopedValues(items: any[], field: string, valueFromKey?: string): {
|
|
5
|
+
scopeIndex: number;
|
|
6
|
+
values: unknown[];
|
|
7
|
+
}[];
|
|
8
|
+
export type ScopeType = 'array' | 'object' | 'root';
|
|
9
|
+
export declare function extractScopedValuesByScope(items: any[], scope: {
|
|
10
|
+
type: ScopeType;
|
|
11
|
+
path?: string;
|
|
12
|
+
}, localKey: string, valueFromKey?: string): {
|
|
13
|
+
scopeIndex: number;
|
|
14
|
+
values: unknown[];
|
|
15
|
+
}[];
|
|
16
|
+
export declare function itemsContainingValues(items: any[], field: string, valueSet: Set<unknown>, valueFromKey?: string): any[];
|
|
17
|
+
export declare function dedupeAndChunk(items: any[], key: string, chunkSize?: number): any[][];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IEnrichConfig, IEnrichConfigEnterprise, INormalizedEnrichConfig, EnrichConfigInput } from './enrichment.types';
|
|
2
|
+
export declare function isLegacyConfig(cfg: EnrichConfigInput): cfg is IEnrichConfig;
|
|
3
|
+
export declare function normalizeLegacyConfig(cfg: IEnrichConfig): INormalizedEnrichConfig;
|
|
4
|
+
export declare function validateEnterpriseConfig(cfg: IEnrichConfigEnterprise): string[];
|
|
5
|
+
export declare function normalizeEnterpriseConfig(cfg: IEnrichConfigEnterprise): INormalizedEnrichConfig;
|
|
6
|
+
export declare function normalizeEnrichConfig(cfg: EnrichConfigInput): INormalizedEnrichConfig;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EnrichConfigInput, IDegradedItem } from './enrichment.types';
|
|
2
|
+
import { RegistryService } from '../registry/registry.service';
|
|
3
|
+
export type { IEnrichConfig, IEnrichConfigEnterprise, EnrichConfigInput, IDegradedItem, } from './enrichment.types';
|
|
4
|
+
export declare class EnrichmentService {
|
|
5
|
+
private readonly registry;
|
|
6
|
+
constructor(registry: RegistryService);
|
|
7
|
+
private recordDegraded;
|
|
8
|
+
enrich(data: any[], configs: EnrichConfigInput[], concurrency?: number, correlationId?: string): Promise<{
|
|
9
|
+
result: any;
|
|
10
|
+
degraded: IDegradedItem[];
|
|
11
|
+
}>;
|
|
12
|
+
private getResponseItems;
|
|
13
|
+
private runScopedEnrichment;
|
|
14
|
+
private runGlobalEnrichment;
|
|
15
|
+
private filterValueToString;
|
|
16
|
+
private buildBody;
|
|
17
|
+
private buildQueryParams;
|
|
18
|
+
private normalizeResponse;
|
|
19
|
+
private callRemote;
|
|
20
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export interface IEnrichConfig {
|
|
2
|
+
key: string;
|
|
3
|
+
mapTo?: string;
|
|
4
|
+
project_id: string;
|
|
5
|
+
serviceName: string;
|
|
6
|
+
isRequired?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface IEnrichQueryFilter {
|
|
9
|
+
field: string;
|
|
10
|
+
operator: 'IN' | 'EQ';
|
|
11
|
+
valueFrom: string;
|
|
12
|
+
}
|
|
13
|
+
export interface IEnrichQuerySort {
|
|
14
|
+
field: string;
|
|
15
|
+
direction: 'ASC' | 'DESC';
|
|
16
|
+
}
|
|
17
|
+
export interface IEnrichQuery {
|
|
18
|
+
filters?: IEnrichQueryFilter[];
|
|
19
|
+
sort?: IEnrichQuerySort[];
|
|
20
|
+
}
|
|
21
|
+
export interface IEnrichPagination {
|
|
22
|
+
pagination: 'all' | 'no';
|
|
23
|
+
page: number;
|
|
24
|
+
limit: number;
|
|
25
|
+
}
|
|
26
|
+
export interface IEnrichMap {
|
|
27
|
+
localKey: string;
|
|
28
|
+
remoteKey?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface IEnrichMapNormalized extends IEnrichMap {
|
|
31
|
+
remoteKey: string;
|
|
32
|
+
}
|
|
33
|
+
export interface IEnrichScope {
|
|
34
|
+
type: 'array' | 'object' | 'root';
|
|
35
|
+
path?: string;
|
|
36
|
+
mode?: 'single' | 'batched';
|
|
37
|
+
batch_size?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface IEnrichSelect {
|
|
40
|
+
include?: string[];
|
|
41
|
+
rename?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
export interface IEnrichSelectNormalized {
|
|
44
|
+
include: string[];
|
|
45
|
+
rename: Record<string, string>;
|
|
46
|
+
}
|
|
47
|
+
export interface IAttachAs {
|
|
48
|
+
field: string;
|
|
49
|
+
type: 'array' | 'object' | 'scalar';
|
|
50
|
+
}
|
|
51
|
+
export interface IEnrichFallback {
|
|
52
|
+
api_version?: string;
|
|
53
|
+
}
|
|
54
|
+
export interface IEnrichConfigEnterprise {
|
|
55
|
+
project_id: string;
|
|
56
|
+
service: string;
|
|
57
|
+
api_version?: string;
|
|
58
|
+
method?: 'GET' | 'POST';
|
|
59
|
+
filterMode?: 'scoped' | 'global';
|
|
60
|
+
pagination?: IEnrichPagination;
|
|
61
|
+
query?: IEnrichQuery;
|
|
62
|
+
map: IEnrichMap;
|
|
63
|
+
mapTo?: string;
|
|
64
|
+
scope?: IEnrichScope;
|
|
65
|
+
attach_as?: IAttachAs;
|
|
66
|
+
select?: IEnrichSelect;
|
|
67
|
+
remove_local_key?: boolean;
|
|
68
|
+
onFailure?: 'degrade' | 'fail' | 'fallback';
|
|
69
|
+
isRequired?: boolean;
|
|
70
|
+
onDuplicate?: 'error' | 'first' | 'last';
|
|
71
|
+
onEmpty?: 'skip' | 'call' | 'error';
|
|
72
|
+
fallback?: IEnrichFallback;
|
|
73
|
+
}
|
|
74
|
+
export type EnrichConfigInput = IEnrichConfig | IEnrichConfigEnterprise;
|
|
75
|
+
export interface INormalizedEnrichConfig {
|
|
76
|
+
field: string;
|
|
77
|
+
project_id: string;
|
|
78
|
+
service: string;
|
|
79
|
+
api_version: string;
|
|
80
|
+
method: 'GET' | 'POST';
|
|
81
|
+
filterMode: 'scoped' | 'global';
|
|
82
|
+
pagination: IEnrichPagination | null;
|
|
83
|
+
query: IEnrichQuery | null;
|
|
84
|
+
map: IEnrichMapNormalized;
|
|
85
|
+
mapTo: string;
|
|
86
|
+
scope: IEnrichScope;
|
|
87
|
+
attach_as: IAttachAs;
|
|
88
|
+
select: IEnrichSelectNormalized | null;
|
|
89
|
+
remove_local_key: boolean;
|
|
90
|
+
onFailure: 'degrade' | 'fail' | 'fallback';
|
|
91
|
+
isRequired: boolean;
|
|
92
|
+
onDuplicate: 'error' | 'first' | 'last';
|
|
93
|
+
onEmpty: 'skip' | 'call' | 'error';
|
|
94
|
+
fallback: IEnrichFallback | null;
|
|
95
|
+
}
|
|
96
|
+
export interface IEnrichmentSlot {
|
|
97
|
+
field: string;
|
|
98
|
+
mapTo: string;
|
|
99
|
+
map: IEnrichMapNormalized;
|
|
100
|
+
onDuplicate: 'error' | 'first' | 'last';
|
|
101
|
+
scope: IEnrichScope;
|
|
102
|
+
attach_as: IAttachAs;
|
|
103
|
+
remove_local_key: boolean;
|
|
104
|
+
data: Record<string, unknown> | unknown[];
|
|
105
|
+
remoteKeyForLookup?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface IDegradedItem {
|
|
108
|
+
project_id: string;
|
|
109
|
+
service: string;
|
|
110
|
+
error: string;
|
|
111
|
+
configField?: string;
|
|
112
|
+
type?: string;
|
|
113
|
+
statusCode?: number;
|
|
114
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IDegradedItem } from './enrichment.types';
|
|
2
|
+
export interface IErpError {
|
|
3
|
+
field: string;
|
|
4
|
+
service: string;
|
|
5
|
+
type: string;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export interface IErpResponse<T = unknown> {
|
|
9
|
+
data: T;
|
|
10
|
+
errors: IErpError[];
|
|
11
|
+
degraded: string[];
|
|
12
|
+
meta: {
|
|
13
|
+
partial: boolean;
|
|
14
|
+
requestId?: string;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface IBuildErpResponseOptions {
|
|
19
|
+
requestId?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function buildErpResponse<T>(enrichResult: {
|
|
22
|
+
result: T;
|
|
23
|
+
degraded: IDegradedItem[];
|
|
24
|
+
}, options?: IBuildErpResponseOptions): IErpResponse<T>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IEnrichMapNormalized, IEnrichScope, IAttachAs } from './enrichment.types';
|
|
2
|
+
export declare function mergeWithMap(original: any[], map: IEnrichMapNormalized, mapTo: string, data: Record<string, any>, onDuplicate: 'error' | 'first' | 'last'): void;
|
|
3
|
+
export declare function mergeWithScopeAndAttach(original: any[], scope: IEnrichScope, attach_as: IAttachAs, map: IEnrichMapNormalized, data: Record<string, any>, onDuplicate: 'error' | 'first' | 'last', remove_local_key: boolean, remoteKeyForLookup?: string): void;
|
|
4
|
+
export declare function mergeResultsDynamic(original: any[], enrichments: {
|
|
5
|
+
key: string;
|
|
6
|
+
mapTo?: string;
|
|
7
|
+
data: Record<string, any>;
|
|
8
|
+
}[]): any[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface IServiceSLA {
|
|
2
|
+
timeout: number;
|
|
3
|
+
retries: number;
|
|
4
|
+
errorThreshold?: number;
|
|
5
|
+
resetTimeout?: number;
|
|
6
|
+
isCritical?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const SERVICE_SLA: Record<string, IServiceSLA>;
|
|
9
|
+
export declare function getServiceSLA(serviceName: string): IServiceSLA;
|
|
10
|
+
export declare function getTimeout(serviceName: string, _operation?: string): number;
|
|
11
|
+
export declare function getRetries(serviceName: string, _operation?: string): number;
|
|
12
|
+
export declare function isCritical(serviceName: string): boolean;
|
|
13
|
+
export declare function getErrorThreshold(serviceName: string): number;
|
|
14
|
+
export declare function getResetTimeout(serviceName: string): number;
|
|
15
|
+
export declare const OPERATION_SLA: Record<string, IServiceSLA>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { IEnrichSelectNormalized } from './enrichment.types';
|
|
2
|
+
export declare function applyProjection(items: any[], select: IEnrichSelectNormalized | null): any[];
|
|
3
|
+
export declare function getRemoteKeyForLookup(remoteKey: string, select: IEnrichSelectNormalized | null): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const HTTP_CONFIG: {
|
|
2
|
+
TIMEOUT_MS: number;
|
|
3
|
+
RETRIES: number;
|
|
4
|
+
BULKHEAD_CONCURRENCY: number;
|
|
5
|
+
BREAKER_THRESHOLD: number;
|
|
6
|
+
BREAKER_RESET_MS: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const SERVICE_SLA: {
|
|
9
|
+
user: {
|
|
10
|
+
timeout: number;
|
|
11
|
+
retries: number;
|
|
12
|
+
};
|
|
13
|
+
orders: {
|
|
14
|
+
timeout: number;
|
|
15
|
+
retries: number;
|
|
16
|
+
};
|
|
17
|
+
loyalty: {
|
|
18
|
+
timeout: number;
|
|
19
|
+
retries: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { QueueAddOptions } from 'p-queue';
|
|
2
|
+
import PriorityQueue from 'p-queue/dist/priority-queue';
|
|
3
|
+
import { Dispatcher } from 'undici';
|
|
4
|
+
import { IHttpRequestOptions } from './types';
|
|
5
|
+
import type PQueue from 'p-queue';
|
|
6
|
+
export declare function createBulkhead(concurrency?: number): PQueue<PriorityQueue, QueueAddOptions>;
|
|
7
|
+
export declare function httpRequest<T>(options: IHttpRequestOptions, dispatcher?: Dispatcher): Promise<T>;
|
|
8
|
+
export declare function withRetry<T>(fn: () => Promise<T>, retries?: number): Promise<T>;
|
|
9
|
+
export interface ICallServiceOptions {
|
|
10
|
+
method: 'GET' | 'POST';
|
|
11
|
+
body?: any;
|
|
12
|
+
queryParams?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
export declare function callService<T>(url: string, options: ICallServiceOptions, project_id: string, serviceName: string, bulkhead: PQueue): Promise<T>;
|
|
15
|
+
export declare function callServicePost<T>(url: string, body: any, project_id: string, serviceName: string, bulkhead: PQueue): Promise<T>;
|
|
16
|
+
export type { ServiceCallResult } from './error.types';
|
|
17
|
+
export declare function callServiceWithResult<T>(url: string, options: ICallServiceOptions, project_id: string, serviceName: string, bulkhead: PQueue): Promise<import('./error.types').ServiceCallResult<T>>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ErrorCategory = 'client' | 'business' | 'infrastructure' | 'systemic';
|
|
2
|
+
export interface INormalizedError {
|
|
3
|
+
type: ErrorCategory;
|
|
4
|
+
message: string;
|
|
5
|
+
project_id: string;
|
|
6
|
+
service: string;
|
|
7
|
+
statusCode?: number;
|
|
8
|
+
code?: string;
|
|
9
|
+
}
|
|
10
|
+
export type ServiceCallResult<T> = {
|
|
11
|
+
ok: true;
|
|
12
|
+
data: T;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: INormalizedError;
|
|
16
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Counter, Gauge, Histogram } from 'prom-client';
|
|
2
|
+
export declare const breakerState: Gauge<"service" | "project_id">;
|
|
3
|
+
export declare const enrichmentDegradedTotal: Counter<"type" | "service" | "project_id">;
|
|
4
|
+
export declare const enrichmentCallDurationSeconds: Histogram<"service">;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function trace<T>(span: string, fn: () => Promise<T>, correlationId?: string): Promise<T>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LoggerService } from '@infineit/winston-logger';
|
|
2
|
+
import { RedisService } from '../../redis.service';
|
|
3
|
+
import type { IRegistryResolution } from './registry.types';
|
|
4
|
+
export declare class RegistryService {
|
|
5
|
+
private readonly redisService;
|
|
6
|
+
private readonly logger;
|
|
7
|
+
private readonly l1;
|
|
8
|
+
constructor(redisService: RedisService, logger: LoggerService);
|
|
9
|
+
resolve(projectId: string, serviceName: string, apiVersion?: string): Promise<string>;
|
|
10
|
+
resolveFull(projectId: string, serviceName: string, apiVersion?: string): Promise<IRegistryResolution>;
|
|
11
|
+
private resolveInternal;
|
|
12
|
+
private setL1;
|
|
13
|
+
private fetchFromRegistry;
|
|
14
|
+
private log;
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface IRegistryResolution {
|
|
2
|
+
base_url: string;
|
|
3
|
+
version: string;
|
|
4
|
+
timeout: number;
|
|
5
|
+
retry_policy: number;
|
|
6
|
+
}
|
|
7
|
+
export interface IRegistryApiInstance {
|
|
8
|
+
base_url: string;
|
|
9
|
+
version: string;
|
|
10
|
+
timeout: number;
|
|
11
|
+
retry_policy: number;
|
|
12
|
+
healthy?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export type IRegistryApiResponse = IRegistryApiInstance | IRegistryApiInstance[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e="degrade",t="first",r="skip";function i(e){return"string"==typeof e.key&&"string"==typeof e.serviceName}function o(i){const o=i.project_id?.trim();if(!o)throw new Error("project_id is required for legacy enrichment config");const a=i.mapTo??i.key;return{field:i.key,project_id:o,service:i.serviceName,api_version:"v1",method:"POST",filterMode:"global",pagination:null,query:null,map:{localKey:i.key,remoteKey:"id"},mapTo:a,scope:{type:"root",path:i.key},attach_as:{field:a,type:"object"},select:null,remove_local_key:!1,onFailure:e,isRequired:i.isRequired??!1,onDuplicate:t,onEmpty:r,fallback:null}}function a(e){const t=[],r=e.method??"GET";if(e.project_id?.trim()||t.push("project_id is required"),e.service?.trim()||t.push("service is required"),e.map?e.map.localKey?.trim()||t.push("map.localKey is required"):t.push("map is required"),e.method&&!["GET","POST"].includes(e.method)&&t.push('method must be "GET" or "POST"'),"GET"===r&&"body"in e&&void 0!==e.body&&t.push("GET enrichment must not send a body; use query params only"),"POST"===r&&(void 0!==e.pagination&&t.push("POST config cannot define pagination; use GET with pagination"),void 0!==e.query?.sort&&(e.query.sort?.length??0)>0&&t.push("POST config cannot define query.sort (query-only); use GET")),e.filterMode&&!["scoped","global"].includes(e.filterMode)&&t.push('filterMode must be "scoped" or "global"'),e.onFailure&&!["degrade","fail","fallback"].includes(e.onFailure)&&t.push('onFailure must be "degrade", "fail", or "fallback"'),e.onDuplicate&&!["error","first","last"].includes(e.onDuplicate)&&t.push('onDuplicate must be "error", "first", or "last"'),e.onEmpty&&!["skip","call","error"].includes(e.onEmpty)&&t.push('onEmpty must be "skip", "call", or "error"'),e.query){if(null!=e.query.filters)if(Array.isArray(e.query.filters))for(let r=0;r<e.query.filters.length;r++){const i=e.query.filters[r];i.field?.trim()||t.push(`query.filters[${r}].field is required`),["IN","EQ"].includes(i.operator)||t.push(`query.filters[${r}].operator must be IN or EQ`),i.valueFrom?.trim()||t.push(`query.filters[${r}].valueFrom is required`)}else t.push("query.filters must be an array");if(null!=e.query.sort&&Array.isArray(e.query.sort))for(let r=0;r<e.query.sort.length;r++){const i=e.query.sort[r];i.field?.trim()||t.push(`query.sort[${r}].field is required`),["ASC","DESC"].includes(i.direction)||t.push(`query.sort[${r}].direction must be ASC or DESC`)}}if(null!=e.pagination&&("all"!==e.pagination.pagination&&t.push('pagination.pagination must be "all"'),("number"!=typeof e.pagination.page||e.pagination.page<1)&&t.push("pagination.page must be a positive number"),("number"!=typeof e.pagination.limit||e.pagination.limit<1)&&t.push("pagination.limit must be a positive number")),null!=e.scope&&(["array","object","root"].includes(e.scope.type)||t.push('scope.type must be "array", "object", or "root"'),"array"!==e.scope.type&&"object"!==e.scope.type||e.scope.path?.trim()||t.push('scope.path is required when scope.type is "array" or "object"'),null==e.scope.mode||["single","batched"].includes(e.scope.mode)||t.push('scope.mode must be "single" or "batched"'),null!=e.scope.batch_size)){const r=Number(e.scope.batch_size);(!Number.isInteger(r)||r<1||r>100)&&t.push("scope.batch_size must be an integer between 1 and 100")}if(null!=e.attach_as&&(e.attach_as.field?.trim()||t.push("attach_as.field is required when attach_as is set"),["array","object","scalar"].includes(e.attach_as.type)||t.push('attach_as.type must be "array", "object", or "scalar"')),null!=e.select){
|
|
1
|
+
const e="degrade",t="first",r="skip";function i(e){return"string"==typeof e.key&&"string"==typeof e.serviceName}function o(i){const o=i.project_id?.trim();if(!o)throw new Error("project_id is required for legacy enrichment config");const a=i.mapTo??i.key;return{field:i.key,project_id:o,service:i.serviceName,api_version:"v1",method:"POST",filterMode:"global",pagination:null,query:null,map:{localKey:i.key,remoteKey:"id"},mapTo:a,scope:{type:"root",path:i.key},attach_as:{field:a,type:"object"},select:null,remove_local_key:!1,onFailure:e,isRequired:i.isRequired??!1,onDuplicate:t,onEmpty:r,fallback:null}}function a(e){const t=[],r=e.method??"GET";if(e.project_id?.trim()||t.push("project_id is required"),e.service?.trim()||t.push("service is required"),e.map?e.map.localKey?.trim()||t.push("map.localKey is required"):t.push("map is required"),e.method&&!["GET","POST"].includes(e.method)&&t.push('method must be "GET" or "POST"'),"GET"===r&&"body"in e&&void 0!==e.body&&t.push("GET enrichment must not send a body; use query params only"),"POST"===r&&(void 0!==e.pagination&&t.push("POST config cannot define pagination; use GET with pagination"),void 0!==e.query?.sort&&(e.query.sort?.length??0)>0&&t.push("POST config cannot define query.sort (query-only); use GET")),e.filterMode&&!["scoped","global"].includes(e.filterMode)&&t.push('filterMode must be "scoped" or "global"'),e.onFailure&&!["degrade","fail","fallback"].includes(e.onFailure)&&t.push('onFailure must be "degrade", "fail", or "fallback"'),e.onDuplicate&&!["error","first","last"].includes(e.onDuplicate)&&t.push('onDuplicate must be "error", "first", or "last"'),e.onEmpty&&!["skip","call","error"].includes(e.onEmpty)&&t.push('onEmpty must be "skip", "call", or "error"'),e.query){if(null!=e.query.filters)if(Array.isArray(e.query.filters))for(let r=0;r<e.query.filters.length;r++){const i=e.query.filters[r];i.field?.trim()||t.push(`query.filters[${r}].field is required`),["IN","EQ"].includes(i.operator)||t.push(`query.filters[${r}].operator must be IN or EQ`),i.valueFrom?.trim()||t.push(`query.filters[${r}].valueFrom is required`)}else t.push("query.filters must be an array");if(null!=e.query.sort&&Array.isArray(e.query.sort))for(let r=0;r<e.query.sort.length;r++){const i=e.query.sort[r];i.field?.trim()||t.push(`query.sort[${r}].field is required`),["ASC","DESC"].includes(i.direction)||t.push(`query.sort[${r}].direction must be ASC or DESC`)}}if(null!=e.pagination&&("all"!==e.pagination.pagination&&t.push('pagination.pagination must be "all"'),("number"!=typeof e.pagination.page||e.pagination.page<1)&&t.push("pagination.page must be a positive number"),("number"!=typeof e.pagination.limit||e.pagination.limit<1)&&t.push("pagination.limit must be a positive number")),null!=e.scope&&(["array","object","root"].includes(e.scope.type)||t.push('scope.type must be "array", "object", or "root"'),"array"!==e.scope.type&&"object"!==e.scope.type||e.scope.path?.trim()||t.push('scope.path is required when scope.type is "array" or "object"'),null==e.scope.mode||["single","batched"].includes(e.scope.mode)||t.push('scope.mode must be "single" or "batched"'),null!=e.scope.batch_size)){const r=Number(e.scope.batch_size);(!Number.isInteger(r)||r<1||r>100)&&t.push("scope.batch_size must be an integer between 1 and 100")}if(null!=e.attach_as&&(e.attach_as.field?.trim()||t.push("attach_as.field is required when attach_as is set"),["array","object","scalar"].includes(e.attach_as.type)||t.push('attach_as.type must be "array", "object", or "scalar"')),null!=e.select){const r=e.select.include;if(null!=r&&Array.isArray(r)&&r.length>0){const i=new Set(r.filter(e=>"string"==typeof e&&e.trim()));if(null!=e.select.rename&&"object"==typeof e.select.rename)for(const r of Object.keys(e.select.rename))i.has(r)||t.push(`select.rename key "${r}" must be in select.include`)}}return t}function s(i){const o=i.mapTo??i.map.localKey;let a=i.scope??{type:"root",path:""};if("root"===a.type||"array"===a.type||"object"===a.type){const e=a.mode??"batched",t=Math.min(100,Math.max(1,a.batch_size??50));a={...a,mode:e,batch_size:t}}const s=i.attach_as??{field:o,type:"object"},n=i.remove_local_key??!0,l="root"===a.type?a.path?.trim()||i.map.localKey:a.path??i.map.localKey,c={localKey:i.map.localKey,remoteKey:i.map.remoteKey?.trim()?i.map.remoteKey:i.map.localKey};let u=null;if(null!=i.select?.include&&Array.isArray(i.select.include)&&i.select.include.length>0){const e=i.select.include.filter(e=>"string"==typeof e&&e.trim());if(e.length>0){u={include:e,rename:null!=i.select.rename&&"object"==typeof i.select.rename?i.select.rename:{}}}}const p=i.project_id?.trim();if(!p)throw new Error("project_id is required for enterprise enrichment config");return{field:l,project_id:p,service:i.service,api_version:i.api_version??"v1",method:i.method??"GET",filterMode:i.filterMode??"scoped",pagination:i.pagination??null,query:i.query??null,map:c,mapTo:o,scope:a,attach_as:s,select:u,remove_local_key:n,onFailure:i.onFailure??e,isRequired:i.isRequired??!1,onDuplicate:i.onDuplicate??t,onEmpty:i.onEmpty??r,fallback:i.fallback??null}}function n(e){if(i(e))return o(e);const t=a(e);if(t.length>0)throw new Error(`Invalid enrichment config: ${t.join("; ")}`);return s(e)}export{i as isLegacyConfig,n as normalizeEnrichConfig,s as normalizeEnterpriseConfig,o as normalizeLegacyConfig,a as validateEnterpriseConfig};
|
|
2
2
|
//# sourceMappingURL=enrichment.config.mjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Counter, Gauge, Histogram } from 'prom-client';
|
|
2
|
-
export declare const breakerState: Gauge<
|
|
3
|
-
export declare const enrichmentDegradedTotal: Counter<
|
|
4
|
-
export declare const enrichmentCallDurationSeconds: Histogram<
|
|
2
|
+
export declare const breakerState: Gauge<string>;
|
|
3
|
+
export declare const enrichmentDegradedTotal: Counter<string>;
|
|
4
|
+
export declare const enrichmentCallDurationSeconds: Histogram<string>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{register as e,Gauge as n,Counter as t,Histogram as r}from"prom-client";const c=function(t){const r=e.getSingleMetric(t.name);return r||new n(t)}({name:"breaker_state",help:"Circuit breaker state (1=open,0=closed)",labelNames:["project_id","service"]}),a=function(n){const r=e.getSingleMetric(n.name);return r||new t(n)}({name:"enrichment_degraded_total",help:"Total number of degraded enrichment calls",labelNames:["project_id","service","type"]}),i=function(n){const t=e.getSingleMetric(n.name);return t||new r(n)}({name:"enrichment_call_duration_seconds",help:"Duration of enrichment remote calls in seconds",labelNames:["service"],buckets:[.01,.05,.1,.25,.5,1,2.5,5]});export{c as breakerState,i as enrichmentCallDurationSeconds,a as enrichmentDegradedTotal};
|
|
2
2
|
//# sourceMappingURL=metrics.mjs.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as e}from"../../../node_modules/tslib/tslib.es6.mjs";import{Injectable as r}from"@nestjs/common";import{LoggerService as s}from"@infineit/winston-logger";import{RedisService as
|
|
1
|
+
import{__decorate as t,__metadata as e}from"../../../node_modules/tslib/tslib.es6.mjs";import{Injectable as r}from"@nestjs/common";import{LoggerService as s}from"@infineit/winston-logger";import{RedisService as o}from"../../redis.service.mjs";const i="REGISTRY_API_URL";let n=class{constructor(t,e){this.redisService=t,this.logger=e,this.l1=new Map}async resolve(t,e,r){const s=r??"v1",o=`${t}:${e}:${s}`;return(await this.resolveInternal(o,t,e,s)).base_url}async resolveFull(t,e,r){const s=r??"v1",o=`${t}:${e}:${s}`;return this.resolveInternal(o,t,e,s)}async resolveInternal(t,e,r,s){const o=Date.now(),i=this.l1.get(t);if(i&&i.expiresAt>o)return this.log("debug",`Registry L1 hit: ${t}`),i.value;i&&this.l1.delete(t);const n="registry:"+t,a=this.redisService.getPublisherClient();try{const e=await a.get(n);if(e){const r=JSON.parse(e);return this.log("debug",`Registry L2 hit: ${t}`),this.setL1(t,r),r}}catch(e){this.log("warn",`Registry L2 get error for ${t}`,e)}this.log("debug",`Registry cache miss: ${t}`);const l=await this.fetchFromRegistry(e,r,s);this.setL1(t,l);try{await a.setex(n,20,JSON.stringify(l))}catch(e){this.log("warn",`Registry L2 set error for ${t}`,e)}return l}setL1(t,e){this.l1.set(t,{value:e,expiresAt:Date.now()+4e3})}async fetchFromRegistry(t,e,r){const s=process.env[i];if(!s?.trim())throw new Error(`${i} environment variable is required for registry lookups. Set it to the central registry API base URL.`);const o=new URL(s);let n,a;o.pathname=o.pathname.replace(/\/?$/,"")+"/resolve",o.searchParams.set("project_id",encodeURIComponent(t)),this.log("debug",`Registry API call: ${o.toString()}`);try{n=await fetch(o.toString(),{method:"GET"})}catch(t){throw this.log("error",`Registry API fetch failed: ${o.toString()}`,t),t}if(!n.ok){const t=await n.text();throw this.log("error",`Registry API error ${n.status}: ${t}`),new Error(`Registry API returned ${n.status}: ${t}`)}try{a=await n.json()}catch(t){throw this.log("error","Registry API response not JSON",t),new Error("Registry API response was not valid JSON")}const l=(Array.isArray(a)?a:[a]).filter(t=>!1!==t.healthy&&t.base_url);if(0===l.length)throw this.log("warn",`No healthy instance for ${t}:${e}:${r}`),new Error(`No healthy instance found for ${t}:${e}:${r}. Check registry and health status.`);const h=l[0],g=(h.base_url||"").replace(/\/$/,""),c={base_url:g?`${g}/api/${r}/${e}`:`http://localhost/api/${r}/${e}`,version:h.version??r,timeout:"number"==typeof h.timeout?h.timeout:200,retry_policy:"number"==typeof h.retry_policy?h.retry_policy:2};return this.log("debug",`Registry resolved: ${c.base_url}`),c}log(t,e,r){"debug"===t?this.logger.debug?.(e):"warn"===t?this.logger.warn?.(e):this.logger.error?.(e,r)}};n=t([r(),e("design:paramtypes",[o,s])],n);export{n as RegistryService};
|
|
2
2
|
//# sourceMappingURL=registry.service.mjs.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function getValueByPath(obj: any, path: string): unknown;
|
|
2
|
+
export declare function extractValuesFromItem(item: any, field: string, valueFromKey?: string): unknown[];
|
|
3
|
+
export declare function extractValuesByField(items: any[], field: string, valueFromKey?: string, chunkSize?: number): unknown[][];
|
|
4
|
+
export declare function extractScopedValues(items: any[], field: string, valueFromKey?: string): {
|
|
5
|
+
scopeIndex: number;
|
|
6
|
+
values: unknown[];
|
|
7
|
+
}[];
|
|
8
|
+
export type ScopeType = 'array' | 'object' | 'root';
|
|
9
|
+
export declare function extractScopedValuesByScope(items: any[], scope: {
|
|
10
|
+
type: ScopeType;
|
|
11
|
+
path?: string;
|
|
12
|
+
}, localKey: string, valueFromKey?: string): {
|
|
13
|
+
scopeIndex: number;
|
|
14
|
+
values: unknown[];
|
|
15
|
+
}[];
|
|
16
|
+
export declare function itemsContainingValues(items: any[], field: string, valueSet: Set<unknown>, valueFromKey?: string): any[];
|
|
17
|
+
export declare function dedupeAndChunk(items: any[], key: string, chunkSize?: number): any[][];
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IEnrichConfig, IEnrichConfigEnterprise, INormalizedEnrichConfig, EnrichConfigInput } from './enrichment.types';
|
|
2
|
+
export declare function isLegacyConfig(cfg: EnrichConfigInput): cfg is IEnrichConfig;
|
|
3
|
+
export declare function normalizeLegacyConfig(cfg: IEnrichConfig): INormalizedEnrichConfig;
|
|
4
|
+
export declare function validateEnterpriseConfig(cfg: IEnrichConfigEnterprise): string[];
|
|
5
|
+
export declare function normalizeEnterpriseConfig(cfg: IEnrichConfigEnterprise): INormalizedEnrichConfig;
|
|
6
|
+
export declare function normalizeEnrichConfig(cfg: EnrichConfigInput): INormalizedEnrichConfig;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EnrichConfigInput, IDegradedItem } from './enrichment.types';
|
|
2
|
+
import { RegistryService } from '../registry/registry.service';
|
|
3
|
+
export type { IEnrichConfig, IEnrichConfigEnterprise, EnrichConfigInput, IDegradedItem, } from './enrichment.types';
|
|
4
|
+
export declare class EnrichmentService {
|
|
5
|
+
private readonly registry;
|
|
6
|
+
constructor(registry: RegistryService);
|
|
7
|
+
private recordDegraded;
|
|
8
|
+
enrich(data: any[], configs: EnrichConfigInput[], concurrency?: number, correlationId?: string): Promise<{
|
|
9
|
+
result: any;
|
|
10
|
+
degraded: IDegradedItem[];
|
|
11
|
+
}>;
|
|
12
|
+
private getResponseItems;
|
|
13
|
+
private runScopedEnrichment;
|
|
14
|
+
private runGlobalEnrichment;
|
|
15
|
+
private filterValueToString;
|
|
16
|
+
private buildBody;
|
|
17
|
+
private buildQueryParams;
|
|
18
|
+
private normalizeResponse;
|
|
19
|
+
private callRemote;
|
|
20
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export interface IEnrichConfig {
|
|
2
|
+
key: string;
|
|
3
|
+
mapTo?: string;
|
|
4
|
+
project_id: string;
|
|
5
|
+
serviceName: string;
|
|
6
|
+
isRequired?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface IEnrichQueryFilter {
|
|
9
|
+
field: string;
|
|
10
|
+
operator: 'IN' | 'EQ';
|
|
11
|
+
valueFrom: string;
|
|
12
|
+
}
|
|
13
|
+
export interface IEnrichQuerySort {
|
|
14
|
+
field: string;
|
|
15
|
+
direction: 'ASC' | 'DESC';
|
|
16
|
+
}
|
|
17
|
+
export interface IEnrichQuery {
|
|
18
|
+
filters?: IEnrichQueryFilter[];
|
|
19
|
+
sort?: IEnrichQuerySort[];
|
|
20
|
+
}
|
|
21
|
+
export interface IEnrichPagination {
|
|
22
|
+
pagination: 'all' | 'no';
|
|
23
|
+
page: number;
|
|
24
|
+
limit: number;
|
|
25
|
+
}
|
|
26
|
+
export interface IEnrichMap {
|
|
27
|
+
localKey: string;
|
|
28
|
+
remoteKey?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface IEnrichMapNormalized extends IEnrichMap {
|
|
31
|
+
remoteKey: string;
|
|
32
|
+
}
|
|
33
|
+
export interface IEnrichScope {
|
|
34
|
+
type: 'array' | 'object' | 'root';
|
|
35
|
+
path?: string;
|
|
36
|
+
mode?: 'single' | 'batched';
|
|
37
|
+
batch_size?: number;
|
|
38
|
+
}
|
|
39
|
+
export interface IEnrichSelect {
|
|
40
|
+
include?: string[];
|
|
41
|
+
rename?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
export interface IEnrichSelectNormalized {
|
|
44
|
+
include: string[];
|
|
45
|
+
rename: Record<string, string>;
|
|
46
|
+
}
|
|
47
|
+
export interface IAttachAs {
|
|
48
|
+
field: string;
|
|
49
|
+
type: 'array' | 'object' | 'scalar';
|
|
50
|
+
}
|
|
51
|
+
export interface IEnrichFallback {
|
|
52
|
+
api_version?: string;
|
|
53
|
+
}
|
|
54
|
+
export interface IEnrichConfigEnterprise {
|
|
55
|
+
project_id: string;
|
|
56
|
+
service: string;
|
|
57
|
+
api_version?: string;
|
|
58
|
+
method?: 'GET' | 'POST';
|
|
59
|
+
filterMode?: 'scoped' | 'global';
|
|
60
|
+
pagination?: IEnrichPagination;
|
|
61
|
+
query?: IEnrichQuery;
|
|
62
|
+
map: IEnrichMap;
|
|
63
|
+
mapTo?: string;
|
|
64
|
+
scope?: IEnrichScope;
|
|
65
|
+
attach_as?: IAttachAs;
|
|
66
|
+
select?: IEnrichSelect;
|
|
67
|
+
remove_local_key?: boolean;
|
|
68
|
+
onFailure?: 'degrade' | 'fail' | 'fallback';
|
|
69
|
+
isRequired?: boolean;
|
|
70
|
+
onDuplicate?: 'error' | 'first' | 'last';
|
|
71
|
+
onEmpty?: 'skip' | 'call' | 'error';
|
|
72
|
+
fallback?: IEnrichFallback;
|
|
73
|
+
}
|
|
74
|
+
export type EnrichConfigInput = IEnrichConfig | IEnrichConfigEnterprise;
|
|
75
|
+
export interface INormalizedEnrichConfig {
|
|
76
|
+
field: string;
|
|
77
|
+
project_id: string;
|
|
78
|
+
service: string;
|
|
79
|
+
api_version: string;
|
|
80
|
+
method: 'GET' | 'POST';
|
|
81
|
+
filterMode: 'scoped' | 'global';
|
|
82
|
+
pagination: IEnrichPagination | null;
|
|
83
|
+
query: IEnrichQuery | null;
|
|
84
|
+
map: IEnrichMapNormalized;
|
|
85
|
+
mapTo: string;
|
|
86
|
+
scope: IEnrichScope;
|
|
87
|
+
attach_as: IAttachAs;
|
|
88
|
+
select: IEnrichSelectNormalized | null;
|
|
89
|
+
remove_local_key: boolean;
|
|
90
|
+
onFailure: 'degrade' | 'fail' | 'fallback';
|
|
91
|
+
isRequired: boolean;
|
|
92
|
+
onDuplicate: 'error' | 'first' | 'last';
|
|
93
|
+
onEmpty: 'skip' | 'call' | 'error';
|
|
94
|
+
fallback: IEnrichFallback | null;
|
|
95
|
+
}
|
|
96
|
+
export interface IEnrichmentSlot {
|
|
97
|
+
field: string;
|
|
98
|
+
mapTo: string;
|
|
99
|
+
map: IEnrichMapNormalized;
|
|
100
|
+
onDuplicate: 'error' | 'first' | 'last';
|
|
101
|
+
scope: IEnrichScope;
|
|
102
|
+
attach_as: IAttachAs;
|
|
103
|
+
remove_local_key: boolean;
|
|
104
|
+
data: Record<string, unknown> | unknown[];
|
|
105
|
+
remoteKeyForLookup?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface IDegradedItem {
|
|
108
|
+
project_id: string;
|
|
109
|
+
service: string;
|
|
110
|
+
error: string;
|
|
111
|
+
configField?: string;
|
|
112
|
+
type?: string;
|
|
113
|
+
statusCode?: number;
|
|
114
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IDegradedItem } from './enrichment.types';
|
|
2
|
+
export interface IErpError {
|
|
3
|
+
field: string;
|
|
4
|
+
service: string;
|
|
5
|
+
type: string;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
8
|
+
export interface IErpResponse<T = unknown> {
|
|
9
|
+
data: T;
|
|
10
|
+
errors: IErpError[];
|
|
11
|
+
degraded: string[];
|
|
12
|
+
meta: {
|
|
13
|
+
partial: boolean;
|
|
14
|
+
requestId?: string;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface IBuildErpResponseOptions {
|
|
19
|
+
requestId?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function buildErpResponse<T>(enrichResult: {
|
|
22
|
+
result: T;
|
|
23
|
+
degraded: IDegradedItem[];
|
|
24
|
+
}, options?: IBuildErpResponseOptions): IErpResponse<T>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IEnrichMapNormalized, IEnrichScope, IAttachAs } from './enrichment.types';
|
|
2
|
+
export declare function mergeWithMap(original: any[], map: IEnrichMapNormalized, mapTo: string, data: Record<string, any>, onDuplicate: 'error' | 'first' | 'last'): void;
|
|
3
|
+
export declare function mergeWithScopeAndAttach(original: any[], scope: IEnrichScope, attach_as: IAttachAs, map: IEnrichMapNormalized, data: Record<string, any>, onDuplicate: 'error' | 'first' | 'last', remove_local_key: boolean, remoteKeyForLookup?: string): void;
|
|
4
|
+
export declare function mergeResultsDynamic(original: any[], enrichments: {
|
|
5
|
+
key: string;
|
|
6
|
+
mapTo?: string;
|
|
7
|
+
data: Record<string, any>;
|
|
8
|
+
}[]): any[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface IServiceSLA {
|
|
2
|
+
timeout: number;
|
|
3
|
+
retries: number;
|
|
4
|
+
errorThreshold?: number;
|
|
5
|
+
resetTimeout?: number;
|
|
6
|
+
isCritical?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const SERVICE_SLA: Record<string, IServiceSLA>;
|
|
9
|
+
export declare function getServiceSLA(serviceName: string): IServiceSLA;
|
|
10
|
+
export declare function getTimeout(serviceName: string, _operation?: string): number;
|
|
11
|
+
export declare function getRetries(serviceName: string, _operation?: string): number;
|
|
12
|
+
export declare function isCritical(serviceName: string): boolean;
|
|
13
|
+
export declare function getErrorThreshold(serviceName: string): number;
|
|
14
|
+
export declare function getResetTimeout(serviceName: string): number;
|
|
15
|
+
export declare const OPERATION_SLA: Record<string, IServiceSLA>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { IEnrichSelectNormalized } from './enrichment.types';
|
|
2
|
+
export declare function applyProjection(items: any[], select: IEnrichSelectNormalized | null): any[];
|
|
3
|
+
export declare function getRemoteKeyForLookup(remoteKey: string, select: IEnrichSelectNormalized | null): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const HTTP_CONFIG: {
|
|
2
|
+
TIMEOUT_MS: number;
|
|
3
|
+
RETRIES: number;
|
|
4
|
+
BULKHEAD_CONCURRENCY: number;
|
|
5
|
+
BREAKER_THRESHOLD: number;
|
|
6
|
+
BREAKER_RESET_MS: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const SERVICE_SLA: {
|
|
9
|
+
user: {
|
|
10
|
+
timeout: number;
|
|
11
|
+
retries: number;
|
|
12
|
+
};
|
|
13
|
+
orders: {
|
|
14
|
+
timeout: number;
|
|
15
|
+
retries: number;
|
|
16
|
+
};
|
|
17
|
+
loyalty: {
|
|
18
|
+
timeout: number;
|
|
19
|
+
retries: number;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { QueueAddOptions } from 'p-queue';
|
|
2
|
+
import PriorityQueue from 'p-queue/dist/priority-queue';
|
|
3
|
+
import { Dispatcher } from 'undici';
|
|
4
|
+
import { IHttpRequestOptions } from './types';
|
|
5
|
+
import type PQueue from 'p-queue';
|
|
6
|
+
export declare function createBulkhead(concurrency?: number): PQueue<PriorityQueue, QueueAddOptions>;
|
|
7
|
+
export declare function httpRequest<T>(options: IHttpRequestOptions, dispatcher?: Dispatcher): Promise<T>;
|
|
8
|
+
export declare function withRetry<T>(fn: () => Promise<T>, retries?: number): Promise<T>;
|
|
9
|
+
export interface ICallServiceOptions {
|
|
10
|
+
method: 'GET' | 'POST';
|
|
11
|
+
body?: any;
|
|
12
|
+
queryParams?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
export declare function callService<T>(url: string, options: ICallServiceOptions, project_id: string, serviceName: string, bulkhead: PQueue): Promise<T>;
|
|
15
|
+
export declare function callServicePost<T>(url: string, body: any, project_id: string, serviceName: string, bulkhead: PQueue): Promise<T>;
|
|
16
|
+
export type { ServiceCallResult } from './error.types';
|
|
17
|
+
export declare function callServiceWithResult<T>(url: string, options: ICallServiceOptions, project_id: string, serviceName: string, bulkhead: PQueue): Promise<import('./error.types').ServiceCallResult<T>>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ErrorCategory = 'client' | 'business' | 'infrastructure' | 'systemic';
|
|
2
|
+
export interface INormalizedError {
|
|
3
|
+
type: ErrorCategory;
|
|
4
|
+
message: string;
|
|
5
|
+
project_id: string;
|
|
6
|
+
service: string;
|
|
7
|
+
statusCode?: number;
|
|
8
|
+
code?: string;
|
|
9
|
+
}
|
|
10
|
+
export type ServiceCallResult<T> = {
|
|
11
|
+
ok: true;
|
|
12
|
+
data: T;
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: INormalizedError;
|
|
16
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Counter, Gauge, Histogram } from 'prom-client';
|
|
2
|
+
export declare const breakerState: Gauge<"service" | "project_id">;
|
|
3
|
+
export declare const enrichmentDegradedTotal: Counter<"type" | "service" | "project_id">;
|
|
4
|
+
export declare const enrichmentCallDurationSeconds: Histogram<"service">;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function trace<T>(span: string, fn: () => Promise<T>, correlationId?: string): Promise<T>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LoggerService } from '@infineit/winston-logger';
|
|
2
|
+
import { RedisService } from '../../redis.service';
|
|
3
|
+
import type { IRegistryResolution } from './registry.types';
|
|
4
|
+
export declare class RegistryService {
|
|
5
|
+
private readonly redisService;
|
|
6
|
+
private readonly logger;
|
|
7
|
+
private readonly l1;
|
|
8
|
+
constructor(redisService: RedisService, logger: LoggerService);
|
|
9
|
+
resolve(projectId: string, serviceName: string, apiVersion?: string): Promise<string>;
|
|
10
|
+
resolveFull(projectId: string, serviceName: string, apiVersion?: string): Promise<IRegistryResolution>;
|
|
11
|
+
private resolveInternal;
|
|
12
|
+
private setL1;
|
|
13
|
+
private fetchFromRegistry;
|
|
14
|
+
private log;
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface IRegistryResolution {
|
|
2
|
+
base_url: string;
|
|
3
|
+
version: string;
|
|
4
|
+
timeout: number;
|
|
5
|
+
retry_policy: number;
|
|
6
|
+
}
|
|
7
|
+
export interface IRegistryApiInstance {
|
|
8
|
+
base_url: string;
|
|
9
|
+
version: string;
|
|
10
|
+
timeout: number;
|
|
11
|
+
retry_policy: number;
|
|
12
|
+
healthy?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export type IRegistryApiResponse = IRegistryApiInstance | IRegistryApiInstance[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infineit-nestjs/services",
|
|
3
|
-
"version": "1.1.0-cursor-ai.
|
|
3
|
+
"version": "1.1.0-cursor-ai.22",
|
|
4
4
|
"main": "./dist/cjs/index.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@elastic/elasticsearch": "^9.3.2",
|
|
53
|
-
"@infineit-nestjs/types": "1.1.0-cursor-ai.
|
|
54
|
-
"@infineit-nestjs/utils": "1.1.0-cursor-ai.
|
|
53
|
+
"@infineit-nestjs/types": "1.1.0-cursor-ai.4",
|
|
54
|
+
"@infineit-nestjs/utils": "1.1.0-cursor-ai.5",
|
|
55
55
|
"@infineit/winston-logger": "^1.0.40",
|
|
56
56
|
"@nestjs/axios": "^4.0.0",
|
|
57
57
|
"@nestjs/microservices": "^11.1.2",
|
|
@@ -126,5 +126,5 @@
|
|
|
126
126
|
"node": ">=18.0.0",
|
|
127
127
|
"npm": ">=9.0.0"
|
|
128
128
|
},
|
|
129
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "5009a5ee9b6203861f2d65bdee760e44d94793e1"
|
|
130
130
|
}
|