@forgehive/task 0.1.13 → 0.2.1
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.ts +37 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +58 -13
- package/dist/index.js.map +1 -1
- package/dist/test/add-listener-with-boundaries.test.js +186 -181
- package/dist/test/add-listener-with-boundaries.test.js.map +1 -1
- package/dist/test/add-listener.test.js +80 -52
- package/dist/test/add-listener.test.js.map +1 -1
- package/dist/test/safe-replay-complex-boundary.test.js +36 -27
- package/dist/test/safe-replay-complex-boundary.test.js.map +1 -1
- package/dist/test/safe-replay.test.js +23 -14
- package/dist/test/safe-replay.test.js.map +1 -1
- package/dist/test/safe-run.test.js +41 -16
- package/dist/test/safe-run.test.js.map +1 -1
- package/dist/test/task-boundary-mocking.test.js +17 -7
- package/dist/test/task-boundary-mocking.test.js.map +1 -1
- package/dist/test/task-execution-log.test.d.ts +2 -0
- package/dist/test/task-execution-log.test.d.ts.map +1 -0
- package/dist/test/task-execution-log.test.js +207 -0
- package/dist/test/task-execution-log.test.js.map +1 -0
- package/dist/test/task-with-boundaries.test.js +56 -24
- package/dist/test/task-with-boundaries.test.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +109 -40
- package/src/test/add-listener-with-boundaries.test.ts +202 -252
- package/src/test/add-listener.test.ts +90 -64
- package/src/test/safe-replay-complex-boundary.test.ts +18 -10
- package/src/test/safe-replay.test.ts +21 -12
- package/src/test/safe-run.test.ts +20 -15
- package/src/test/task-boundary-mocking.test.ts +8 -6
- package/src/test/task-execution-log.test.ts +246 -0
- package/src/test/task-with-boundaries.test.ts +45 -44
package/src/index.ts
CHANGED
|
@@ -35,6 +35,8 @@ export type {
|
|
|
35
35
|
export { Schema }
|
|
36
36
|
|
|
37
37
|
export interface TaskConfig<B extends Boundaries = Boundaries> {
|
|
38
|
+
name?: string
|
|
39
|
+
description?: string
|
|
38
40
|
schema?: Schema<Record<string, SchemaType>>
|
|
39
41
|
mode?: Mode
|
|
40
42
|
boundaries?: B
|
|
@@ -49,19 +51,7 @@ export interface ReplayConfig<B extends Boundaries = Boundaries> {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
// ToDo: Add a type for the boundaries data
|
|
52
|
-
|
|
53
|
-
* Represents the record passed to task listeners
|
|
54
|
-
*/
|
|
55
|
-
export interface TaskRecord<InputType = unknown, OutputType = unknown> {
|
|
56
|
-
/** The input arguments passed to the task */
|
|
57
|
-
input: InputType;
|
|
58
|
-
/** The output returned by the task (if successful) */
|
|
59
|
-
output?: OutputType | null;
|
|
60
|
-
/** The error message if the task failed */
|
|
61
|
-
error?: string;
|
|
62
|
-
/** Boundary execution data */
|
|
63
|
-
boundaries?: Record<string, unknown>;
|
|
64
|
-
}
|
|
54
|
+
|
|
65
55
|
|
|
66
56
|
// Make BoundaryLog generic
|
|
67
57
|
export type BoundaryLog<I extends unknown[] = unknown[], O = unknown> = BoundaryRecord<I, O>;
|
|
@@ -85,11 +75,19 @@ export interface ExecutionRecord<InputType = unknown, OutputType = unknown, B ex
|
|
|
85
75
|
error?: string
|
|
86
76
|
/** Boundary execution data */
|
|
87
77
|
boundaries: BoundaryLogsFor<B>
|
|
78
|
+
/** The name of the task (if set) */
|
|
79
|
+
taskName?: string
|
|
80
|
+
/** Additional context metadata */
|
|
81
|
+
metadata?: Record<string, string>
|
|
82
|
+
/** The type of execution record - computed from output/error state */
|
|
83
|
+
type: 'success' | 'error' | 'pending'
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
export interface TaskInstanceType<Func extends BaseFunction = BaseFunction, B extends Boundaries = Boundaries> {
|
|
91
87
|
version: string
|
|
92
88
|
|
|
89
|
+
getName: () => string | undefined
|
|
90
|
+
setName: (name: string) => void
|
|
93
91
|
getMode: () => Mode
|
|
94
92
|
setMode: (mode: Mode) => void
|
|
95
93
|
setSchema: (base: Schema<Record<string, SchemaType>>) => void
|
|
@@ -103,9 +101,9 @@ export interface TaskInstanceType<Func extends BaseFunction = BaseFunction, B ex
|
|
|
103
101
|
isValid: <T extends Record<string, unknown> = Parameters<Func>[0]>(argv?: T) => boolean
|
|
104
102
|
|
|
105
103
|
// Listener methods
|
|
106
|
-
addListener: <I = Parameters<Func>[0], O = ReturnType<Func>>(fn: (record:
|
|
104
|
+
addListener: <I = Parameters<Func>[0], O = ReturnType<Func>>(fn: (record: ExecutionRecord<I, O, B>) => void) => void
|
|
107
105
|
removeListener: () => void
|
|
108
|
-
emit: (data:
|
|
106
|
+
emit: (data: ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B>) => void
|
|
109
107
|
|
|
110
108
|
// Boundary methods
|
|
111
109
|
asBoundary: () => (args: Parameters<Func>[0]) => Promise<ReturnType<Func>>
|
|
@@ -119,7 +117,7 @@ export interface TaskInstanceType<Func extends BaseFunction = BaseFunction, B ex
|
|
|
119
117
|
resetMocks: () => void
|
|
120
118
|
|
|
121
119
|
run: (argv?: Parameters<Func>[0]) => Promise<ReturnType<Func>>
|
|
122
|
-
safeRun: (argv?: Parameters<Func>[0]) => Promise<[Awaited<ReturnType<Func>> | null, Error | null, ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B>]>
|
|
120
|
+
safeRun: (argv?: Parameters<Func>[0], context?: Record<string, string>) => Promise<[Awaited<ReturnType<Func>> | null, Error | null, ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B>]>
|
|
123
121
|
|
|
124
122
|
// Method for replaying task execution
|
|
125
123
|
safeReplay: (
|
|
@@ -146,6 +144,21 @@ export type TaskFunction<S, B extends Boundaries> =
|
|
|
146
144
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
147
145
|
(argv: InferSchemaType<S>, boundaries: WrappedBoundaries<B>) => Promise<any>;
|
|
148
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Utility function to compute the execution record type based on output and error state
|
|
149
|
+
*/
|
|
150
|
+
export function getExecutionRecordType<InputType = unknown, OutputType = unknown, B extends Boundaries = Boundaries>(
|
|
151
|
+
record: Omit<ExecutionRecord<InputType, OutputType, B>, 'type'>
|
|
152
|
+
): 'success' | 'error' | 'pending' {
|
|
153
|
+
if (record.error !== undefined && record.error !== null) {
|
|
154
|
+
return 'error'
|
|
155
|
+
}
|
|
156
|
+
if (record.output !== undefined && record.output !== null) {
|
|
157
|
+
return 'success'
|
|
158
|
+
}
|
|
159
|
+
return 'pending'
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
export const Task = class Task<
|
|
150
163
|
B extends Boundaries = Boundaries,
|
|
151
164
|
Func extends BaseFunction = BaseFunction
|
|
@@ -155,6 +168,7 @@ export const Task = class Task<
|
|
|
155
168
|
_fn: Func
|
|
156
169
|
_mode: Mode
|
|
157
170
|
_coolDown: number
|
|
171
|
+
_name?: string
|
|
158
172
|
_description?: string
|
|
159
173
|
|
|
160
174
|
_boundariesDefinition: B
|
|
@@ -165,9 +179,11 @@ export const Task = class Task<
|
|
|
165
179
|
_boundaryMocks: Record<string, WrappedBoundaryFunction> = {}
|
|
166
180
|
|
|
167
181
|
_schema: Schema<Record<string, SchemaType>> | undefined
|
|
168
|
-
_listener?: ((record:
|
|
182
|
+
_listener?: ((record: ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B>) => void) | undefined
|
|
169
183
|
|
|
170
184
|
constructor (fn: Func, conf: TaskConfig<B> = {
|
|
185
|
+
name: undefined,
|
|
186
|
+
description: undefined,
|
|
171
187
|
schema: undefined,
|
|
172
188
|
mode: 'proxy',
|
|
173
189
|
boundaries: undefined,
|
|
@@ -182,6 +198,10 @@ export const Task = class Task<
|
|
|
182
198
|
this._mode = conf.mode ?? 'proxy'
|
|
183
199
|
this._boundariesDefinition = conf.boundaries ?? {} as B
|
|
184
200
|
|
|
201
|
+
// Set name and description from config
|
|
202
|
+
this._name = conf.name
|
|
203
|
+
this._description = conf.description
|
|
204
|
+
|
|
185
205
|
this._listener = undefined
|
|
186
206
|
|
|
187
207
|
// Cool down time before killing the process on cli runner
|
|
@@ -208,6 +228,14 @@ export const Task = class Task<
|
|
|
208
228
|
}
|
|
209
229
|
}
|
|
210
230
|
|
|
231
|
+
getName(): string | undefined {
|
|
232
|
+
return this._name
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
setName(name: string): void {
|
|
236
|
+
this._name = name
|
|
237
|
+
}
|
|
238
|
+
|
|
211
239
|
getMode (): Mode {
|
|
212
240
|
return this._mode
|
|
213
241
|
}
|
|
@@ -256,8 +284,8 @@ export const Task = class Task<
|
|
|
256
284
|
}
|
|
257
285
|
|
|
258
286
|
// Posible improvement to handle multiple listeners, but so far its not needed
|
|
259
|
-
addListener<I = Parameters<Func>[0], O = ReturnType<Func>>(fn: (record:
|
|
260
|
-
this._listener = fn as (record:
|
|
287
|
+
addListener<I = Parameters<Func>[0], O = ReturnType<Func>>(fn: (record: ExecutionRecord<I, O, B>) => void): void {
|
|
288
|
+
this._listener = fn as (record: ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B>) => void
|
|
261
289
|
}
|
|
262
290
|
|
|
263
291
|
removeListener (): void {
|
|
@@ -268,10 +296,10 @@ export const Task = class Task<
|
|
|
268
296
|
The listener get the input/outout of the call
|
|
269
297
|
Plus all the boundary data
|
|
270
298
|
*/
|
|
271
|
-
emit (data:
|
|
299
|
+
emit (data: ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B>): void {
|
|
272
300
|
if (typeof this._listener === 'undefined') { return }
|
|
273
301
|
|
|
274
|
-
this._listener(data
|
|
302
|
+
this._listener(data)
|
|
275
303
|
}
|
|
276
304
|
|
|
277
305
|
getBoundaries (): WrappedBoundaries<B> {
|
|
@@ -378,10 +406,22 @@ export const Task = class Task<
|
|
|
378
406
|
Error | null,
|
|
379
407
|
ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B>
|
|
380
408
|
]> {
|
|
381
|
-
//
|
|
382
|
-
|
|
409
|
+
// Metadata is empty at start. Then will be populated on the task execution
|
|
410
|
+
// Need to implement that task have a ctx and setMetadata({key, value}) boundary
|
|
411
|
+
const metadata = {} as Record<string, string>
|
|
412
|
+
|
|
413
|
+
// Initialize log item (without type initially)
|
|
414
|
+
const logItemBase = {
|
|
383
415
|
input: argv as Parameters<Func>[0],
|
|
384
|
-
boundaries: {} as BoundaryLogsFor<B
|
|
416
|
+
boundaries: {} as BoundaryLogsFor<B>,
|
|
417
|
+
taskName: this._name,
|
|
418
|
+
metadata: metadata || {}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Create the log item with computed type
|
|
422
|
+
const logItem: ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B> = {
|
|
423
|
+
...logItemBase,
|
|
424
|
+
type: getExecutionRecordType(logItemBase)
|
|
385
425
|
}
|
|
386
426
|
|
|
387
427
|
// Create fresh boundaries for this execution
|
|
@@ -410,6 +450,7 @@ export const Task = class Task<
|
|
|
410
450
|
: 'Invalid input'
|
|
411
451
|
|
|
412
452
|
logItem.error = errorMessage
|
|
453
|
+
logItem.type = 'error'
|
|
413
454
|
logItem.boundaries = {} as BoundaryLogsFor<B>
|
|
414
455
|
|
|
415
456
|
// Add boundary elements empty
|
|
@@ -433,9 +474,11 @@ export const Task = class Task<
|
|
|
433
474
|
)
|
|
434
475
|
|
|
435
476
|
logItem.output = output
|
|
477
|
+
logItem.type = 'success'
|
|
436
478
|
} catch (caughtError) {
|
|
437
479
|
const errorMessage = caughtError instanceof Error ? caughtError.message : String(caughtError)
|
|
438
480
|
logItem.error = errorMessage
|
|
481
|
+
logItem.type = 'error'
|
|
439
482
|
error = new Error(errorMessage)
|
|
440
483
|
}
|
|
441
484
|
|
|
@@ -487,10 +530,18 @@ export const Task = class Task<
|
|
|
487
530
|
// Extract the input from the execution log
|
|
488
531
|
const argv = executionLog.input
|
|
489
532
|
|
|
490
|
-
// Initialize log item for this replay
|
|
491
|
-
const
|
|
533
|
+
// Initialize log item for this replay (without type initially)
|
|
534
|
+
const logItemBase = {
|
|
492
535
|
input: argv,
|
|
493
|
-
boundaries: {} as BoundaryLogsFor<B
|
|
536
|
+
boundaries: {} as BoundaryLogsFor<B>,
|
|
537
|
+
taskName: this._name,
|
|
538
|
+
metadata: executionLog.metadata || {}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Create the log item with computed type
|
|
542
|
+
const logItem: ExecutionRecord<Parameters<Func>[0], ReturnType<Func>, B> = {
|
|
543
|
+
...logItemBase,
|
|
544
|
+
type: getExecutionRecordType(logItemBase)
|
|
494
545
|
}
|
|
495
546
|
|
|
496
547
|
// Create boundaries for this replay execution with custom modes based on config
|
|
@@ -534,6 +585,7 @@ export const Task = class Task<
|
|
|
534
585
|
: 'Invalid input'
|
|
535
586
|
|
|
536
587
|
logItem.error = errorMessage
|
|
588
|
+
logItem.type = 'error'
|
|
537
589
|
logItem.output = executionLog.output // Keep the original output
|
|
538
590
|
|
|
539
591
|
// Copy the boundary data from the execution log
|
|
@@ -555,9 +607,11 @@ export const Task = class Task<
|
|
|
555
607
|
)
|
|
556
608
|
|
|
557
609
|
logItem.output = output
|
|
610
|
+
logItem.type = 'success'
|
|
558
611
|
} catch (caughtError) {
|
|
559
612
|
const errorMessage = caughtError instanceof Error ? caughtError.message : String(caughtError)
|
|
560
613
|
logItem.error = errorMessage
|
|
614
|
+
logItem.type = 'error'
|
|
561
615
|
error = new Error(errorMessage)
|
|
562
616
|
}
|
|
563
617
|
|
|
@@ -757,12 +811,26 @@ export const Task = class Task<
|
|
|
757
811
|
}
|
|
758
812
|
}
|
|
759
813
|
|
|
814
|
+
/**
|
|
815
|
+
* Configuration object for creating a task
|
|
816
|
+
*/
|
|
817
|
+
export interface CreateTaskConfig<
|
|
818
|
+
S extends Schema<Record<string, SchemaType>>,
|
|
819
|
+
B extends Boundaries,
|
|
820
|
+
R
|
|
821
|
+
> {
|
|
822
|
+
name?: string
|
|
823
|
+
description?: string
|
|
824
|
+
schema: S
|
|
825
|
+
boundaries: B
|
|
826
|
+
fn: (argv: InferSchemaType<S>, boundaries: WrappedBoundaries<B>) => Promise<R>
|
|
827
|
+
mode?: Mode
|
|
828
|
+
boundariesData?: BoundaryTapeData
|
|
829
|
+
}
|
|
830
|
+
|
|
760
831
|
/**
|
|
761
832
|
* Helper function to create a task with proper type inference
|
|
762
|
-
* @param
|
|
763
|
-
* @param boundaries The boundaries to use
|
|
764
|
-
* @param fn The task function
|
|
765
|
-
* @param config Additional task configuration
|
|
833
|
+
* @param config Configuration object containing schema, boundaries, and function
|
|
766
834
|
* @returns A new Task instance with proper type inference
|
|
767
835
|
*/
|
|
768
836
|
export function createTask<
|
|
@@ -770,17 +838,18 @@ export function createTask<
|
|
|
770
838
|
B extends Boundaries,
|
|
771
839
|
R
|
|
772
840
|
>(
|
|
773
|
-
|
|
774
|
-
boundaries: B,
|
|
775
|
-
fn: (argv: InferSchemaType<S>, boundaries: WrappedBoundaries<B>) => Promise<R>,
|
|
776
|
-
config?: Omit<TaskConfig<B>, 'schema' | 'boundaries'>
|
|
841
|
+
config: CreateTaskConfig<S, B, R>
|
|
777
842
|
): TaskInstanceType<(argv: InferSchemaType<S>, boundaries: WrappedBoundaries<B>) => Promise<R>, B> {
|
|
778
|
-
|
|
779
|
-
fn,
|
|
843
|
+
const task = new Task(
|
|
844
|
+
config.fn,
|
|
780
845
|
{
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
846
|
+
name: config.name,
|
|
847
|
+
description: config.description,
|
|
848
|
+
schema: config.schema,
|
|
849
|
+
boundaries: config.boundaries,
|
|
850
|
+
mode: config.mode,
|
|
851
|
+
boundariesData: config.boundariesData
|
|
784
852
|
}
|
|
785
853
|
)
|
|
854
|
+
return task
|
|
786
855
|
}
|