@adaas/a-utils 0.1.17 → 0.1.19
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/dist/index.d.mts +964 -354
- package/dist/index.d.ts +964 -354
- package/dist/index.js +1426 -714
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1426 -714
- package/dist/index.mjs.map +1 -1
- package/examples/A-Channel-examples.ts +13 -11
- package/examples/A-Command-examples-2.ts +429 -0
- package/examples/A-Command-examples.ts +487 -202
- package/examples/A-StateMachine-examples.ts +609 -0
- package/package.json +3 -2
- package/src/index.ts +1 -2
- package/src/lib/A-Channel/A-Channel.component.ts +14 -74
- package/src/lib/A-Channel/A-Channel.error.ts +5 -5
- package/src/lib/A-Channel/A-Channel.types.ts +2 -10
- package/src/lib/A-Channel/A-ChannelRequest.context.ts +25 -74
- package/src/lib/A-Command/A-Command.constants.ts +78 -23
- package/src/lib/A-Command/A-Command.entity.ts +447 -119
- package/src/lib/A-Command/A-Command.error.ts +11 -0
- package/src/lib/A-Command/A-Command.types.ts +96 -20
- package/src/lib/A-Command/A-CommandExecution.context.ts +0 -0
- package/src/lib/A-Command/README.md +164 -68
- package/src/lib/A-Config/A-Config.container.ts +2 -2
- package/src/lib/A-Config/A-Config.context.ts +19 -5
- package/src/lib/A-Config/components/ConfigReader.component.ts +1 -1
- package/src/lib/A-Logger/A-Logger.component.ts +211 -35
- package/src/lib/A-Logger/A-Logger.constants.ts +50 -10
- package/src/lib/A-Logger/A-Logger.env.ts +17 -1
- package/src/lib/A-Memory/A-Memory.component.ts +440 -0
- package/src/lib/A-Memory/A-Memory.constants.ts +49 -0
- package/src/lib/A-Memory/A-Memory.context.ts +14 -118
- package/src/lib/A-Memory/A-Memory.error.ts +21 -0
- package/src/lib/A-Memory/A-Memory.types.ts +21 -0
- package/src/lib/A-Operation/A-Operation.context.ts +58 -0
- package/src/lib/A-Operation/A-Operation.types.ts +47 -0
- package/src/lib/A-StateMachine/A-StateMachine.component.ts +258 -0
- package/src/lib/A-StateMachine/A-StateMachine.constants.ts +18 -0
- package/src/lib/A-StateMachine/A-StateMachine.error.ts +10 -0
- package/src/lib/A-StateMachine/A-StateMachine.types.ts +20 -0
- package/src/lib/A-StateMachine/A-StateMachineTransition.context.ts +41 -0
- package/src/lib/A-StateMachine/README.md +391 -0
- package/tests/A-Channel.test.ts +17 -14
- package/tests/A-Command.test.ts +548 -460
- package/tests/A-Logger.test.ts +8 -4
- package/tests/A-Memory.test.ts +151 -115
- package/tests/A-Schedule.test.ts +2 -2
- package/tests/A-StateMachine.test.ts +760 -0
|
@@ -0,0 +1,609 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A_StateMachine Examples
|
|
3
|
+
*
|
|
4
|
+
* This file contains comprehensive examples demonstrating various use cases
|
|
5
|
+
* for the A_StateMachine component including:
|
|
6
|
+
*
|
|
7
|
+
* 1. Basic State Machine (Traffic Light)
|
|
8
|
+
* 2. Business Workflow (Order Processing)
|
|
9
|
+
* 3. User Authentication Flow
|
|
10
|
+
* 4. Document Approval Workflow
|
|
11
|
+
* 5. Error Handling and Recovery
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { A_StateMachine } from '../src/lib/A-StateMachine/A-StateMachine.component';
|
|
15
|
+
import { A_StateMachineFeatures } from '../src/lib/A-StateMachine/A-StateMachine.constants';
|
|
16
|
+
import { A_Feature, A_Scope, A_Component, A_Context, A_Inject } from '@adaas/a-concept';
|
|
17
|
+
import { A_OperationContext } from '../src/lib/A-Operation/A-Operation.context';
|
|
18
|
+
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// EXAMPLE 1: Basic Traffic Light State Machine
|
|
21
|
+
// =============================================================================
|
|
22
|
+
|
|
23
|
+
interface TrafficLightStates {
|
|
24
|
+
red: { duration: number; timestamp: Date; };
|
|
25
|
+
yellow: { duration: number; fromState: 'red' | 'green'; timestamp: Date; };
|
|
26
|
+
green: { duration: number; timestamp: Date; };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class TrafficLightMachine extends A_StateMachine<TrafficLightStates> {
|
|
30
|
+
private currentState: keyof TrafficLightStates = 'red';
|
|
31
|
+
|
|
32
|
+
@A_Feature.Extend()
|
|
33
|
+
async [A_StateMachineFeatures.onInitialize](): Promise<void> {
|
|
34
|
+
console.log('🚦 Traffic Light System Initialized');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@A_Feature.Extend()
|
|
38
|
+
async [A_StateMachineFeatures.onBeforeTransition](
|
|
39
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
40
|
+
): Promise<void> {
|
|
41
|
+
const { from, to } = operation.params;
|
|
42
|
+
console.log(`🔄 Light changing: ${String(from).toUpperCase()} → ${String(to).toUpperCase()}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Custom transition with validation
|
|
46
|
+
@A_Feature.Extend()
|
|
47
|
+
async red_green(
|
|
48
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
const { duration } = operation.params.props;
|
|
51
|
+
|
|
52
|
+
if (duration < 30000) {
|
|
53
|
+
throw new Error('Green light must be at least 30 seconds for safety');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log('🟢 GREEN: Traffic may proceed');
|
|
57
|
+
operation.succeed({ safetyChecked: true });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getCurrentState(): keyof TrafficLightStates {
|
|
61
|
+
return this.currentState;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// =============================================================================
|
|
66
|
+
// EXAMPLE 2: E-commerce Order Processing Workflow
|
|
67
|
+
// =============================================================================
|
|
68
|
+
|
|
69
|
+
interface OrderStates {
|
|
70
|
+
pending: { orderId: string; customerId: string; amount: number; };
|
|
71
|
+
validated: { orderId: string; customerId: string; amount: number; validatedAt: Date; };
|
|
72
|
+
paid: { orderId: string; customerId: string; amount: number; transactionId: string; };
|
|
73
|
+
shipped: { orderId: string; customerId: string; amount: number; trackingId: string; };
|
|
74
|
+
delivered: { orderId: string; customerId: string; amount: number; deliveredAt: Date; };
|
|
75
|
+
cancelled: { orderId: string; customerId: string; amount: number; reason: string; };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class OrderProcessingMachine extends A_StateMachine<OrderStates> {
|
|
79
|
+
private currentState: keyof OrderStates = 'pending';
|
|
80
|
+
|
|
81
|
+
@A_Feature.Extend()
|
|
82
|
+
async [A_StateMachineFeatures.onAfterTransition](
|
|
83
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
84
|
+
): Promise<void> {
|
|
85
|
+
|
|
86
|
+
this.currentState = operation.params.to as keyof OrderStates;
|
|
87
|
+
console.log(`📦 Order now in ${String(this.currentState).toUpperCase()} state`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@A_Feature.Extend()
|
|
92
|
+
async pending_validated(
|
|
93
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
94
|
+
): Promise<void> {
|
|
95
|
+
const orderData = operation.params.props;
|
|
96
|
+
|
|
97
|
+
console.log('🔍 Validating order...');
|
|
98
|
+
// Simulate inventory check
|
|
99
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
100
|
+
|
|
101
|
+
operation.succeed({
|
|
102
|
+
...orderData,
|
|
103
|
+
validatedAt: new Date()
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@A_Feature.Extend()
|
|
109
|
+
async validated_paid(
|
|
110
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
111
|
+
): Promise<void> {
|
|
112
|
+
const orderData = operation.params.props;
|
|
113
|
+
|
|
114
|
+
console.log('💳 Processing payment...');
|
|
115
|
+
// Simulate payment processing
|
|
116
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
117
|
+
|
|
118
|
+
operation.succeed({
|
|
119
|
+
...orderData,
|
|
120
|
+
transactionId: `txn_${Date.now()}`
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@A_Feature.Extend()
|
|
125
|
+
async paid_shipped(
|
|
126
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
127
|
+
): Promise<void> {
|
|
128
|
+
const orderData = operation.params.props;
|
|
129
|
+
|
|
130
|
+
console.log('📮 Creating shipment...');
|
|
131
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
132
|
+
|
|
133
|
+
operation.succeed({
|
|
134
|
+
...orderData,
|
|
135
|
+
trackingId: `TRK${Math.random().toString(36).substr(2, 9).toUpperCase()}`
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
getCurrentState(): keyof OrderStates {
|
|
140
|
+
return this.currentState;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// =============================================================================
|
|
145
|
+
// EXAMPLE 3: User Authentication Flow
|
|
146
|
+
// =============================================================================
|
|
147
|
+
|
|
148
|
+
interface AuthStates {
|
|
149
|
+
anonymous: { sessionId: string; };
|
|
150
|
+
authenticating: { sessionId: string; username: string; };
|
|
151
|
+
authenticated: { sessionId: string; userId: string; username: string; loginTime: Date; };
|
|
152
|
+
mfa_required: { sessionId: string; userId: string; username: string; mfaChallenge: string; };
|
|
153
|
+
mfa_verified: { sessionId: string; userId: string; username: string; loginTime: Date; mfaVerified: boolean; };
|
|
154
|
+
locked: { sessionId: string; reason: string; lockedAt: Date; };
|
|
155
|
+
logged_out: { sessionId: string; logoutTime: Date; };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
class AuthenticationMachine extends A_StateMachine<AuthStates> {
|
|
159
|
+
private attempts = 0;
|
|
160
|
+
private maxAttempts = 3;
|
|
161
|
+
|
|
162
|
+
@A_Feature.Extend()
|
|
163
|
+
async [A_StateMachineFeatures.onError](): Promise<void> {
|
|
164
|
+
this.attempts++;
|
|
165
|
+
console.log(`❌ Authentication attempt ${this.attempts}/${this.maxAttempts} failed`);
|
|
166
|
+
|
|
167
|
+
if (this.attempts >= this.maxAttempts) {
|
|
168
|
+
console.log('🔒 Account will be locked due to too many failed attempts');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@A_Feature.Extend()
|
|
173
|
+
async anonymous_authenticating(
|
|
174
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
175
|
+
): Promise<void> {
|
|
176
|
+
const { username } = operation.params.props;
|
|
177
|
+
|
|
178
|
+
console.log(`🔐 Starting authentication for user: ${username}`);
|
|
179
|
+
|
|
180
|
+
operation.succeed({
|
|
181
|
+
sessionId: operation.params.props.sessionId,
|
|
182
|
+
username
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@A_Feature.Extend()
|
|
187
|
+
async authenticating_authenticated(
|
|
188
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
189
|
+
): Promise<void> {
|
|
190
|
+
const { sessionId, username } = operation.params.props;
|
|
191
|
+
|
|
192
|
+
console.log('✅ Basic authentication successful');
|
|
193
|
+
// Reset attempts on successful auth
|
|
194
|
+
this.attempts = 0;
|
|
195
|
+
|
|
196
|
+
operation.succeed({
|
|
197
|
+
sessionId,
|
|
198
|
+
userId: `user_${Date.now()}`,
|
|
199
|
+
username,
|
|
200
|
+
loginTime: new Date()
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@A_Feature.Extend()
|
|
205
|
+
async authenticated_mfa_required(
|
|
206
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
207
|
+
): Promise<void> {
|
|
208
|
+
const authData = operation.params.props;
|
|
209
|
+
|
|
210
|
+
console.log('🔢 Multi-factor authentication required');
|
|
211
|
+
|
|
212
|
+
operation.succeed({
|
|
213
|
+
...authData,
|
|
214
|
+
mfaChallenge: `MFA_${Math.random().toString(36).substr(2, 8)}`
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@A_Feature.Extend()
|
|
219
|
+
async mfa_required_mfa_verified(
|
|
220
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
221
|
+
): Promise<void> {
|
|
222
|
+
const authData = operation.params.props;
|
|
223
|
+
|
|
224
|
+
console.log('🔐 MFA verification successful');
|
|
225
|
+
|
|
226
|
+
operation.succeed({
|
|
227
|
+
...authData,
|
|
228
|
+
loginTime: new Date(),
|
|
229
|
+
mfaVerified: true
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@A_Feature.Extend()
|
|
234
|
+
async authenticating_locked(
|
|
235
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
236
|
+
): Promise<void> {
|
|
237
|
+
console.log('🔒 Account locked due to failed attempts');
|
|
238
|
+
|
|
239
|
+
operation.succeed({
|
|
240
|
+
sessionId: operation.params.props.sessionId,
|
|
241
|
+
reason: 'Too many failed login attempts',
|
|
242
|
+
lockedAt: new Date()
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// =============================================================================
|
|
248
|
+
// EXAMPLE 4: Document Approval Workflow
|
|
249
|
+
// =============================================================================
|
|
250
|
+
|
|
251
|
+
interface DocumentStates {
|
|
252
|
+
draft: { docId: string; authorId: string; content: string; };
|
|
253
|
+
review: { docId: string; authorId: string; content: string; reviewerId: string; reviewStarted: Date; };
|
|
254
|
+
approved: { docId: string; authorId: string; content: string; approvedBy: string; approvedAt: Date; };
|
|
255
|
+
rejected: { docId: string; authorId: string; content: string; rejectedBy: string; rejectedAt: Date; feedback: string; };
|
|
256
|
+
published: { docId: string; authorId: string; content: string; publishedAt: Date; version: number; };
|
|
257
|
+
archived: { docId: string; authorId: string; content: string; archivedAt: Date; reason: string; };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
class DocumentWorkflowMachine extends A_StateMachine<DocumentStates> {
|
|
261
|
+
|
|
262
|
+
@A_Feature.Extend()
|
|
263
|
+
async [A_StateMachineFeatures.onBeforeTransition](
|
|
264
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
265
|
+
): Promise<void> {
|
|
266
|
+
const { from, to, props } = operation.params;
|
|
267
|
+
|
|
268
|
+
// Business rule validation
|
|
269
|
+
if (to === 'published' && from !== 'approved') {
|
|
270
|
+
throw new Error('Documents can only be published after approval');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (to === 'review' && (!props?.content || props.content.trim().length < 10)) {
|
|
274
|
+
throw new Error('Document must have at least 10 characters to submit for review');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
console.log(`📄 Document ${props?.docId}: ${String(from)} → ${String(to)}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
@A_Feature.Extend()
|
|
281
|
+
async draft_review(
|
|
282
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
283
|
+
): Promise<void> {
|
|
284
|
+
const docData = operation.params.props;
|
|
285
|
+
|
|
286
|
+
console.log('📋 Submitting document for review...');
|
|
287
|
+
|
|
288
|
+
// Auto-assign reviewer (in real app, would be based on business logic)
|
|
289
|
+
const reviewerId = this.assignReviewer(docData.authorId);
|
|
290
|
+
|
|
291
|
+
operation.succeed({
|
|
292
|
+
...docData,
|
|
293
|
+
reviewerId,
|
|
294
|
+
reviewStarted: new Date()
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@A_Feature.Extend()
|
|
299
|
+
async review_approved(
|
|
300
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
301
|
+
): Promise<void> {
|
|
302
|
+
const docData = operation.params.props;
|
|
303
|
+
|
|
304
|
+
console.log('✅ Document approved');
|
|
305
|
+
|
|
306
|
+
operation.succeed({
|
|
307
|
+
docId: docData.docId,
|
|
308
|
+
authorId: docData.authorId,
|
|
309
|
+
content: docData.content,
|
|
310
|
+
approvedBy: docData.reviewerId,
|
|
311
|
+
approvedAt: new Date()
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
@A_Feature.Extend()
|
|
316
|
+
async review_rejected(
|
|
317
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
318
|
+
): Promise<void> {
|
|
319
|
+
const docData = operation.params.props;
|
|
320
|
+
|
|
321
|
+
console.log('❌ Document rejected');
|
|
322
|
+
|
|
323
|
+
operation.succeed({
|
|
324
|
+
docId: docData.docId,
|
|
325
|
+
authorId: docData.authorId,
|
|
326
|
+
content: docData.content,
|
|
327
|
+
rejectedBy: docData.reviewerId,
|
|
328
|
+
rejectedAt: new Date(),
|
|
329
|
+
feedback: 'Please revise and resubmit'
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
@A_Feature.Extend()
|
|
334
|
+
async approved_published(
|
|
335
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
336
|
+
): Promise<void> {
|
|
337
|
+
const docData = operation.params.props;
|
|
338
|
+
|
|
339
|
+
console.log('🚀 Publishing document...');
|
|
340
|
+
|
|
341
|
+
operation.succeed({
|
|
342
|
+
docId: docData.docId,
|
|
343
|
+
authorId: docData.authorId,
|
|
344
|
+
content: docData.content,
|
|
345
|
+
publishedAt: new Date(),
|
|
346
|
+
version: 1
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
private assignReviewer(authorId: string): string {
|
|
351
|
+
const reviewers = ['reviewer1', 'reviewer2', 'reviewer3'];
|
|
352
|
+
return reviewers[authorId.length % reviewers.length];
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// =============================================================================
|
|
357
|
+
// EXAMPLE 5: External Component for Cross-Cutting Concerns
|
|
358
|
+
// =============================================================================
|
|
359
|
+
|
|
360
|
+
class StateMachineLogger extends A_Component {
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@A_Feature.Extend({ scope: [TrafficLightMachine, OrderProcessingMachine, AuthenticationMachine, DocumentWorkflowMachine] })
|
|
364
|
+
async [A_StateMachineFeatures.onAfterTransition](
|
|
365
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
366
|
+
): Promise<void> {
|
|
367
|
+
const { from, to, props } = operation.params;
|
|
368
|
+
|
|
369
|
+
// Log all state transitions for audit purposes
|
|
370
|
+
const logEntry = {
|
|
371
|
+
timestamp: new Date().toISOString(),
|
|
372
|
+
transition: `${String(from)} → ${String(to)}`,
|
|
373
|
+
entityId: props?.orderId || props?.docId || props?.sessionId || 'unknown',
|
|
374
|
+
success: true
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
console.log(`📊 [AUDIT LOG] ${JSON.stringify(logEntry)}`);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
@A_Feature.Extend({ scope: [TrafficLightMachine, OrderProcessingMachine, AuthenticationMachine, DocumentWorkflowMachine] })
|
|
381
|
+
async [A_StateMachineFeatures.onError](
|
|
382
|
+
@A_Inject(A_OperationContext) operation: A_OperationContext
|
|
383
|
+
): Promise<void> {
|
|
384
|
+
const { from, to, props } = operation.params;
|
|
385
|
+
|
|
386
|
+
const errorLog = {
|
|
387
|
+
timestamp: new Date().toISOString(),
|
|
388
|
+
transition: `${String(from)} → ${String(to)}`,
|
|
389
|
+
entityId: props?.orderId || props?.docId || props?.sessionId || 'unknown',
|
|
390
|
+
success: false,
|
|
391
|
+
error: 'Transition failed'
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
console.log(`📊 [ERROR LOG] ${JSON.stringify(errorLog)}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// =============================================================================
|
|
399
|
+
// EXAMPLE RUNNER FUNCTIONS
|
|
400
|
+
// =============================================================================
|
|
401
|
+
|
|
402
|
+
async function runTrafficLightExample(): Promise<void> {
|
|
403
|
+
console.log('🚦 === Traffic Light Example ===\n');
|
|
404
|
+
|
|
405
|
+
const trafficLight = new TrafficLightMachine();
|
|
406
|
+
await trafficLight.ready;
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
await trafficLight.transition('red', 'green', {
|
|
410
|
+
duration: 30000,
|
|
411
|
+
timestamp: new Date()
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
await trafficLight.transition('green', 'yellow', {
|
|
415
|
+
duration: 5000,
|
|
416
|
+
fromState: 'green',
|
|
417
|
+
timestamp: new Date()
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
await trafficLight.transition('yellow', 'red', {
|
|
421
|
+
duration: 60000,
|
|
422
|
+
timestamp: new Date()
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
console.log(`✅ Traffic light cycle completed. Current state: ${trafficLight.getCurrentState()}\n`);
|
|
426
|
+
|
|
427
|
+
} catch (error) {
|
|
428
|
+
console.error('❌ Traffic light error:', (error as Error).message);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
async function runOrderProcessingExample(): Promise<void> {
|
|
433
|
+
console.log('📦 === Order Processing Example ===\n');
|
|
434
|
+
|
|
435
|
+
const orderMachine = new OrderProcessingMachine();
|
|
436
|
+
await orderMachine.ready;
|
|
437
|
+
|
|
438
|
+
const orderData = {
|
|
439
|
+
orderId: 'ORD-001',
|
|
440
|
+
customerId: 'CUST-123',
|
|
441
|
+
amount: 99.99
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
await orderMachine.transition('pending', 'validated', orderData);
|
|
446
|
+
await orderMachine.transition('validated', 'paid', {
|
|
447
|
+
...orderData,
|
|
448
|
+
validatedAt: new Date()
|
|
449
|
+
});
|
|
450
|
+
await orderMachine.transition('paid', 'shipped', {
|
|
451
|
+
...orderData,
|
|
452
|
+
transactionId: 'txn_123'
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
console.log(`✅ Order processed successfully. Final state: ${orderMachine.getCurrentState()}\n`);
|
|
456
|
+
|
|
457
|
+
} catch (error) {
|
|
458
|
+
console.error('❌ Order processing error:', (error as Error).message);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async function runAuthenticationExample(): Promise<void> {
|
|
463
|
+
console.log('🔐 === Authentication Flow Example ===\n');
|
|
464
|
+
|
|
465
|
+
const authMachine = new AuthenticationMachine();
|
|
466
|
+
await authMachine.ready;
|
|
467
|
+
|
|
468
|
+
const sessionData = {
|
|
469
|
+
sessionId: 'sess_' + Date.now()
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
try {
|
|
473
|
+
// Successful authentication flow
|
|
474
|
+
await authMachine.transition('anonymous', 'authenticating', {
|
|
475
|
+
...sessionData,
|
|
476
|
+
username: 'john.doe'
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
await authMachine.transition('authenticating', 'authenticated', {
|
|
480
|
+
...sessionData,
|
|
481
|
+
username: 'john.doe'
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
await authMachine.transition('authenticated', 'mfa_required', {
|
|
485
|
+
sessionId: sessionData.sessionId,
|
|
486
|
+
userId: 'user_123',
|
|
487
|
+
username: 'john.doe',
|
|
488
|
+
loginTime: new Date()
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
await authMachine.transition('mfa_required', 'mfa_verified', {
|
|
492
|
+
sessionId: sessionData.sessionId,
|
|
493
|
+
userId: 'user_123',
|
|
494
|
+
username: 'john.doe',
|
|
495
|
+
mfaChallenge: 'MFA_12345'
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
console.log('✅ Authentication flow completed with MFA\n');
|
|
499
|
+
|
|
500
|
+
} catch (error) {
|
|
501
|
+
console.error('❌ Authentication error:', (error as Error).message);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
async function runDocumentWorkflowExample(): Promise<void> {
|
|
506
|
+
console.log('📄 === Document Workflow Example ===\n');
|
|
507
|
+
|
|
508
|
+
const docMachine = new DocumentWorkflowMachine();
|
|
509
|
+
await docMachine.ready;
|
|
510
|
+
|
|
511
|
+
const docData = {
|
|
512
|
+
docId: 'DOC-001',
|
|
513
|
+
authorId: 'author1',
|
|
514
|
+
content: 'This is a comprehensive document that needs review and approval before publication.'
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
try {
|
|
518
|
+
await docMachine.transition('draft', 'review', docData);
|
|
519
|
+
|
|
520
|
+
await docMachine.transition('review', 'approved', {
|
|
521
|
+
...docData,
|
|
522
|
+
reviewerId: 'reviewer1',
|
|
523
|
+
reviewStarted: new Date()
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
await docMachine.transition('approved', 'published', {
|
|
527
|
+
docId: docData.docId,
|
|
528
|
+
authorId: docData.authorId,
|
|
529
|
+
content: docData.content,
|
|
530
|
+
approvedBy: 'reviewer1',
|
|
531
|
+
approvedAt: new Date()
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
console.log('✅ Document successfully published\n');
|
|
535
|
+
|
|
536
|
+
} catch (error) {
|
|
537
|
+
console.error('❌ Document workflow error:', (error as Error).message);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
async function runErrorHandlingExample(): Promise<void> {
|
|
542
|
+
console.log('⚠️ === Error Handling Example ===\n');
|
|
543
|
+
|
|
544
|
+
const docMachine = new DocumentWorkflowMachine();
|
|
545
|
+
await docMachine.ready;
|
|
546
|
+
|
|
547
|
+
try {
|
|
548
|
+
// Try to submit document with insufficient content
|
|
549
|
+
await docMachine.transition('draft', 'review', {
|
|
550
|
+
docId: 'DOC-002',
|
|
551
|
+
authorId: 'author2',
|
|
552
|
+
content: 'Too short' // This will fail validation
|
|
553
|
+
});
|
|
554
|
+
} catch (error) {
|
|
555
|
+
console.log('❌ Expected validation error:', (error as Error).message);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
try {
|
|
559
|
+
// Try invalid transition
|
|
560
|
+
await docMachine.transition('draft', 'published', {
|
|
561
|
+
docId: 'DOC-003',
|
|
562
|
+
authorId: 'author3',
|
|
563
|
+
content: 'Cannot publish directly from draft'
|
|
564
|
+
});
|
|
565
|
+
} catch (error) {
|
|
566
|
+
console.log('❌ Expected business rule error:', (error as Error).message);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
console.log('✅ Error handling examples completed\n');
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// =============================================================================
|
|
573
|
+
// MAIN EXAMPLE RUNNER
|
|
574
|
+
// =============================================================================
|
|
575
|
+
|
|
576
|
+
async function runAllExamples(): Promise<void> {
|
|
577
|
+
console.log('🎯 === A_StateMachine Comprehensive Examples ===\n');
|
|
578
|
+
|
|
579
|
+
// Register the logger component for cross-cutting concerns
|
|
580
|
+
A_Context.root.register(StateMachineLogger);
|
|
581
|
+
|
|
582
|
+
await runTrafficLightExample();
|
|
583
|
+
await runOrderProcessingExample();
|
|
584
|
+
await runAuthenticationExample();
|
|
585
|
+
await runDocumentWorkflowExample();
|
|
586
|
+
await runErrorHandlingExample();
|
|
587
|
+
|
|
588
|
+
console.log('🎉 All examples completed successfully!');
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Export everything for use in tests or other modules
|
|
592
|
+
export {
|
|
593
|
+
TrafficLightMachine,
|
|
594
|
+
OrderProcessingMachine,
|
|
595
|
+
AuthenticationMachine,
|
|
596
|
+
DocumentWorkflowMachine,
|
|
597
|
+
StateMachineLogger,
|
|
598
|
+
runAllExamples,
|
|
599
|
+
runTrafficLightExample,
|
|
600
|
+
runOrderProcessingExample,
|
|
601
|
+
runAuthenticationExample,
|
|
602
|
+
runDocumentWorkflowExample,
|
|
603
|
+
runErrorHandlingExample
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
// Run examples if this file is executed directly
|
|
607
|
+
if (require.main === module) {
|
|
608
|
+
runAllExamples().catch(console.error);
|
|
609
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaas/a-utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
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",
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"start": "nodemon ./tests/log.ts",
|
|
72
72
|
"examples:config": "nodemon ./examples/config.ts",
|
|
73
73
|
"examples:logger": "nodemon ./examples/A-Logger-examples.ts",
|
|
74
|
+
"examples:command": "nodemon ./examples/A-Command-examples.ts",
|
|
74
75
|
"release": "npm run test && npm run build && git add . && git commit -m \"new version created :: $(cat package.json | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g')\" && npm version patch && npm publish --access public",
|
|
75
76
|
"preversion": "echo test",
|
|
76
77
|
"version": "echo git add .",
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
"build": "tsup --config tsup.config.ts"
|
|
80
81
|
},
|
|
81
82
|
"dependencies": {
|
|
82
|
-
"@adaas/a-concept": "^0.1.
|
|
83
|
+
"@adaas/a-concept": "^0.1.44"
|
|
83
84
|
},
|
|
84
85
|
"devDependencies": {
|
|
85
86
|
"@types/chai": "^4.3.14",
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// A-Channel Components
|
|
4
4
|
// ============================================================================
|
|
5
5
|
export { A_Channel } from './lib/A-Channel/A-Channel.component';
|
|
6
|
-
export { A_ChannelRequest } from './lib/A-Channel/A-ChannelRequest.context';
|
|
7
6
|
export { A_ChannelError } from './lib/A-Channel/A-Channel.error';
|
|
8
7
|
export * from './lib/A-Channel/A-Channel.types';
|
|
9
8
|
export * from './lib/A-Channel/A-Channel.constants';
|
|
@@ -50,7 +49,7 @@ export * from './lib/A-Manifest/A-Manifest.types';
|
|
|
50
49
|
// ============================================================================
|
|
51
50
|
// A-Memory Components
|
|
52
51
|
// ============================================================================
|
|
53
|
-
export { A_Memory } from './lib/A-Memory/A-Memory.
|
|
52
|
+
export { A_Memory } from './lib/A-Memory/A-Memory.component';
|
|
54
53
|
|
|
55
54
|
|
|
56
55
|
// ============================================================================
|