@rainbow-o23/n1 1.0.58 → 1.0.60

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 CHANGED
@@ -399,7 +399,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
399
399
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
400
400
  PERFORMANCE OF THIS SOFTWARE.
401
401
  ***************************************************************************** */
402
- /* global Reflect, Promise, SuppressedError, Symbol */
402
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
403
403
 
404
404
 
405
405
  function __decorate(decorators, target, key, desc) {
@@ -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) {
@@ -704,24 +813,28 @@ class AbstractPipeline extends AbstractPipelineExecution {
704
813
  const options = this.buildStepOptions();
705
814
  return await Promise.all(this.getStepBuilders().map(async (builder) => await builder.create(options)));
706
815
  }
816
+ defendPipelineRequest(request) {
817
+ if (request.$context == null) {
818
+ request.$context = new PipelineExecutionContext();
819
+ }
820
+ return request;
821
+ }
707
822
  convertRequestToPipelineData(request) {
708
- return { content: request.payload };
823
+ return {
824
+ content: request.payload,
825
+ $context: request.$context
826
+ };
709
827
  }
710
828
  convertPipelineDataToResponse(result) {
711
- return { payload: result.content };
712
- }
713
- createTraceId(request) {
714
- const { traceId } = request;
715
- if (traceId == null || traceId.trim().length === 0) {
716
- return nanoid.nanoid(16);
717
- }
718
- else {
719
- return traceId;
720
- }
829
+ return {
830
+ payload: result.content,
831
+ $context: result.$context
832
+ };
721
833
  }
722
834
  async perform(request) {
723
- const traceId = this.createTraceId(request);
724
- const authorization = request.authorization;
835
+ request = this.defendPipelineRequest(request);
836
+ const $context = request.$context;
837
+ const traceId = $context.traceId;
725
838
  const response = await this.measurePerformance(traceId, 'PIPELINE')
726
839
  .execute(async () => {
727
840
  this.traceRequest(traceId, request);
@@ -731,9 +844,7 @@ class AbstractPipeline extends AbstractPipelineExecution {
731
844
  return await this.measurePerformance(traceId, 'STEP', step.constructor.name)
732
845
  .execute(async () => {
733
846
  this.traceStepIn(traceId, step, request);
734
- const response = await step.perform({
735
- ...request, $context: { ...request.$context, authorization, traceId }
736
- });
847
+ const response = await step.perform({ ...request, $context });
737
848
  this.traceStepOut(traceId, step, response);
738
849
  return this.returnOrContinueOrClear(request, response);
739
850
  });
@@ -818,8 +929,10 @@ exports.LoggerUtils = LoggerUtils;
818
929
  exports.PIPELINE_STEP_FILE_SYMBOL = PIPELINE_STEP_FILE_SYMBOL;
819
930
  exports.PIPELINE_STEP_RETURN_NULL = PIPELINE_STEP_RETURN_NULL;
820
931
  exports.PerformanceExecution = PerformanceExecution;
932
+ exports.PipelineExecutionContext = PipelineExecutionContext;
821
933
  exports.PipelineRepository = PipelineRepository;
822
934
  exports.PipelineStepDateHelper = PipelineStepDateHelper;
935
+ exports.TemporaryExecutionContext = TemporaryExecutionContext;
823
936
  exports.UncatchableError = UncatchableError;
824
937
  exports.createConfig = createConfig;
825
938
  exports.createLogger = createLogger;
package/index.js CHANGED
@@ -397,7 +397,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
397
397
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
398
398
  PERFORMANCE OF THIS SOFTWARE.
399
399
  ***************************************************************************** */
400
- /* global Reflect, Promise, SuppressedError, Symbol */
400
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
401
401
 
402
402
 
403
403
  function __decorate(decorators, target, key, desc) {
@@ -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) {
@@ -702,24 +811,28 @@ class AbstractPipeline extends AbstractPipelineExecution {
702
811
  const options = this.buildStepOptions();
703
812
  return await Promise.all(this.getStepBuilders().map(async (builder) => await builder.create(options)));
704
813
  }
814
+ defendPipelineRequest(request) {
815
+ if (request.$context == null) {
816
+ request.$context = new PipelineExecutionContext();
817
+ }
818
+ return request;
819
+ }
705
820
  convertRequestToPipelineData(request) {
706
- return { content: request.payload };
821
+ return {
822
+ content: request.payload,
823
+ $context: request.$context
824
+ };
707
825
  }
708
826
  convertPipelineDataToResponse(result) {
709
- return { payload: result.content };
710
- }
711
- createTraceId(request) {
712
- const { traceId } = request;
713
- if (traceId == null || traceId.trim().length === 0) {
714
- return nanoid(16);
715
- }
716
- else {
717
- return traceId;
718
- }
827
+ return {
828
+ payload: result.content,
829
+ $context: result.$context
830
+ };
719
831
  }
720
832
  async perform(request) {
721
- const traceId = this.createTraceId(request);
722
- const authorization = request.authorization;
833
+ request = this.defendPipelineRequest(request);
834
+ const $context = request.$context;
835
+ const traceId = $context.traceId;
723
836
  const response = await this.measurePerformance(traceId, 'PIPELINE')
724
837
  .execute(async () => {
725
838
  this.traceRequest(traceId, request);
@@ -729,9 +842,7 @@ class AbstractPipeline extends AbstractPipelineExecution {
729
842
  return await this.measurePerformance(traceId, 'STEP', step.constructor.name)
730
843
  .execute(async () => {
731
844
  this.traceStepIn(traceId, step, request);
732
- const response = await step.perform({
733
- ...request, $context: { ...request.$context, authorization, traceId }
734
- });
845
+ const response = await step.perform({ ...request, $context });
735
846
  this.traceStepOut(traceId, step, response);
736
847
  return this.returnOrContinueOrClear(request, response);
737
848
  });
@@ -795,4 +906,4 @@ class PipelineRepository {
795
906
  }
796
907
  }
797
908
 
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 };
909
+ 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 };
@@ -1,4 +1,5 @@
1
1
  export * from './pipeline-execution';
2
+ export * from './pipeline-execution-context';
2
3
  export * from './pipeline-step';
3
4
  export * from './pipeline';
4
5
  export * from './step-helpers-utils';
@@ -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 PipelineStepContext {
8
- authorization?: PipelineRequestAuthorization;
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
- authorization?: PipelineRequestAuthorization;
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> {
@@ -39,9 +30,9 @@ export declare abstract class AbstractPipeline<In = any, Out = any> extends Abst
39
30
  protected abstract getStepBuilders(): Array<PipelineStepBuilder>;
40
31
  protected buildStepOptions(): Pick<PipelineStepOptions, 'config' | 'logger'>;
41
32
  createSteps(): Promise<Array<PipelineStep>>;
33
+ protected defendPipelineRequest(request: PipelineRequest<In>): Required<PipelineRequest<In>>;
42
34
  convertRequestToPipelineData<I, FirstStepIn>(request: PipelineRequest<I>): PipelineStepData<FirstStepIn>;
43
35
  convertPipelineDataToResponse<LastStepOut, O>(result: PipelineStepData<LastStepOut>): PipelineResponse<O>;
44
- protected createTraceId(request: PipelineRequest<In>): string;
45
36
  perform(request: PipelineRequest<In>): Promise<PipelineResponse<Out>>;
46
37
  }
47
38
  export declare abstract class AbstractStaticPipeline<In = any, Out = any> extends AbstractPipeline<In, Out> {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainbow-o23/n1",
3
- "version": "1.0.58",
3
+ "version": "1.0.60",
4
4
  "description": "o23 interfaces",
5
5
  "main": "index.cjs",
6
6
  "module": "index.js",
@@ -1,4 +1,5 @@
1
1
  export * from './pipeline-execution';
2
+ export * from './pipeline-execution-context';
2
3
  export * from './pipeline-step';
3
4
  export * from './pipeline';
4
5
 
@@ -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 PipelineStepContext {
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?: CTX;
13
+ $context: CTX;
19
14
  content: C;
20
15
  }
21
16
 
@@ -1,6 +1,6 @@
1
- import {nanoid} from 'nanoid';
2
1
  import {Config, Logger} from '../utils';
3
2
  import {AbstractPipelineExecution, PipelineExecutionOptions} from './pipeline-execution';
3
+ import {PipelineExecutionContext} from './pipeline-execution-context';
4
4
  import {
5
5
  DefaultPipelineStepBuilder,
6
6
  PipelineStep,
@@ -13,27 +13,9 @@ import {
13
13
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
14
  export type PipelineRequestPayload = any;
15
15
 
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
16
  export interface PipelineRequest<C = PipelineRequestPayload> {
34
17
  payload: C;
35
- authorization?: PipelineRequestAuthorization;
36
- traceId?: string;
18
+ $context?: PipelineExecutionContext;
37
19
  }
38
20
 
39
21
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -41,6 +23,7 @@ export type PipelineResponsePayload = any;
41
23
 
42
24
  export interface PipelineResponse<C = PipelineResponsePayload> {
43
25
  payload: C;
26
+ $context: PipelineExecutionContext;
44
27
  }
45
28
 
46
29
  export type PipelineCode = string;
@@ -94,21 +77,25 @@ export abstract class AbstractPipeline<In = any, Out = any> extends AbstractPipe
94
77
  return await Promise.all(this.getStepBuilders().map(async builder => await builder.create(options)));
95
78
  }
96
79
 
97
- public convertRequestToPipelineData<I, FirstStepIn>(request: PipelineRequest<I>): PipelineStepData<FirstStepIn> {
98
- return {content: request.payload as unknown as FirstStepIn};
80
+ protected defendPipelineRequest(request: PipelineRequest<In>): Required<PipelineRequest<In>> {
81
+ if (request.$context == null) {
82
+ request.$context = new PipelineExecutionContext();
83
+ }
84
+ return request as Required<PipelineRequest<In>>;
99
85
  }
100
86
 
101
- public convertPipelineDataToResponse<LastStepOut, O>(result: PipelineStepData<LastStepOut>): PipelineResponse<O> {
102
- return {payload: result.content as unknown as O};
87
+ public convertRequestToPipelineData<I, FirstStepIn>(request: PipelineRequest<I>): PipelineStepData<FirstStepIn> {
88
+ return {
89
+ content: request.payload as unknown as FirstStepIn,
90
+ $context: request.$context
91
+ };
103
92
  }
104
93
 
105
- protected createTraceId(request: PipelineRequest<In>): string {
106
- const {traceId} = request;
107
- if (traceId == null || traceId.trim().length === 0) {
108
- return nanoid(16);
109
- } else {
110
- return traceId;
111
- }
94
+ public convertPipelineDataToResponse<LastStepOut, O>(result: PipelineStepData<LastStepOut>): PipelineResponse<O> {
95
+ return {
96
+ payload: result.content as unknown as O,
97
+ $context: result.$context
98
+ };
112
99
  }
113
100
 
114
101
  /**
@@ -118,8 +105,9 @@ export abstract class AbstractPipeline<In = any, Out = any> extends AbstractPipe
118
105
  * - use last step's result as response.
119
106
  */
120
107
  public async perform(request: PipelineRequest<In>): Promise<PipelineResponse<Out>> {
121
- const traceId = this.createTraceId(request);
122
- const authorization = request.authorization;
108
+ request = this.defendPipelineRequest(request);
109
+ const $context = request.$context;
110
+ const traceId = $context.traceId;
123
111
  const response = await this.measurePerformance(traceId, 'PIPELINE')
124
112
  .execute(async () => {
125
113
  this.traceRequest(traceId, request);
@@ -129,9 +117,7 @@ export abstract class AbstractPipeline<In = any, Out = any> extends AbstractPipe
129
117
  return await this.measurePerformance(traceId, 'STEP', step.constructor.name)
130
118
  .execute(async () => {
131
119
  this.traceStepIn(traceId, step, request);
132
- const response = await step.perform({
133
- ...request, $context: {...request.$context, authorization, traceId}
134
- });
120
+ const response = await step.perform({...request, $context});
135
121
  this.traceStepOut(traceId, step, response);
136
122
  // if no response returned, keep using request for next
137
123
  return this.returnOrContinueOrClear(request, response);