@adaas/a-utils 0.1.24 → 0.1.26

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaas/a-utils",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "A-Utils is a set of utilities that are used across the ADAAS ecosystem. This package is designed to be a collection of utilities that are used across the ADAAS ecosystem.",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.cjs",
@@ -80,7 +80,7 @@
80
80
  "build": "tsup --config tsup.config.ts"
81
81
  },
82
82
  "dependencies": {
83
- "@adaas/a-concept": "^0.1.46"
83
+ "@adaas/a-concept": "^0.1.47"
84
84
  },
85
85
  "devDependencies": {
86
86
  "@types/chai": "^4.3.14",
package/src/index.ts CHANGED
@@ -71,6 +71,13 @@ export { A_ExecutionContext } from './lib/A-Execution/A-Execution.context';
71
71
  export { A_OperationContext } from './lib/A-Operation/A-Operation.context';
72
72
  export * from './lib/A-Operation/A-Operation.types';
73
73
 
74
+ // ============================================================================
75
+ // A-Service Container
76
+ // ============================================================================
77
+ export { A_Service } from './lib/A-Service/A-Service.container';
78
+ // export * from './lib/A-Service/A-Service.types';
79
+ export * from './lib/A-Service/A-Service.constants';
80
+
74
81
  // ============================================================================
75
82
  // A-Polyfill Components
76
83
  // ============================================================================
@@ -0,0 +1,17 @@
1
+ export enum A_ServiceFeatures {
2
+
3
+ onBeforeLoad = '_A_Service_onBeforeLoad',
4
+ onLoad = '_A_Service_onLoad',
5
+ onAfterLoad = '_A_Service_onAfterLoad',
6
+
7
+ onBeforeStart = '_A_Service_onBeforeStart',
8
+ onStart = '_A_Service_onStart',
9
+ onAfterStart = '_A_Service_onAfterStart',
10
+
11
+ onBeforeStop = '_A_Service_onBeforeStop',
12
+ onStop = '_A_Service_onStop',
13
+ onAfterStop = '_A_Service_onAfterStop',
14
+
15
+
16
+ onError = '_A_Service_onError',
17
+ }
@@ -0,0 +1,162 @@
1
+ import { A_Concept, A_Container, A_Error, A_Feature, A_Inject } from "@adaas/a-concept";
2
+ import { A_ServiceFeatures } from "./A-Service.constants";
3
+ import { A_Polyfill } from "../A-Polyfill/A-Polyfill.component";
4
+ import { A_Config } from "../A-Config/A-Config.context";
5
+ import { A_Logger } from "../A-Logger/A-Logger.component";
6
+ import { A_Service_Error } from "./A-Service.error";
7
+
8
+
9
+
10
+
11
+ /**
12
+ * A-Service is a container that can run different types of services, such as HTTP servers, workers, etc.
13
+ * Depending on the provided config and configuration, it will load the necessary components and start the service.
14
+ *
15
+ */
16
+ export class A_Service extends A_Container {
17
+
18
+
19
+ @A_Concept.Start()
20
+ /**
21
+ * Start the server
22
+ */
23
+ async start() {
24
+ try {
25
+ await this.call(A_ServiceFeatures.onBeforeStart);
26
+
27
+ await this.call(A_ServiceFeatures.onStart);
28
+
29
+ await this.call(A_ServiceFeatures.onAfterStart);
30
+
31
+ } catch (error) {
32
+
33
+ let wrappedError;
34
+
35
+ switch (true) {
36
+ case error instanceof A_Service_Error:
37
+ wrappedError = error;
38
+ break;
39
+
40
+ case error instanceof A_Error && error.originalError instanceof A_Service_Error:
41
+ wrappedError = error.originalError;
42
+ break;
43
+
44
+ default:
45
+ wrappedError = new A_Service_Error({
46
+ title: A_Service_Error.ServiceStartError,
47
+ description: 'An error occurred while processing the request.',
48
+ originalError: error
49
+ })
50
+ break;
51
+ }
52
+
53
+ this.scope.register(wrappedError);
54
+
55
+ await this.call(A_ServiceFeatures.onError);
56
+ }
57
+
58
+ }
59
+
60
+ @A_Concept.Stop()
61
+ /**
62
+ * Stop the server
63
+ */
64
+ async stop() {
65
+ try {
66
+ await this.call(A_ServiceFeatures.onBeforeStop);
67
+
68
+ await this.call(A_ServiceFeatures.onStop);
69
+
70
+ await this.call(A_ServiceFeatures.onAfterStop);
71
+
72
+ } catch (error) {
73
+
74
+ let wrappedError;
75
+
76
+ switch (true) {
77
+ case error instanceof A_Service_Error:
78
+ wrappedError = error;
79
+ break;
80
+
81
+ case error instanceof A_Error && error.originalError instanceof A_Service_Error:
82
+ wrappedError = error.originalError;
83
+ break;
84
+
85
+ default:
86
+ wrappedError = new A_Service_Error({
87
+ title: A_Service_Error.ServiceStopError,
88
+ description: 'An error occurred while processing the request.',
89
+ originalError: error
90
+ })
91
+ break;
92
+ }
93
+
94
+ this.scope.register(wrappedError);
95
+
96
+ await this.call(A_ServiceFeatures.onError);
97
+ }
98
+ }
99
+
100
+ // ======================================================================================
101
+ // ============================= A-Service Lifecycle =================================
102
+ // ======================================================================================
103
+
104
+ @A_Feature.Extend()
105
+ protected async [A_ServiceFeatures.onBeforeLoad](
106
+ @A_Inject(A_Polyfill) polyfill: A_Polyfill,
107
+ ): Promise<void> {
108
+ // Initialize Polyfill
109
+ if (!polyfill) {
110
+ this.scope.register(A_Polyfill);
111
+ polyfill = this.scope.resolve(A_Polyfill)!
112
+ }
113
+ }
114
+
115
+ @A_Feature.Extend()
116
+ protected async [A_ServiceFeatures.onLoad](...args: any[]) { }
117
+
118
+ @A_Feature.Extend()
119
+ protected async [A_ServiceFeatures.onAfterLoad](...args: any[]) { }
120
+
121
+
122
+ @A_Feature.Extend()
123
+ protected async [A_ServiceFeatures.onBeforeStart](...args: any[]) { }
124
+
125
+ @A_Feature.Extend()
126
+ protected async [A_ServiceFeatures.onStart](...args: any[]) { }
127
+
128
+ @A_Feature.Extend()
129
+ protected async [A_ServiceFeatures.onAfterStart](...args: any[]) { }
130
+
131
+
132
+
133
+ @A_Feature.Extend()
134
+ protected async [A_ServiceFeatures.onBeforeStop](...args: any[]) { }
135
+
136
+ @A_Feature.Extend()
137
+ protected async [A_ServiceFeatures.onStop](...args: any[]) { }
138
+
139
+ @A_Feature.Extend()
140
+ protected async [A_ServiceFeatures.onAfterStop](...args: any[]) { }
141
+
142
+
143
+
144
+ @A_Feature.Extend({
145
+ before: /.*/
146
+ })
147
+ protected async [A_ServiceFeatures.onError](
148
+ @A_Inject(A_Error) error: A_Error,
149
+ @A_Inject(A_Logger) logger?: A_Logger,
150
+ ...args: any[]) {
151
+ logger?.error(error);
152
+ }
153
+
154
+ }
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
@@ -0,0 +1,11 @@
1
+ import { A_Error } from "@adaas/a-concept";
2
+
3
+
4
+
5
+ export class A_Service_Error extends A_Error {
6
+
7
+ static readonly ServiceStartError = 'Service start error';
8
+
9
+ static readonly ServiceStopError = 'Service stop error';
10
+
11
+ }
@@ -0,0 +1,32 @@
1
+ import { A_Component, A_Fragment } from "@adaas/a-concept";
2
+
3
+
4
+ export type A_SERVER_TYPES__ServerFeatures = [
5
+ A_SERVER_TYPES__ServerFeature.beforeStart,
6
+ A_SERVER_TYPES__ServerFeature.afterStart,
7
+ A_SERVER_TYPES__ServerFeature.beforeStop,
8
+ A_SERVER_TYPES__ServerFeature.afterStop,
9
+ A_SERVER_TYPES__ServerFeature.onRequest
10
+ ]
11
+
12
+ export enum A_SERVER_TYPES__ServerFeature {
13
+ beforeStart = 'beforeStart',
14
+ afterStart = 'afterStart',
15
+ beforeStop = 'beforeStop',
16
+ afterStop = 'afterStop',
17
+ beforeRequest = 'beforeRequest',
18
+ onRequest = 'onRequest',
19
+ afterRequest = 'afterRequest',
20
+ }
21
+
22
+
23
+ export type A_ServiceConstructor = {
24
+ name: string,
25
+ version: string,
26
+ controllers: Array<A_Component>,
27
+ entities: Array<A_Fragment>,
28
+ extensions: Array<A_Component>
29
+ }
30
+
31
+
32
+
@@ -612,6 +612,71 @@ describe('A-Command tests', () => {
612
612
  expect([A_Command_Status.COMPLETED, A_Command_Status.FAILED])
613
613
  .toContain(command.status);
614
614
  });
615
+
616
+ it('Should stop command execution in case of error', async () => {
617
+
618
+ class FailingProcessor extends A_Component {
619
+
620
+ @A_Feature.Extend({
621
+ name: A_CommandFeatures.onExecute
622
+ })
623
+ async step1(
624
+ @A_Inject(A_Caller) command: ErrorTestCommand
625
+ ) {
626
+ await new Promise(resolve => setTimeout(resolve, 500));
627
+
628
+ testExecutionLog.push('Step 1 executed');
629
+ }
630
+
631
+ @A_Feature.Extend({
632
+ name: A_CommandFeatures.onExecute
633
+ })
634
+ async step2(
635
+ @A_Inject(A_Caller) command: ErrorTestCommand
636
+ ) {
637
+ await new Promise(resolve => setTimeout(resolve, 500));
638
+ testExecutionLog.push('Step 2 executed');
639
+ throw new Error('Simulated error in step 2');
640
+ }
641
+
642
+ @A_Feature.Extend({
643
+ name: A_CommandFeatures.onExecute
644
+ })
645
+ async step3(
646
+ @A_Inject(A_Caller) command: ErrorTestCommand
647
+ ) {
648
+ testExecutionLog.push('Step 3 executed');
649
+ }
650
+ }
651
+
652
+ const container = new A_Container({
653
+ name: 'Error Stop Test Container',
654
+ components: [
655
+ FailingProcessor,
656
+ A_StateMachine
657
+ ],
658
+ entities: [ErrorTestCommand]
659
+ });
660
+
661
+ const concept = new A_Concept({
662
+ containers: [container]
663
+ });
664
+
665
+ await concept.load();
666
+
667
+ const command = new ErrorTestCommand({ shouldFail: true });
668
+ container.scope.register(command);
669
+
670
+ await command.execute();
671
+
672
+ expect(command.status).toBe(A_Command_Status.FAILED);
673
+ expect(command.error).toBeDefined();
674
+ expect(command.isProcessed).toBe(true);
675
+ expect(testExecutionLog).toEqual([
676
+ 'Step 1 executed',
677
+ 'Step 2 executed'
678
+ ]); // Step 3 should not be executed
679
+ });
615
680
  });
616
681
 
617
682
  // =============================================================================