@adaas/a-utils 0.1.11 → 0.1.13

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.
@@ -0,0 +1,268 @@
1
+ /**
2
+ * A-Command Examples
3
+ *
4
+ * This file contains practical examples of using A-Command for various scenarios.
5
+ * Run with: npx ts-node examples/command-examples.ts
6
+ */
7
+
8
+ import { A_Command } from '../src/lib/A-Command/A-Command.entity';
9
+ import { A_CONSTANTS_A_Command_Features } from '../src/lib/A-Command/A-Command.constants';
10
+ import { A_Memory } from '../src/lib/A-Memory/A-Memory.context';
11
+ import { A_Component, A_Context, A_Feature, A_Inject, A_Error } from '@adaas/a-concept';
12
+
13
+ // Example 1: Basic Command Usage
14
+ async function basicCommandExample() {
15
+ console.log('\n=== Basic Command Example ===');
16
+
17
+ const command = new A_Command({
18
+ action: 'greet',
19
+ name: 'World'
20
+ });
21
+
22
+ A_Context.root.register(command);
23
+
24
+ // Add event listeners
25
+ command.on('init', () => console.log('Command initializing...'));
26
+ command.on('complete', () => console.log('Command completed!'));
27
+
28
+ await command.execute();
29
+
30
+ console.log(`Status: ${command.status}`);
31
+ console.log(`Duration: ${command.duration}ms`);
32
+ console.log(`Code: ${command.code}`);
33
+ }
34
+
35
+ // Example 2: Typed Command with Custom Logic
36
+ interface UserCreateParams {
37
+ name: string;
38
+ email: string;
39
+ role: 'admin' | 'user';
40
+ }
41
+
42
+ interface UserCreateResult {
43
+ userId: string;
44
+ createdAt: string;
45
+ profileCreated: boolean;
46
+ }
47
+
48
+ class CreateUserCommand extends A_Command<UserCreateParams, UserCreateResult> {}
49
+
50
+ class UserCreationService extends A_Component {
51
+
52
+ @A_Feature.Extend({ scope: [CreateUserCommand] })
53
+ async [A_CONSTANTS_A_Command_Features.EXECUTE](
54
+ @A_Inject(A_Memory) memory: A_Memory<UserCreateResult>
55
+ ) {
56
+ const command = A_Context.scope(this).resolve(CreateUserCommand);
57
+ const { name, email, role } = command.params;
58
+
59
+ console.log(`Creating user: ${name} (${email}) with role: ${role}`);
60
+
61
+ // Simulate user creation
62
+ const userId = `user_${Date.now()}`;
63
+ const createdAt = new Date().toISOString();
64
+
65
+ // Store results in memory
66
+ await memory.set('userId', userId);
67
+ await memory.set('createdAt', createdAt);
68
+ await memory.set('profileCreated', true);
69
+
70
+ console.log(`User created with ID: ${userId}`);
71
+ }
72
+ }
73
+
74
+ async function typedCommandExample() {
75
+ console.log('\n=== Typed Command with Custom Logic Example ===');
76
+
77
+ A_Context.reset();
78
+ A_Context.root.register(UserCreationService);
79
+
80
+ const command = new CreateUserCommand({
81
+ name: 'John Doe',
82
+ email: 'john@example.com',
83
+ role: 'user'
84
+ });
85
+
86
+ A_Context.root.register(command);
87
+ await command.execute();
88
+
89
+ console.log('User creation result:', command.result);
90
+ }
91
+
92
+ // Example 3: Command Serialization and Persistence
93
+ async function serializationExample() {
94
+ console.log('\n=== Command Serialization Example ===');
95
+
96
+ A_Context.reset();
97
+ A_Context.root.register(UserCreationService);
98
+
99
+ // Create and execute original command
100
+ const originalCommand = new CreateUserCommand({
101
+ name: 'Jane Smith',
102
+ email: 'jane@example.com',
103
+ role: 'admin'
104
+ });
105
+
106
+ A_Context.root.register(originalCommand);
107
+ await originalCommand.execute();
108
+
109
+ // Serialize command
110
+ const serialized = originalCommand.toJSON();
111
+ console.log('Command serialized for storage/transmission');
112
+
113
+ // Simulate storage and retrieval
114
+ const serializedJson = JSON.stringify(serialized);
115
+ const parsedData = JSON.parse(serializedJson);
116
+
117
+ // Restore command from serialized data
118
+ const restoredCommand = new CreateUserCommand(parsedData);
119
+
120
+ console.log('Command restored from serialization:');
121
+ console.log(`- Status: ${restoredCommand.status}`);
122
+ console.log(`- Duration: ${restoredCommand.duration}ms`);
123
+ console.log(`- User ID: ${restoredCommand.result?.userId}`);
124
+ console.log(`- Created At: ${restoredCommand.result?.createdAt}`);
125
+ }
126
+
127
+ // Example 4: Error Handling
128
+ class FailingCommand extends A_Command<{ shouldFail: boolean }, { success: boolean }> {}
129
+
130
+ class FailingService extends A_Component {
131
+
132
+ @A_Feature.Extend({ scope: [FailingCommand] })
133
+ async [A_CONSTANTS_A_Command_Features.EXECUTE](
134
+ @A_Inject(A_Memory) memory: A_Memory<{ success: boolean }>
135
+ ) {
136
+ const command = A_Context.scope(this).resolve(FailingCommand);
137
+
138
+ if (command.params.shouldFail) {
139
+ // Add error to memory
140
+ await memory.error(new A_Error({
141
+ title: 'Intentional Failure',
142
+ message: 'This command was designed to fail',
143
+ code: 'INTENTIONAL_FAIL'
144
+ }));
145
+
146
+ throw new Error('Command failed as requested');
147
+ }
148
+
149
+ await memory.set('success', true);
150
+ }
151
+ }
152
+
153
+ async function errorHandlingExample() {
154
+ console.log('\n=== Error Handling Example ===');
155
+
156
+ A_Context.reset();
157
+ A_Context.root.register(FailingService);
158
+
159
+ // Test successful command
160
+ const successCommand = new FailingCommand({ shouldFail: false });
161
+ A_Context.root.register(successCommand);
162
+ await successCommand.execute();
163
+
164
+ console.log(`Success command - Status: ${successCommand.status}`);
165
+ console.log(`Success command - Result:`, successCommand.result);
166
+
167
+ // Test failing command
168
+ const failCommand = new FailingCommand({ shouldFail: true });
169
+ A_Context.root.register(failCommand);
170
+ await failCommand.execute();
171
+
172
+ console.log(`Fail command - Status: ${failCommand.status}`);
173
+ console.log(`Fail command - Is Failed: ${failCommand.isFailed}`);
174
+ console.log(`Fail command - Errors:`, Array.from(failCommand.errors?.values() || []));
175
+ }
176
+
177
+ // Example 5: Custom Events
178
+ type FileProcessEvents = 'validation-started' | 'processing' | 'cleanup';
179
+
180
+ class FileProcessCommand extends A_Command<
181
+ { filePath: string; operation: string },
182
+ { outputPath: string; size: number },
183
+ FileProcessEvents
184
+ > {}
185
+
186
+ class FileProcessor extends A_Component {
187
+
188
+ @A_Feature.Extend({ scope: [FileProcessCommand] })
189
+ async [A_CONSTANTS_A_Command_Features.EXECUTE](
190
+ @A_Inject(A_Memory) memory: A_Memory<{ outputPath: string; size: number }>
191
+ ) {
192
+ const command = A_Context.scope(this).resolve(FileProcessCommand);
193
+ const { filePath, operation } = command.params;
194
+
195
+ // Emit custom events during processing
196
+ command.emit('validation-started');
197
+ console.log(`Validating file: ${filePath}`);
198
+ await new Promise(resolve => setTimeout(resolve, 100));
199
+
200
+ command.emit('processing');
201
+ console.log(`Processing file with operation: ${operation}`);
202
+ await new Promise(resolve => setTimeout(resolve, 200));
203
+
204
+ command.emit('cleanup');
205
+ console.log('Cleaning up temporary files');
206
+ await new Promise(resolve => setTimeout(resolve, 50));
207
+
208
+ await memory.set('outputPath', `processed_${filePath}`);
209
+ await memory.set('size', 1024);
210
+ }
211
+ }
212
+
213
+ async function customEventsExample() {
214
+ console.log('\n=== Custom Events Example ===');
215
+
216
+ A_Context.reset();
217
+ A_Context.root.register(FileProcessor);
218
+
219
+ const command = new FileProcessCommand({
220
+ filePath: 'document.pdf',
221
+ operation: 'compress'
222
+ });
223
+
224
+ // Subscribe to custom events
225
+ command.on('validation-started', () => console.log('📋 Validation phase started'));
226
+ command.on('processing', () => console.log('⚙️ Processing phase started'));
227
+ command.on('cleanup', () => console.log('🧹 Cleanup phase started'));
228
+
229
+ // Subscribe to lifecycle events
230
+ command.on('complete', () => console.log('✅ File processing completed'));
231
+
232
+ A_Context.root.register(command);
233
+ await command.execute();
234
+
235
+ console.log('Final result:', command.result);
236
+ }
237
+
238
+ // Run all examples
239
+ async function runAllExamples() {
240
+ console.log('🚀 Running A-Command Examples\n');
241
+
242
+ try {
243
+ await basicCommandExample();
244
+ await typedCommandExample();
245
+ await serializationExample();
246
+ await errorHandlingExample();
247
+ await customEventsExample();
248
+
249
+ console.log('\n✅ All examples completed successfully!');
250
+ } catch (error) {
251
+ console.error('\n❌ Example failed:', error);
252
+ }
253
+ }
254
+
255
+ // Export for use as module or run directly
256
+ export {
257
+ basicCommandExample,
258
+ typedCommandExample,
259
+ serializationExample,
260
+ errorHandlingExample,
261
+ customEventsExample,
262
+ runAllExamples
263
+ };
264
+
265
+ // Run if this file is executed directly
266
+ if (require.main === module) {
267
+ runAllExamples();
268
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaas/a-utils",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
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
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -5,7 +5,11 @@ export enum A_TYPES__CommandMetaKey {
5
5
  }
6
6
 
7
7
  export enum A_CONSTANTS__A_Command_Status {
8
+ CREATED = 'CREATED',
9
+ INITIALIZATION = 'INITIALIZATION',
8
10
  INITIALIZED = 'INITIALIZED',
11
+ COMPILATION = 'COMPILATION',
12
+ COMPILED = 'COMPILED',
9
13
  IN_PROGRESS = 'IN_PROGRESS',
10
14
  COMPLETED = 'COMPLETED',
11
15
  FAILED = 'FAILED',
@@ -9,13 +9,14 @@ import {
9
9
  } from "./A-Command.constants";
10
10
  import { A_Context, A_Entity, A_Error, A_Scope } from "@adaas/a-concept";
11
11
  import { A_Memory } from "../A-Memory/A-Memory.context";
12
+ import { A_CommandError } from "./A-Command.error";
12
13
 
13
14
 
14
15
  export class A_Command<
15
16
  InvokeType extends A_TYPES__Command_Init = A_TYPES__Command_Init,
16
17
  ResultType extends Record<string, any> = Record<string, any>,
17
- LifecycleEvents extends string = A_CONSTANTS__A_Command_Event
18
- > extends A_Entity<InvokeType, A_TYPES__Command_Serialized<ResultType>> {
18
+ LifecycleEvents extends string | A_CONSTANTS__A_Command_Event = A_CONSTANTS__A_Command_Event
19
+ > extends A_Entity<InvokeType, A_TYPES__Command_Serialized<InvokeType, ResultType>> {
19
20
 
20
21
  // ====================================================================
21
22
  // ================== Static A-Command Information ====================
@@ -136,7 +137,7 @@ export class A_Command<
136
137
  /**
137
138
  * Command invocation parameters
138
139
  */
139
- params: InvokeType | A_TYPES__Command_Serialized<ResultType> | string
140
+ params: InvokeType | A_TYPES__Command_Serialized<InvokeType, ResultType> | string
140
141
  ) {
141
142
  super(params as any)
142
143
  }
@@ -148,32 +149,63 @@ export class A_Command<
148
149
 
149
150
  // should create a new Task in DB with basic records
150
151
  async init(): Promise<void> {
151
- this._status = A_CONSTANTS__A_Command_Status.IN_PROGRESS;
152
- this._startTime = new Date();
153
- if (!this.scope.isInheritedFrom(A_Context.scope(this))) {
154
- this.scope.inherit(A_Context.scope(this));
152
+ // first check statuis if it passed then - skip
153
+ if (this._status !== A_CONSTANTS__A_Command_Status.CREATED) {
154
+ return;
155
155
  }
156
156
 
157
+ this._status = A_CONSTANTS__A_Command_Status.INITIALIZATION;
158
+ this._startTime = new Date();
159
+
160
+ this.checkScopeInheritance();
157
161
 
158
162
  this.emit('init');
159
- return await this.call('init', this.scope);
163
+ await this.call('init', this.scope);
164
+ this._status = A_CONSTANTS__A_Command_Status.INITIALIZED;
160
165
  }
161
166
 
162
167
  // Should compile everything before execution
163
168
  async compile() {
169
+ if (this._status !== A_CONSTANTS__A_Command_Status.INITIALIZED) {
170
+ return;
171
+ }
172
+
173
+ this.checkScopeInheritance();
174
+
175
+ this._status = A_CONSTANTS__A_Command_Status.COMPILATION;
164
176
  this.emit('compile');
165
- return await this.call('compile', this.scope);
177
+ await this.call('compile', this.scope);
178
+ this._status = A_CONSTANTS__A_Command_Status.COMPILED;
179
+ }
180
+
181
+ /**
182
+ * Processes the command execution
183
+ *
184
+ * @returns
185
+ */
186
+ async process() {
187
+ if (this._status !== A_CONSTANTS__A_Command_Status.COMPILED)
188
+ return;
189
+
190
+ this._status = A_CONSTANTS__A_Command_Status.IN_PROGRESS;
191
+
192
+ this.checkScopeInheritance();
193
+
194
+ this.emit('execute');
195
+
196
+ await this.call('execute', this.scope);
166
197
  }
167
198
 
168
199
  /**
169
200
  * Executes the command logic.
170
201
  */
171
202
  async execute(): Promise<any> {
203
+ this.checkScopeInheritance();
204
+
172
205
  try {
173
206
  await this.init();
174
207
  await this.compile();
175
- this.emit('execute');
176
- await this.call('execute', this.scope);
208
+ await this.process();
177
209
  await this.complete();
178
210
 
179
211
  } catch (error) {
@@ -185,6 +217,8 @@ export class A_Command<
185
217
  * Marks the command as completed
186
218
  */
187
219
  async complete() {
220
+ this.checkScopeInheritance();
221
+
188
222
  this._status = A_CONSTANTS__A_Command_Status.COMPLETED;
189
223
  this._endTime = new Date();
190
224
  this._result = this.scope.resolve(A_Memory).toJSON() as ResultType;
@@ -198,6 +232,8 @@ export class A_Command<
198
232
  * Marks the command as failed
199
233
  */
200
234
  async fail() {
235
+ this.checkScopeInheritance();
236
+
201
237
  this._status = A_CONSTANTS__A_Command_Status.FAILED;
202
238
  this._endTime = new Date();
203
239
  this._errors = this.scope.resolve(A_Memory).Errors;
@@ -265,7 +301,7 @@ export class A_Command<
265
301
 
266
302
  this._params = newEntity;
267
303
 
268
- this._status = A_CONSTANTS__A_Command_Status.INITIALIZED;
304
+ this._status = A_CONSTANTS__A_Command_Status.CREATED;
269
305
  }
270
306
 
271
307
 
@@ -277,7 +313,7 @@ export class A_Command<
277
313
  *
278
314
  * @param serialized
279
315
  */
280
- fromJSON(serialized: A_TYPES__Command_Serialized<ResultType>): void {
316
+ fromJSON(serialized: A_TYPES__Command_Serialized<InvokeType, ResultType>): void {
281
317
  super.fromJSON(serialized);
282
318
 
283
319
  this._executionScope = new A_Scope();
@@ -303,7 +339,10 @@ export class A_Command<
303
339
  });
304
340
  }
305
341
 
306
- this._status = serialized.status || A_CONSTANTS__A_Command_Status.INITIALIZED;
342
+ this._params = serialized.params
343
+
344
+ this._status = serialized.status || A_CONSTANTS__A_Command_Status.CREATED;
345
+
307
346
  }
308
347
 
309
348
 
@@ -312,11 +351,12 @@ export class A_Command<
312
351
  *
313
352
  * @returns
314
353
  */
315
- toJSON(): A_TYPES__Command_Serialized<ResultType> {
354
+ toJSON(): A_TYPES__Command_Serialized<InvokeType, ResultType> {
316
355
  return {
317
356
  ...super.toJSON(),
318
357
  code: this.code,
319
358
  status: this._status,
359
+ params: this._params,
320
360
  startedAt: this._startTime ? this._startTime.toISOString() : undefined,
321
361
  endedAt: this._endTime ? this._endTime.toISOString() : undefined,
322
362
  duration: this.duration,
@@ -324,4 +364,23 @@ export class A_Command<
324
364
  errors: this.errors ? Array.from(this.errors).map(err => err.toJSON()) : undefined
325
365
  }
326
366
  };
367
+
368
+
369
+ protected checkScopeInheritance(): void {
370
+ let attachedScope: A_Scope;
371
+ try {
372
+ attachedScope = A_Context.scope(this);
373
+ } catch (error) {
374
+ throw new A_CommandError({
375
+ title: A_CommandError.CommandScopeBindingError,
376
+ description: `Command ${this.code} is not bound to any context scope. Ensure the command is properly registered within a context before execution.`,
377
+ originalError: error
378
+ });
379
+ }
380
+
381
+ if (!this.scope.isInheritedFrom(A_Context.scope(this))) {
382
+ this.scope.inherit(A_Context.scope(this));
383
+ }
384
+ }
385
+
327
386
  }
@@ -3,4 +3,6 @@ import { A_Error } from "@adaas/a-concept";
3
3
 
4
4
  export class A_CommandError extends A_Error {
5
5
 
6
+
7
+ static readonly CommandScopeBindingError = 'A-Command Scope Binding Error';
6
8
  }
@@ -15,11 +15,12 @@ export type A_TYPES__Command_Constructor<T = A_Command> = new (...args: any[]) =
15
15
  /**
16
16
  * Command initialization type
17
17
  */
18
- export type A_TYPES__Command_Init = any;
18
+ export type A_TYPES__Command_Init = Record<string, any>;
19
19
  /**
20
20
  * Command serialized type
21
21
  */
22
22
  export type A_TYPES__Command_Serialized<
23
+ ParamsType extends Record<string, any> = Record<string, any>,
23
24
  ResultType extends Record<string, any> = Record<string, any>
24
25
  > = {
25
26
  /**
@@ -30,6 +31,10 @@ export type A_TYPES__Command_Serialized<
30
31
  * Current status of the command
31
32
  */
32
33
  status: A_CONSTANTS__A_Command_Status;
34
+ /**
35
+ * Parameters used to invoke the command
36
+ */
37
+ params: ParamsType;
33
38
  // --------------------------------------------------
34
39
  /**
35
40
  * The time when the command was created