@adaas/a-utils 0.1.11 → 0.1.12
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/README.md +87 -32
- package/dist/index.d.mts +25 -6
- package/dist/index.d.ts +25 -6
- package/dist/index.js +33 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +33 -7
- package/dist/index.mjs.map +1 -1
- package/examples/command-examples.ts +268 -0
- package/package.json +1 -1
- package/src/lib/A-Command/A-Command.constants.ts +4 -0
- package/src/lib/A-Command/A-Command.entity.ts +31 -13
- package/src/lib/A-Command/A-Command.types.ts +6 -1
- package/src/lib/A-Command/README.md +645 -0
- package/src/lib/A-Memory/A-Memory.context.ts +15 -0
- package/tests/A-Command.test.ts +447 -2
- package/tests/A-Memory.test.ts +189 -0
|
@@ -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.
|
|
3
|
+
"version": "0.1.12",
|
|
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',
|
|
@@ -14,8 +14,8 @@ import { A_Memory } from "../A-Memory/A-Memory.context";
|
|
|
14
14
|
export class A_Command<
|
|
15
15
|
InvokeType extends A_TYPES__Command_Init = A_TYPES__Command_Init,
|
|
16
16
|
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>> {
|
|
17
|
+
LifecycleEvents extends string | A_CONSTANTS__A_Command_Event = A_CONSTANTS__A_Command_Event
|
|
18
|
+
> extends A_Entity<InvokeType, A_TYPES__Command_Serialized<InvokeType, ResultType>> {
|
|
19
19
|
|
|
20
20
|
// ====================================================================
|
|
21
21
|
// ================== Static A-Command Information ====================
|
|
@@ -136,7 +136,7 @@ export class A_Command<
|
|
|
136
136
|
/**
|
|
137
137
|
* Command invocation parameters
|
|
138
138
|
*/
|
|
139
|
-
params: InvokeType | A_TYPES__Command_Serialized<ResultType> | string
|
|
139
|
+
params: InvokeType | A_TYPES__Command_Serialized<InvokeType, ResultType> | string
|
|
140
140
|
) {
|
|
141
141
|
super(params as any)
|
|
142
142
|
}
|
|
@@ -148,21 +148,32 @@ export class A_Command<
|
|
|
148
148
|
|
|
149
149
|
// should create a new Task in DB with basic records
|
|
150
150
|
async init(): Promise<void> {
|
|
151
|
-
|
|
151
|
+
// first check statuis if it passed then - skip
|
|
152
|
+
if (this._status !== A_CONSTANTS__A_Command_Status.CREATED) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
this._status = A_CONSTANTS__A_Command_Status.INITIALIZATION;
|
|
152
157
|
this._startTime = new Date();
|
|
153
158
|
if (!this.scope.isInheritedFrom(A_Context.scope(this))) {
|
|
154
159
|
this.scope.inherit(A_Context.scope(this));
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
|
|
158
162
|
this.emit('init');
|
|
159
|
-
|
|
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._status = A_CONSTANTS__A_Command_Status.COMPILATION;
|
|
164
174
|
this.emit('compile');
|
|
165
|
-
|
|
175
|
+
await this.call('compile', this.scope);
|
|
176
|
+
this._status = A_CONSTANTS__A_Command_Status.COMPILED;
|
|
166
177
|
}
|
|
167
178
|
|
|
168
179
|
/**
|
|
@@ -172,8 +183,11 @@ export class A_Command<
|
|
|
172
183
|
try {
|
|
173
184
|
await this.init();
|
|
174
185
|
await this.compile();
|
|
175
|
-
|
|
176
|
-
|
|
186
|
+
|
|
187
|
+
if (this._status === A_CONSTANTS__A_Command_Status.COMPILED) {
|
|
188
|
+
this.emit('execute');
|
|
189
|
+
await this.call('execute', this.scope);
|
|
190
|
+
}
|
|
177
191
|
await this.complete();
|
|
178
192
|
|
|
179
193
|
} catch (error) {
|
|
@@ -265,7 +279,7 @@ export class A_Command<
|
|
|
265
279
|
|
|
266
280
|
this._params = newEntity;
|
|
267
281
|
|
|
268
|
-
this._status = A_CONSTANTS__A_Command_Status.
|
|
282
|
+
this._status = A_CONSTANTS__A_Command_Status.CREATED;
|
|
269
283
|
}
|
|
270
284
|
|
|
271
285
|
|
|
@@ -277,7 +291,7 @@ export class A_Command<
|
|
|
277
291
|
*
|
|
278
292
|
* @param serialized
|
|
279
293
|
*/
|
|
280
|
-
fromJSON(serialized: A_TYPES__Command_Serialized<ResultType>): void {
|
|
294
|
+
fromJSON(serialized: A_TYPES__Command_Serialized<InvokeType, ResultType>): void {
|
|
281
295
|
super.fromJSON(serialized);
|
|
282
296
|
|
|
283
297
|
this._executionScope = new A_Scope();
|
|
@@ -303,7 +317,10 @@ export class A_Command<
|
|
|
303
317
|
});
|
|
304
318
|
}
|
|
305
319
|
|
|
306
|
-
this.
|
|
320
|
+
this._params = serialized.params
|
|
321
|
+
|
|
322
|
+
this._status = serialized.status || A_CONSTANTS__A_Command_Status.CREATED;
|
|
323
|
+
|
|
307
324
|
}
|
|
308
325
|
|
|
309
326
|
|
|
@@ -312,11 +329,12 @@ export class A_Command<
|
|
|
312
329
|
*
|
|
313
330
|
* @returns
|
|
314
331
|
*/
|
|
315
|
-
toJSON(): A_TYPES__Command_Serialized<ResultType> {
|
|
332
|
+
toJSON(): A_TYPES__Command_Serialized<InvokeType, ResultType> {
|
|
316
333
|
return {
|
|
317
334
|
...super.toJSON(),
|
|
318
335
|
code: this.code,
|
|
319
336
|
status: this._status,
|
|
337
|
+
params: this._params,
|
|
320
338
|
startedAt: this._startTime ? this._startTime.toISOString() : undefined,
|
|
321
339
|
endedAt: this._endTime ? this._endTime.toISOString() : undefined,
|
|
322
340
|
duration: this.duration,
|
|
@@ -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
|