@rainbow-o23/n1 1.0.58-alpha.3 → 1.0.59
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/index.cjs +123 -8
- package/index.js +122 -9
- package/lib/pipeline/index.d.ts +1 -0
- package/lib/pipeline/pipeline-execution-context.d.ts +42 -0
- package/lib/pipeline/pipeline-step.d.ts +3 -7
- package/lib/pipeline/pipeline.d.ts +3 -12
- package/package.json +1 -1
- package/src/lib/pipeline/index.ts +1 -0
- package/src/lib/pipeline/pipeline-execution-context.ts +166 -0
- package/src/lib/pipeline/pipeline-step.ts +3 -8
- package/src/lib/pipeline/pipeline.ts +15 -27
package/index.cjs
CHANGED
|
@@ -604,6 +604,115 @@ class AbstractPipelineExecution {
|
|
|
604
604
|
}
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
+
class PipelineExecutionContext {
|
|
608
|
+
_authorization;
|
|
609
|
+
_traceId;
|
|
610
|
+
_scopedTraceIds;
|
|
611
|
+
_others = {};
|
|
612
|
+
constructor(authorization, traceId, scopedTraceIds) {
|
|
613
|
+
this._authorization = authorization;
|
|
614
|
+
this._traceId = traceId || nanoid.nanoid(16);
|
|
615
|
+
this._scopedTraceIds = scopedTraceIds || {};
|
|
616
|
+
}
|
|
617
|
+
get authorization() {
|
|
618
|
+
return this._authorization;
|
|
619
|
+
}
|
|
620
|
+
get traceId() {
|
|
621
|
+
return this._traceId;
|
|
622
|
+
}
|
|
623
|
+
get scopedTraceIds() {
|
|
624
|
+
return Object.values(this._scopedTraceIds).reduce((acc, [name, value]) => {
|
|
625
|
+
if (value != null && value.trim().length !== 0) {
|
|
626
|
+
acc[name] = value;
|
|
627
|
+
}
|
|
628
|
+
return acc;
|
|
629
|
+
}, {});
|
|
630
|
+
}
|
|
631
|
+
findScopedTraceId(scopeKey) {
|
|
632
|
+
return this._scopedTraceIds[scopeKey];
|
|
633
|
+
}
|
|
634
|
+
setScopedTraceId(scopeKey, name, value) {
|
|
635
|
+
this._scopedTraceIds[scopeKey] = [name, value];
|
|
636
|
+
}
|
|
637
|
+
findOther(key) {
|
|
638
|
+
return this._others[key];
|
|
639
|
+
}
|
|
640
|
+
setOther(key, value) {
|
|
641
|
+
this._others[key] = value;
|
|
642
|
+
}
|
|
643
|
+
shallowClone(...omittedKeys) {
|
|
644
|
+
const cloned = new PipelineExecutionContext(this.authorization, this.traceId, this._scopedTraceIds);
|
|
645
|
+
Object.keys(this._others).forEach(key => {
|
|
646
|
+
if (omittedKeys.includes(key)) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
cloned.setOther(key, this.findOther(key));
|
|
650
|
+
});
|
|
651
|
+
return cloned;
|
|
652
|
+
}
|
|
653
|
+
clone(...omittedKeys) {
|
|
654
|
+
const cloned = new PipelineExecutionContext(this.authorization, this.traceId);
|
|
655
|
+
Object.keys(this._others).forEach(key => {
|
|
656
|
+
if (omittedKeys.includes(key)) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
cloned.setOther(key, this.findOther(key));
|
|
660
|
+
});
|
|
661
|
+
return cloned;
|
|
662
|
+
}
|
|
663
|
+
temporaryWith(temporaryContext) {
|
|
664
|
+
return new TemporaryExecutionContext(this, temporaryContext);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
class TemporaryExecutionContext extends PipelineExecutionContext {
|
|
668
|
+
_parent;
|
|
669
|
+
_temporaryContext;
|
|
670
|
+
_temporaryKeys;
|
|
671
|
+
constructor(parent, temporaryContext) {
|
|
672
|
+
super();
|
|
673
|
+
this._parent = parent;
|
|
674
|
+
this._temporaryContext = temporaryContext ?? {};
|
|
675
|
+
this._temporaryKeys = Object.keys(this._temporaryContext);
|
|
676
|
+
}
|
|
677
|
+
get parent() {
|
|
678
|
+
return this._parent;
|
|
679
|
+
}
|
|
680
|
+
get authorization() {
|
|
681
|
+
return this.parent.authorization;
|
|
682
|
+
}
|
|
683
|
+
get traceId() {
|
|
684
|
+
return this.parent.traceId;
|
|
685
|
+
}
|
|
686
|
+
get scopedTraceIds() {
|
|
687
|
+
return this.parent.scopedTraceIds;
|
|
688
|
+
}
|
|
689
|
+
findScopedTraceId(scopeKey) {
|
|
690
|
+
return this.parent.findScopedTraceId(scopeKey);
|
|
691
|
+
}
|
|
692
|
+
setScopedTraceId(scopeKey, name, value) {
|
|
693
|
+
this.parent.setScopedTraceId(scopeKey, name, value);
|
|
694
|
+
}
|
|
695
|
+
get temporaryContext() {
|
|
696
|
+
return this._temporaryContext;
|
|
697
|
+
}
|
|
698
|
+
findOther(key) {
|
|
699
|
+
if (this._temporaryKeys.includes(key)) {
|
|
700
|
+
return this.temporaryContext[key];
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
return super.findOther(key);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
setOther(key, value) {
|
|
707
|
+
if (this._temporaryKeys.includes(key)) {
|
|
708
|
+
this.temporaryContext[key] = value;
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
super.setOther(key, value);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
607
716
|
class PipelineStepDateHelper {
|
|
608
717
|
_dateTimeFormat;
|
|
609
718
|
constructor(config) {
|
|
@@ -705,13 +814,19 @@ class AbstractPipeline extends AbstractPipelineExecution {
|
|
|
705
814
|
return await Promise.all(this.getStepBuilders().map(async (builder) => await builder.create(options)));
|
|
706
815
|
}
|
|
707
816
|
convertRequestToPipelineData(request) {
|
|
708
|
-
return {
|
|
817
|
+
return {
|
|
818
|
+
content: request.payload,
|
|
819
|
+
$context: request.$context
|
|
820
|
+
};
|
|
709
821
|
}
|
|
710
822
|
convertPipelineDataToResponse(result) {
|
|
711
|
-
return {
|
|
823
|
+
return {
|
|
824
|
+
payload: result.content,
|
|
825
|
+
$context: result.$context
|
|
826
|
+
};
|
|
712
827
|
}
|
|
713
828
|
createTraceId(request) {
|
|
714
|
-
const { traceId } = request;
|
|
829
|
+
const { traceId } = request.$context ?? {};
|
|
715
830
|
if (traceId == null || traceId.trim().length === 0) {
|
|
716
831
|
return nanoid.nanoid(16);
|
|
717
832
|
}
|
|
@@ -720,8 +835,8 @@ class AbstractPipeline extends AbstractPipelineExecution {
|
|
|
720
835
|
}
|
|
721
836
|
}
|
|
722
837
|
async perform(request) {
|
|
723
|
-
const
|
|
724
|
-
const
|
|
838
|
+
const $context = request.$context;
|
|
839
|
+
const traceId = $context.traceId;
|
|
725
840
|
const response = await this.measurePerformance(traceId, 'PIPELINE')
|
|
726
841
|
.execute(async () => {
|
|
727
842
|
this.traceRequest(traceId, request);
|
|
@@ -731,9 +846,7 @@ class AbstractPipeline extends AbstractPipelineExecution {
|
|
|
731
846
|
return await this.measurePerformance(traceId, 'STEP', step.constructor.name)
|
|
732
847
|
.execute(async () => {
|
|
733
848
|
this.traceStepIn(traceId, step, request);
|
|
734
|
-
const response = await step.perform({
|
|
735
|
-
...request, $context: { ...request.$context, authorization, traceId }
|
|
736
|
-
});
|
|
849
|
+
const response = await step.perform({ ...request, $context });
|
|
737
850
|
this.traceStepOut(traceId, step, response);
|
|
738
851
|
return this.returnOrContinueOrClear(request, response);
|
|
739
852
|
});
|
|
@@ -818,8 +931,10 @@ exports.LoggerUtils = LoggerUtils;
|
|
|
818
931
|
exports.PIPELINE_STEP_FILE_SYMBOL = PIPELINE_STEP_FILE_SYMBOL;
|
|
819
932
|
exports.PIPELINE_STEP_RETURN_NULL = PIPELINE_STEP_RETURN_NULL;
|
|
820
933
|
exports.PerformanceExecution = PerformanceExecution;
|
|
934
|
+
exports.PipelineExecutionContext = PipelineExecutionContext;
|
|
821
935
|
exports.PipelineRepository = PipelineRepository;
|
|
822
936
|
exports.PipelineStepDateHelper = PipelineStepDateHelper;
|
|
937
|
+
exports.TemporaryExecutionContext = TemporaryExecutionContext;
|
|
823
938
|
exports.UncatchableError = UncatchableError;
|
|
824
939
|
exports.createConfig = createConfig;
|
|
825
940
|
exports.createLogger = createLogger;
|
package/index.js
CHANGED
|
@@ -602,6 +602,115 @@ class AbstractPipelineExecution {
|
|
|
602
602
|
}
|
|
603
603
|
}
|
|
604
604
|
|
|
605
|
+
class PipelineExecutionContext {
|
|
606
|
+
_authorization;
|
|
607
|
+
_traceId;
|
|
608
|
+
_scopedTraceIds;
|
|
609
|
+
_others = {};
|
|
610
|
+
constructor(authorization, traceId, scopedTraceIds) {
|
|
611
|
+
this._authorization = authorization;
|
|
612
|
+
this._traceId = traceId || nanoid(16);
|
|
613
|
+
this._scopedTraceIds = scopedTraceIds || {};
|
|
614
|
+
}
|
|
615
|
+
get authorization() {
|
|
616
|
+
return this._authorization;
|
|
617
|
+
}
|
|
618
|
+
get traceId() {
|
|
619
|
+
return this._traceId;
|
|
620
|
+
}
|
|
621
|
+
get scopedTraceIds() {
|
|
622
|
+
return Object.values(this._scopedTraceIds).reduce((acc, [name, value]) => {
|
|
623
|
+
if (value != null && value.trim().length !== 0) {
|
|
624
|
+
acc[name] = value;
|
|
625
|
+
}
|
|
626
|
+
return acc;
|
|
627
|
+
}, {});
|
|
628
|
+
}
|
|
629
|
+
findScopedTraceId(scopeKey) {
|
|
630
|
+
return this._scopedTraceIds[scopeKey];
|
|
631
|
+
}
|
|
632
|
+
setScopedTraceId(scopeKey, name, value) {
|
|
633
|
+
this._scopedTraceIds[scopeKey] = [name, value];
|
|
634
|
+
}
|
|
635
|
+
findOther(key) {
|
|
636
|
+
return this._others[key];
|
|
637
|
+
}
|
|
638
|
+
setOther(key, value) {
|
|
639
|
+
this._others[key] = value;
|
|
640
|
+
}
|
|
641
|
+
shallowClone(...omittedKeys) {
|
|
642
|
+
const cloned = new PipelineExecutionContext(this.authorization, this.traceId, this._scopedTraceIds);
|
|
643
|
+
Object.keys(this._others).forEach(key => {
|
|
644
|
+
if (omittedKeys.includes(key)) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
cloned.setOther(key, this.findOther(key));
|
|
648
|
+
});
|
|
649
|
+
return cloned;
|
|
650
|
+
}
|
|
651
|
+
clone(...omittedKeys) {
|
|
652
|
+
const cloned = new PipelineExecutionContext(this.authorization, this.traceId);
|
|
653
|
+
Object.keys(this._others).forEach(key => {
|
|
654
|
+
if (omittedKeys.includes(key)) {
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
cloned.setOther(key, this.findOther(key));
|
|
658
|
+
});
|
|
659
|
+
return cloned;
|
|
660
|
+
}
|
|
661
|
+
temporaryWith(temporaryContext) {
|
|
662
|
+
return new TemporaryExecutionContext(this, temporaryContext);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
class TemporaryExecutionContext extends PipelineExecutionContext {
|
|
666
|
+
_parent;
|
|
667
|
+
_temporaryContext;
|
|
668
|
+
_temporaryKeys;
|
|
669
|
+
constructor(parent, temporaryContext) {
|
|
670
|
+
super();
|
|
671
|
+
this._parent = parent;
|
|
672
|
+
this._temporaryContext = temporaryContext ?? {};
|
|
673
|
+
this._temporaryKeys = Object.keys(this._temporaryContext);
|
|
674
|
+
}
|
|
675
|
+
get parent() {
|
|
676
|
+
return this._parent;
|
|
677
|
+
}
|
|
678
|
+
get authorization() {
|
|
679
|
+
return this.parent.authorization;
|
|
680
|
+
}
|
|
681
|
+
get traceId() {
|
|
682
|
+
return this.parent.traceId;
|
|
683
|
+
}
|
|
684
|
+
get scopedTraceIds() {
|
|
685
|
+
return this.parent.scopedTraceIds;
|
|
686
|
+
}
|
|
687
|
+
findScopedTraceId(scopeKey) {
|
|
688
|
+
return this.parent.findScopedTraceId(scopeKey);
|
|
689
|
+
}
|
|
690
|
+
setScopedTraceId(scopeKey, name, value) {
|
|
691
|
+
this.parent.setScopedTraceId(scopeKey, name, value);
|
|
692
|
+
}
|
|
693
|
+
get temporaryContext() {
|
|
694
|
+
return this._temporaryContext;
|
|
695
|
+
}
|
|
696
|
+
findOther(key) {
|
|
697
|
+
if (this._temporaryKeys.includes(key)) {
|
|
698
|
+
return this.temporaryContext[key];
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
return super.findOther(key);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
setOther(key, value) {
|
|
705
|
+
if (this._temporaryKeys.includes(key)) {
|
|
706
|
+
this.temporaryContext[key] = value;
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
super.setOther(key, value);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
605
714
|
class PipelineStepDateHelper {
|
|
606
715
|
_dateTimeFormat;
|
|
607
716
|
constructor(config) {
|
|
@@ -703,13 +812,19 @@ class AbstractPipeline extends AbstractPipelineExecution {
|
|
|
703
812
|
return await Promise.all(this.getStepBuilders().map(async (builder) => await builder.create(options)));
|
|
704
813
|
}
|
|
705
814
|
convertRequestToPipelineData(request) {
|
|
706
|
-
return {
|
|
815
|
+
return {
|
|
816
|
+
content: request.payload,
|
|
817
|
+
$context: request.$context
|
|
818
|
+
};
|
|
707
819
|
}
|
|
708
820
|
convertPipelineDataToResponse(result) {
|
|
709
|
-
return {
|
|
821
|
+
return {
|
|
822
|
+
payload: result.content,
|
|
823
|
+
$context: result.$context
|
|
824
|
+
};
|
|
710
825
|
}
|
|
711
826
|
createTraceId(request) {
|
|
712
|
-
const { traceId } = request;
|
|
827
|
+
const { traceId } = request.$context ?? {};
|
|
713
828
|
if (traceId == null || traceId.trim().length === 0) {
|
|
714
829
|
return nanoid(16);
|
|
715
830
|
}
|
|
@@ -718,8 +833,8 @@ class AbstractPipeline extends AbstractPipelineExecution {
|
|
|
718
833
|
}
|
|
719
834
|
}
|
|
720
835
|
async perform(request) {
|
|
721
|
-
const
|
|
722
|
-
const
|
|
836
|
+
const $context = request.$context;
|
|
837
|
+
const traceId = $context.traceId;
|
|
723
838
|
const response = await this.measurePerformance(traceId, 'PIPELINE')
|
|
724
839
|
.execute(async () => {
|
|
725
840
|
this.traceRequest(traceId, request);
|
|
@@ -729,9 +844,7 @@ class AbstractPipeline extends AbstractPipelineExecution {
|
|
|
729
844
|
return await this.measurePerformance(traceId, 'STEP', step.constructor.name)
|
|
730
845
|
.execute(async () => {
|
|
731
846
|
this.traceStepIn(traceId, step, request);
|
|
732
|
-
const response = await step.perform({
|
|
733
|
-
...request, $context: { ...request.$context, authorization, traceId }
|
|
734
|
-
});
|
|
847
|
+
const response = await step.perform({ ...request, $context });
|
|
735
848
|
this.traceStepOut(traceId, step, response);
|
|
736
849
|
return this.returnOrContinueOrClear(request, response);
|
|
737
850
|
});
|
|
@@ -795,4 +908,4 @@ class PipelineRepository {
|
|
|
795
908
|
}
|
|
796
909
|
}
|
|
797
910
|
|
|
798
|
-
export { AbstractPipeline, AbstractPipelineExecution, AbstractPipelineStep, AbstractStaticPipeline, CatchableError, Config, ConsoleLogger, DefaultPipelineBuilder, DefaultPipelineStepBuilder, ERR_DUPLICATED_ERROR_CODE, ERR_PIPELINE_NOT_FOUND, ERR_TRIM_NON_STRING, ERR_UNKNOWN, EnhancedLogger, ErrorCodes, ExposedUncatchableError, LoggerPerformanceSaver, LoggerUtils, PIPELINE_STEP_FILE_SYMBOL, PIPELINE_STEP_RETURN_NULL, PerformanceExecution, PipelineRepository, PipelineStepDateHelper, StepHelpersUtils, UncatchableError, createConfig, createLogger, createStepHelpers, registerToStepHelpers, saveLoggerPerformance };
|
|
911
|
+
export { AbstractPipeline, AbstractPipelineExecution, AbstractPipelineStep, AbstractStaticPipeline, CatchableError, Config, ConsoleLogger, DefaultPipelineBuilder, DefaultPipelineStepBuilder, ERR_DUPLICATED_ERROR_CODE, ERR_PIPELINE_NOT_FOUND, ERR_TRIM_NON_STRING, ERR_UNKNOWN, EnhancedLogger, ErrorCodes, ExposedUncatchableError, LoggerPerformanceSaver, LoggerUtils, PIPELINE_STEP_FILE_SYMBOL, PIPELINE_STEP_RETURN_NULL, PerformanceExecution, PipelineExecutionContext, PipelineRepository, PipelineStepDateHelper, StepHelpersUtils, TemporaryExecutionContext, UncatchableError, createConfig, createLogger, createStepHelpers, registerToStepHelpers, saveLoggerPerformance };
|
package/lib/pipeline/index.d.ts
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface PipelineRequestAuthorizationRole {
|
|
2
|
+
code?: string;
|
|
3
|
+
[key: string]: any | undefined;
|
|
4
|
+
}
|
|
5
|
+
export interface PipelineRequestAuthorization<A = any> {
|
|
6
|
+
readonly authorized: boolean;
|
|
7
|
+
readonly authentication?: A;
|
|
8
|
+
readonly roles: Array<PipelineRequestAuthorizationRole>;
|
|
9
|
+
readonly headers?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export declare class PipelineExecutionContext {
|
|
12
|
+
private readonly _authorization?;
|
|
13
|
+
private readonly _traceId;
|
|
14
|
+
private readonly _scopedTraceIds;
|
|
15
|
+
private readonly _others;
|
|
16
|
+
constructor(authorization?: PipelineRequestAuthorization, traceId?: string, scopedTraceIds?: Record<string, [string, string]>);
|
|
17
|
+
get authorization(): PipelineRequestAuthorization;
|
|
18
|
+
get traceId(): string;
|
|
19
|
+
get scopedTraceIds(): Record<string, string>;
|
|
20
|
+
findScopedTraceId(scopeKey: string): [string, string] | undefined;
|
|
21
|
+
setScopedTraceId(scopeKey: string, name: string, value: string): void;
|
|
22
|
+
findOther(key: string): any | undefined;
|
|
23
|
+
setOther(key: string, value: any): void;
|
|
24
|
+
shallowClone(...omittedKeys: Array<string>): PipelineExecutionContext;
|
|
25
|
+
clone(...omittedKeys: Array<string>): PipelineExecutionContext;
|
|
26
|
+
temporaryWith(temporaryContext: Record<string, any>): PipelineExecutionContext;
|
|
27
|
+
}
|
|
28
|
+
export declare class TemporaryExecutionContext extends PipelineExecutionContext {
|
|
29
|
+
private readonly _parent;
|
|
30
|
+
private readonly _temporaryContext;
|
|
31
|
+
private readonly _temporaryKeys;
|
|
32
|
+
constructor(parent: PipelineExecutionContext, temporaryContext: Record<string, any>);
|
|
33
|
+
protected get parent(): PipelineExecutionContext;
|
|
34
|
+
get authorization(): PipelineRequestAuthorization;
|
|
35
|
+
get traceId(): string;
|
|
36
|
+
get scopedTraceIds(): Record<string, string>;
|
|
37
|
+
findScopedTraceId(scopeKey: string): [string, string] | undefined;
|
|
38
|
+
setScopedTraceId(scopeKey: string, name: string, value: string): void;
|
|
39
|
+
get temporaryContext(): Record<string, any>;
|
|
40
|
+
findOther(key: string): any;
|
|
41
|
+
setOther(key: string, value: any): void;
|
|
42
|
+
}
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { Config, Logger } from '../utils';
|
|
2
|
-
import { PipelineRequestAuthorization } from './pipeline';
|
|
3
2
|
import { AbstractPipelineExecution, PipelineExecutionOptions } from './pipeline-execution';
|
|
3
|
+
import { PipelineExecutionContext } from './pipeline-execution-context';
|
|
4
4
|
import { PipelineStepHelpers } from './step-helpers';
|
|
5
5
|
export type PipelineStepCode = string;
|
|
6
6
|
export type PipelineStepPayload = any;
|
|
7
|
-
export interface
|
|
8
|
-
|
|
9
|
-
traceId?: string;
|
|
10
|
-
}
|
|
11
|
-
export interface PipelineStepData<C = PipelineStepPayload, CTX = PipelineStepContext> {
|
|
12
|
-
$context?: CTX;
|
|
7
|
+
export interface PipelineStepData<C = PipelineStepPayload, CTX = PipelineExecutionContext> {
|
|
8
|
+
$context: CTX;
|
|
13
9
|
content: C;
|
|
14
10
|
}
|
|
15
11
|
export interface PipelineStep<In = any, Out = any> {
|
|
@@ -1,25 +1,16 @@
|
|
|
1
1
|
import { Config, Logger } from '../utils';
|
|
2
2
|
import { AbstractPipelineExecution, PipelineExecutionOptions } from './pipeline-execution';
|
|
3
|
+
import { PipelineExecutionContext } from './pipeline-execution-context';
|
|
3
4
|
import { PipelineStep, PipelineStepBuilder, PipelineStepData, PipelineStepOptions, PipelineStepType } from './pipeline-step';
|
|
4
5
|
export type PipelineRequestPayload = any;
|
|
5
|
-
export interface PipelineRequestAuthorizationRole {
|
|
6
|
-
code?: string;
|
|
7
|
-
[key: string]: any | undefined;
|
|
8
|
-
}
|
|
9
|
-
export interface PipelineRequestAuthorization<A = any> {
|
|
10
|
-
readonly authorized: boolean;
|
|
11
|
-
readonly authentication?: A;
|
|
12
|
-
readonly roles: Array<PipelineRequestAuthorizationRole>;
|
|
13
|
-
readonly headers?: Record<string, string>;
|
|
14
|
-
}
|
|
15
6
|
export interface PipelineRequest<C = PipelineRequestPayload> {
|
|
16
7
|
payload: C;
|
|
17
|
-
|
|
18
|
-
traceId?: string;
|
|
8
|
+
$context: PipelineExecutionContext;
|
|
19
9
|
}
|
|
20
10
|
export type PipelineResponsePayload = any;
|
|
21
11
|
export interface PipelineResponse<C = PipelineResponsePayload> {
|
|
22
12
|
payload: C;
|
|
13
|
+
$context: PipelineExecutionContext;
|
|
23
14
|
}
|
|
24
15
|
export type PipelineCode = string;
|
|
25
16
|
export interface Pipeline<In = any, Out = any> {
|
package/package.json
CHANGED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import {nanoid} from 'nanoid';
|
|
2
|
+
|
|
3
|
+
export interface PipelineRequestAuthorizationRole {
|
|
4
|
+
code?: string;
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
+
[key: string]: any | undefined;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
export interface PipelineRequestAuthorization<A = any> {
|
|
11
|
+
readonly authorized: boolean;
|
|
12
|
+
/** undefined when authorized is false */
|
|
13
|
+
readonly authentication?: A;
|
|
14
|
+
/** empty array when authorized is false */
|
|
15
|
+
readonly roles: Array<PipelineRequestAuthorizationRole>;
|
|
16
|
+
/** headers should be added to response */
|
|
17
|
+
readonly headers?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class PipelineExecutionContext {
|
|
21
|
+
private readonly _authorization?: PipelineRequestAuthorization;
|
|
22
|
+
private readonly _traceId: string;
|
|
23
|
+
/*
|
|
24
|
+
* typically, when calling a remote service, and which is from some microservices group,
|
|
25
|
+
* there might be some trace ids brought in.
|
|
26
|
+
* therefore, these trace ids should be collected and put into pipeline context.
|
|
27
|
+
* the key is tracing group, and value is trace id of this tracing group.
|
|
28
|
+
* Record<scope key, [name, value]>
|
|
29
|
+
*/
|
|
30
|
+
private readonly _scopedTraceIds: Record<string, [string, string]>;
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
+
private readonly _others: Record<string, any> = {};
|
|
33
|
+
|
|
34
|
+
constructor(authorization?: PipelineRequestAuthorization, traceId?: string, scopedTraceIds?: Record<string, [string, string]>) {
|
|
35
|
+
this._authorization = authorization;
|
|
36
|
+
this._traceId = traceId || nanoid(16);
|
|
37
|
+
this._scopedTraceIds = scopedTraceIds || {};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get authorization(): PipelineRequestAuthorization {
|
|
41
|
+
return this._authorization;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get traceId(): string {
|
|
45
|
+
return this._traceId;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get scopedTraceIds(): Record<string, string> {
|
|
49
|
+
return Object.values(this._scopedTraceIds).reduce((acc, [name, value]) => {
|
|
50
|
+
if (value != null && value.trim().length !== 0) {
|
|
51
|
+
acc[name] = value;
|
|
52
|
+
}
|
|
53
|
+
return acc;
|
|
54
|
+
}, {});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
findScopedTraceId(scopeKey: string): [string, string] | undefined {
|
|
58
|
+
return this._scopedTraceIds[scopeKey];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
setScopedTraceId(scopeKey: string, name: string, value: string): void {
|
|
62
|
+
this._scopedTraceIds[scopeKey] = [name, value];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
findOther(key: string): any | undefined {
|
|
67
|
+
return this._others[key];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
71
|
+
setOther(key: string, value: any): void {
|
|
72
|
+
this._others[key] = value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
shallowClone(...omittedKeys: Array<string>): PipelineExecutionContext {
|
|
76
|
+
const cloned = new PipelineExecutionContext(this.authorization, this.traceId, this._scopedTraceIds);
|
|
77
|
+
Object.keys(this._others).forEach(key => {
|
|
78
|
+
if (omittedKeys.includes(key)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
cloned.setOther(key, this.findOther(key));
|
|
82
|
+
});
|
|
83
|
+
return cloned;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
clone(...omittedKeys: Array<string>): PipelineExecutionContext {
|
|
87
|
+
const cloned = new PipelineExecutionContext(this.authorization, this.traceId);
|
|
88
|
+
Object.keys(this._others).forEach(key => {
|
|
89
|
+
if (omittedKeys.includes(key)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
cloned.setOther(key, this.findOther(key));
|
|
93
|
+
});
|
|
94
|
+
return cloned;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
98
|
+
temporaryWith(temporaryContext: Record<string, any>): PipelineExecutionContext {
|
|
99
|
+
return new TemporaryExecutionContext(this, temporaryContext);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* everything same as parent context, except things in given temporary context
|
|
105
|
+
*/
|
|
106
|
+
export class TemporaryExecutionContext extends PipelineExecutionContext {
|
|
107
|
+
private readonly _parent: PipelineExecutionContext;
|
|
108
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
|
+
private readonly _temporaryContext: Record<string, any>;
|
|
110
|
+
private readonly _temporaryKeys: Array<string>;
|
|
111
|
+
|
|
112
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
|
+
constructor(parent: PipelineExecutionContext, temporaryContext: Record<string, any>) {
|
|
114
|
+
super();
|
|
115
|
+
this._parent = parent;
|
|
116
|
+
this._temporaryContext = temporaryContext ?? {};
|
|
117
|
+
this._temporaryKeys = Object.keys(this._temporaryContext);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
protected get parent(): PipelineExecutionContext {
|
|
121
|
+
return this._parent;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get authorization(): PipelineRequestAuthorization {
|
|
125
|
+
return this.parent.authorization;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get traceId(): string {
|
|
129
|
+
return this.parent.traceId;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get scopedTraceIds(): Record<string, string> {
|
|
133
|
+
return this.parent.scopedTraceIds;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
findScopedTraceId(scopeKey: string): [string, string] | undefined {
|
|
137
|
+
return this.parent.findScopedTraceId(scopeKey);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
setScopedTraceId(scopeKey: string, name: string, value: string) {
|
|
141
|
+
this.parent.setScopedTraceId(scopeKey, name, value);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
145
|
+
get temporaryContext(): Record<string, any> {
|
|
146
|
+
return this._temporaryContext;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
|
+
findOther(key: string): any {
|
|
151
|
+
if (this._temporaryKeys.includes(key)) {
|
|
152
|
+
return this.temporaryContext[key];
|
|
153
|
+
} else {
|
|
154
|
+
return super.findOther(key);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
159
|
+
setOther(key: string, value: any) {
|
|
160
|
+
if (this._temporaryKeys.includes(key)) {
|
|
161
|
+
this.temporaryContext[key] = value;
|
|
162
|
+
} else {
|
|
163
|
+
super.setOther(key, value);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Config, Logger} from '../utils';
|
|
2
|
-
import {PipelineRequestAuthorization} from './pipeline';
|
|
3
2
|
import {AbstractPipelineExecution, PipelineExecutionOptions} from './pipeline-execution';
|
|
3
|
+
import {PipelineExecutionContext} from './pipeline-execution-context';
|
|
4
4
|
import {createStepHelpers, PipelineStepHelpers} from './step-helpers';
|
|
5
5
|
|
|
6
6
|
export type PipelineStepCode = string;
|
|
@@ -8,14 +8,9 @@ export type PipelineStepCode = string;
|
|
|
8
8
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
9
|
export type PipelineStepPayload = any;
|
|
10
10
|
|
|
11
|
-
export interface
|
|
12
|
-
authorization?: PipelineRequestAuthorization;
|
|
13
|
-
traceId?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface PipelineStepData<C = PipelineStepPayload, CTX = PipelineStepContext> {
|
|
11
|
+
export interface PipelineStepData<C = PipelineStepPayload, CTX = PipelineExecutionContext> {
|
|
17
12
|
/** this is runtime context */
|
|
18
|
-
$context
|
|
13
|
+
$context: CTX;
|
|
19
14
|
content: C;
|
|
20
15
|
}
|
|
21
16
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {nanoid} from 'nanoid';
|
|
2
2
|
import {Config, Logger} from '../utils';
|
|
3
3
|
import {AbstractPipelineExecution, PipelineExecutionOptions} from './pipeline-execution';
|
|
4
|
+
import {PipelineExecutionContext} from './pipeline-execution-context';
|
|
4
5
|
import {
|
|
5
6
|
DefaultPipelineStepBuilder,
|
|
6
7
|
PipelineStep,
|
|
@@ -13,27 +14,9 @@ import {
|
|
|
13
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
15
|
export type PipelineRequestPayload = any;
|
|
15
16
|
|
|
16
|
-
export interface PipelineRequestAuthorizationRole {
|
|
17
|
-
code?: string;
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
-
[key: string]: any | undefined;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
-
export interface PipelineRequestAuthorization<A = any> {
|
|
24
|
-
readonly authorized: boolean;
|
|
25
|
-
/** undefined when authorized is false */
|
|
26
|
-
readonly authentication?: A;
|
|
27
|
-
/** empty array when authorized is false */
|
|
28
|
-
readonly roles: Array<PipelineRequestAuthorizationRole>;
|
|
29
|
-
/** headers should be added to response */
|
|
30
|
-
readonly headers?: Record<string, string>;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
17
|
export interface PipelineRequest<C = PipelineRequestPayload> {
|
|
34
18
|
payload: C;
|
|
35
|
-
|
|
36
|
-
traceId?: string;
|
|
19
|
+
$context: PipelineExecutionContext;
|
|
37
20
|
}
|
|
38
21
|
|
|
39
22
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -41,6 +24,7 @@ export type PipelineResponsePayload = any;
|
|
|
41
24
|
|
|
42
25
|
export interface PipelineResponse<C = PipelineResponsePayload> {
|
|
43
26
|
payload: C;
|
|
27
|
+
$context: PipelineExecutionContext;
|
|
44
28
|
}
|
|
45
29
|
|
|
46
30
|
export type PipelineCode = string;
|
|
@@ -95,15 +79,21 @@ export abstract class AbstractPipeline<In = any, Out = any> extends AbstractPipe
|
|
|
95
79
|
}
|
|
96
80
|
|
|
97
81
|
public convertRequestToPipelineData<I, FirstStepIn>(request: PipelineRequest<I>): PipelineStepData<FirstStepIn> {
|
|
98
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
content: request.payload as unknown as FirstStepIn,
|
|
84
|
+
$context: request.$context
|
|
85
|
+
};
|
|
99
86
|
}
|
|
100
87
|
|
|
101
88
|
public convertPipelineDataToResponse<LastStepOut, O>(result: PipelineStepData<LastStepOut>): PipelineResponse<O> {
|
|
102
|
-
return {
|
|
89
|
+
return {
|
|
90
|
+
payload: result.content as unknown as O,
|
|
91
|
+
$context: result.$context
|
|
92
|
+
};
|
|
103
93
|
}
|
|
104
94
|
|
|
105
95
|
protected createTraceId(request: PipelineRequest<In>): string {
|
|
106
|
-
const {traceId} = request;
|
|
96
|
+
const {traceId} = request.$context ?? {};
|
|
107
97
|
if (traceId == null || traceId.trim().length === 0) {
|
|
108
98
|
return nanoid(16);
|
|
109
99
|
} else {
|
|
@@ -118,8 +108,8 @@ export abstract class AbstractPipeline<In = any, Out = any> extends AbstractPipe
|
|
|
118
108
|
* - use last step's result as response.
|
|
119
109
|
*/
|
|
120
110
|
public async perform(request: PipelineRequest<In>): Promise<PipelineResponse<Out>> {
|
|
121
|
-
const
|
|
122
|
-
const
|
|
111
|
+
const $context = request.$context;
|
|
112
|
+
const traceId = $context.traceId;
|
|
123
113
|
const response = await this.measurePerformance(traceId, 'PIPELINE')
|
|
124
114
|
.execute(async () => {
|
|
125
115
|
this.traceRequest(traceId, request);
|
|
@@ -129,9 +119,7 @@ export abstract class AbstractPipeline<In = any, Out = any> extends AbstractPipe
|
|
|
129
119
|
return await this.measurePerformance(traceId, 'STEP', step.constructor.name)
|
|
130
120
|
.execute(async () => {
|
|
131
121
|
this.traceStepIn(traceId, step, request);
|
|
132
|
-
const response = await step.perform({
|
|
133
|
-
...request, $context: {...request.$context, authorization, traceId}
|
|
134
|
-
});
|
|
122
|
+
const response = await step.perform({...request, $context});
|
|
135
123
|
this.traceStepOut(traceId, step, response);
|
|
136
124
|
// if no response returned, keep using request for next
|
|
137
125
|
return this.returnOrContinueOrClear(request, response);
|