@forgehive/record-tape 0.0.3 → 0.1.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 +22 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -14
- package/dist/index.js.map +1 -1
- package/dist/tests/safe-run.test.d.ts +2 -0
- package/dist/tests/safe-run.test.d.ts.map +1 -0
- package/dist/tests/safe-run.test.js +283 -0
- package/dist/tests/safe-run.test.js.map +1 -0
- package/package.json +10 -3
- package/src/index.ts +129 -34
- package/src/tests/safe-run.test.ts +346 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,49 +1,53 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
|
|
2
|
+
import { type ExecutionRecord, type Boundaries } from '@forgehive/task';
|
|
3
|
+
export interface LogRecord<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> extends ExecutionRecord<TInput, TOutput, B> {
|
|
3
4
|
name: string;
|
|
4
5
|
type: 'success' | 'error';
|
|
5
|
-
|
|
6
|
-
output?: TOutput;
|
|
7
|
-
error?: unknown;
|
|
8
|
-
boundaries: Record<string, unknown>;
|
|
6
|
+
context?: Record<string, string>;
|
|
9
7
|
}
|
|
10
|
-
interface SuccessLogItem<TInput = unknown
|
|
8
|
+
export interface SuccessLogItem<TInput = unknown, TOutput = unknown> {
|
|
11
9
|
input: TInput;
|
|
12
10
|
output: TOutput;
|
|
13
11
|
boundaries?: Record<string, unknown>;
|
|
14
12
|
}
|
|
15
|
-
interface ErrorLogItem<TInput = unknown
|
|
13
|
+
export interface ErrorLogItem<TInput = unknown> {
|
|
16
14
|
input: TInput;
|
|
17
15
|
error: unknown;
|
|
18
16
|
boundaries?: Record<string, unknown>;
|
|
19
17
|
}
|
|
20
|
-
export type LogItem<TInput = unknown
|
|
21
|
-
|
|
18
|
+
export type LogItem<TInput = unknown, TOutput = unknown> = SuccessLogItem<TInput, TOutput> | ErrorLogItem<TInput>;
|
|
19
|
+
export type TaskLogItem<TInput = unknown, TOutput = unknown> = LogItem<TInput, TOutput> | {
|
|
20
|
+
input: TInput;
|
|
21
|
+
output?: TOutput;
|
|
22
|
+
error?: unknown;
|
|
23
|
+
boundaries?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
interface Config<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> {
|
|
22
26
|
path?: fs.PathLike;
|
|
23
|
-
log?: LogRecord<TInput, TOutput>[];
|
|
27
|
+
log?: LogRecord<TInput, TOutput, B>[];
|
|
24
28
|
boundaries?: Record<string, unknown>;
|
|
25
29
|
}
|
|
26
30
|
export type Mode = 'record' | 'replay';
|
|
27
|
-
export declare class RecordTape<TInput = unknown
|
|
31
|
+
export declare class RecordTape<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> {
|
|
28
32
|
private _path;
|
|
29
33
|
private _mode;
|
|
30
|
-
private _boundaries;
|
|
31
34
|
private _log;
|
|
32
|
-
constructor(config?: Config<TInput, TOutput>);
|
|
33
|
-
getLog(): LogRecord<TInput, TOutput>[];
|
|
35
|
+
constructor(config?: Config<TInput, TOutput, B>);
|
|
36
|
+
getLog(): LogRecord<TInput, TOutput, B>[];
|
|
34
37
|
getMode(): Mode;
|
|
35
38
|
setMode(mode: Mode): void;
|
|
36
39
|
addLogItem(name: string, logItem: LogItem<TInput, TOutput>): void;
|
|
37
|
-
|
|
40
|
+
push(name: string, record: ExecutionRecord<TInput, unknown, B>, context?: Record<string, string>): LogRecord<TInput, TOutput, B>;
|
|
41
|
+
addLogRecord(logRecord: LogRecord<TInput, TOutput, B>): void;
|
|
38
42
|
stringify(): string;
|
|
39
|
-
parse(content: string): LogRecord<TInput, TOutput>[];
|
|
43
|
+
parse(content: string): LogRecord<TInput, TOutput, B>[];
|
|
40
44
|
compileCache(): Record<string, unknown>;
|
|
41
45
|
recordFrom(name: string, task: {
|
|
42
46
|
_listener?: unknown;
|
|
43
47
|
setBoundariesData: (data: Record<string, unknown>) => void;
|
|
44
48
|
}): void;
|
|
45
|
-
load(): Promise<LogRecord<TInput, TOutput>[]>;
|
|
46
|
-
loadSync(): LogRecord<TInput, TOutput>[];
|
|
49
|
+
load(): Promise<LogRecord<TInput, TOutput, B>[]>;
|
|
50
|
+
loadSync(): LogRecord<TInput, TOutput, B>[];
|
|
47
51
|
save(): Promise<void>;
|
|
48
52
|
saveSync(): void;
|
|
49
53
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -6,18 +6,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.RecordTape = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
function isSuccessLogItem(log) {
|
|
10
|
-
return log.output !== undefined;
|
|
11
|
-
}
|
|
12
|
-
function isErrorLogItem(log) {
|
|
13
|
-
return log.error !== undefined;
|
|
14
|
-
}
|
|
15
9
|
class RecordTape {
|
|
16
10
|
constructor(config = {}) {
|
|
17
|
-
var _a
|
|
11
|
+
var _a;
|
|
18
12
|
this._path = typeof config.path === 'string' ? `${config.path}.log` : undefined;
|
|
19
13
|
this._log = (_a = config.log) !== null && _a !== void 0 ? _a : [];
|
|
20
|
-
this._boundaries = (_b = config.boundaries) !== null && _b !== void 0 ? _b : {};
|
|
21
14
|
this._mode = 'record';
|
|
22
15
|
}
|
|
23
16
|
// Data functions
|
|
@@ -34,18 +27,107 @@ class RecordTape {
|
|
|
34
27
|
if (this._mode === 'replay') {
|
|
35
28
|
return;
|
|
36
29
|
}
|
|
37
|
-
if
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
// Format boundaries to ensure both error and output fields are set if needed
|
|
31
|
+
const formattedBoundaries = {};
|
|
32
|
+
if (logItem.boundaries) {
|
|
33
|
+
for (const key in logItem.boundaries) {
|
|
34
|
+
// Check if the source is from safe-run (if it has error field in entries)
|
|
35
|
+
const boundaryEntries = logItem.boundaries[key];
|
|
36
|
+
const isSafeRun = boundaryEntries.some(entry => entry.error !== undefined);
|
|
37
|
+
formattedBoundaries[key] = boundaryEntries.map(entry => {
|
|
38
|
+
var _a, _b;
|
|
39
|
+
// Only add error field if it's from safe-run
|
|
40
|
+
return isSafeRun ?
|
|
41
|
+
{
|
|
42
|
+
input: entry.input,
|
|
43
|
+
output: (_a = entry.output) !== null && _a !== void 0 ? _a : null,
|
|
44
|
+
error: (_b = entry.error) !== null && _b !== void 0 ? _b : null
|
|
45
|
+
} :
|
|
46
|
+
{
|
|
47
|
+
input: entry.input,
|
|
48
|
+
output: entry.output
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Handle LogItem interface - need to type cast to access properties safely
|
|
54
|
+
const typedLogItem = logItem;
|
|
55
|
+
if ('output' in typedLogItem && typedLogItem.output !== undefined) {
|
|
56
|
+
const { input, output } = typedLogItem;
|
|
57
|
+
this._log.push({
|
|
58
|
+
name,
|
|
59
|
+
type: 'success',
|
|
60
|
+
input,
|
|
61
|
+
output,
|
|
62
|
+
boundaries: formattedBoundaries
|
|
63
|
+
});
|
|
40
64
|
}
|
|
41
|
-
else if (
|
|
42
|
-
const { input, error
|
|
43
|
-
this._log.push({
|
|
65
|
+
else if ('error' in typedLogItem && typedLogItem.error !== undefined) {
|
|
66
|
+
const { input, error } = typedLogItem;
|
|
67
|
+
this._log.push({
|
|
68
|
+
name,
|
|
69
|
+
type: 'error',
|
|
70
|
+
input,
|
|
71
|
+
error,
|
|
72
|
+
boundaries: formattedBoundaries
|
|
73
|
+
});
|
|
44
74
|
}
|
|
45
75
|
else {
|
|
46
76
|
throw new Error('invalid log item');
|
|
47
77
|
}
|
|
48
78
|
}
|
|
79
|
+
push(name, record, context) {
|
|
80
|
+
if (this._mode === 'replay') {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
// For safeRun records, always include both error and output fields
|
|
84
|
+
const formattedBoundaries = {};
|
|
85
|
+
if (record.boundaries) {
|
|
86
|
+
for (const key in record.boundaries) {
|
|
87
|
+
const boundaryArray = record.boundaries[key];
|
|
88
|
+
formattedBoundaries[key] = boundaryArray.map(entry => {
|
|
89
|
+
var _a, _b;
|
|
90
|
+
return {
|
|
91
|
+
input: entry.input,
|
|
92
|
+
output: (_a = entry.output) !== null && _a !== void 0 ? _a : null,
|
|
93
|
+
error: (_b = entry.error) !== null && _b !== void 0 ? _b : null
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
let logRecord;
|
|
99
|
+
if ('output' in record && record.output !== undefined) {
|
|
100
|
+
const input = record.input;
|
|
101
|
+
// Handle Promise outputs by setting to null in the log
|
|
102
|
+
const output = record.output instanceof Promise ? null : record.output;
|
|
103
|
+
logRecord = {
|
|
104
|
+
name,
|
|
105
|
+
type: 'success',
|
|
106
|
+
input,
|
|
107
|
+
output,
|
|
108
|
+
boundaries: formattedBoundaries,
|
|
109
|
+
context
|
|
110
|
+
};
|
|
111
|
+
this._log.push(logRecord);
|
|
112
|
+
}
|
|
113
|
+
else if ('error' in record && record.error !== undefined) {
|
|
114
|
+
const input = record.input;
|
|
115
|
+
const error = record.error;
|
|
116
|
+
logRecord = {
|
|
117
|
+
name,
|
|
118
|
+
type: 'error',
|
|
119
|
+
input,
|
|
120
|
+
error,
|
|
121
|
+
boundaries: formattedBoundaries,
|
|
122
|
+
context
|
|
123
|
+
};
|
|
124
|
+
this._log.push(logRecord);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
throw new Error('invalid record type');
|
|
128
|
+
}
|
|
129
|
+
return logRecord;
|
|
130
|
+
}
|
|
49
131
|
addLogRecord(logRecord) {
|
|
50
132
|
this._log.push(logRecord);
|
|
51
133
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,4CAAmB;AACnB,gDAAuB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-run.test.d.ts","sourceRoot":"","sources":["../../src/tests/safe-run.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../index");
|
|
4
|
+
const task_1 = require("@forgehive/task");
|
|
5
|
+
describe('RecordTape safeRun integration tests', () => {
|
|
6
|
+
it('should record log items directly from safeRun result', async () => {
|
|
7
|
+
// Create a schema
|
|
8
|
+
const schema = new task_1.Schema({
|
|
9
|
+
value: task_1.Schema.number()
|
|
10
|
+
});
|
|
11
|
+
// Define the boundaries
|
|
12
|
+
const boundaries = {
|
|
13
|
+
fetchData: async (value) => {
|
|
14
|
+
return value * 2;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
// Create the task
|
|
18
|
+
const task = (0, task_1.createTask)(schema, boundaries, async function ({ value }, { fetchData }) {
|
|
19
|
+
const result = await fetchData(value);
|
|
20
|
+
return { result, success: true };
|
|
21
|
+
});
|
|
22
|
+
// Create a record tape
|
|
23
|
+
const tape = new index_1.RecordTape();
|
|
24
|
+
// Run the task with safeRun and directly use the logItem
|
|
25
|
+
const [result, error, record] = await task.safeRun({ value: 5 });
|
|
26
|
+
tape.push('test-task', record);
|
|
27
|
+
// Verify the execution was successful
|
|
28
|
+
expect(error).toBeNull();
|
|
29
|
+
expect(result).toEqual({ result: 10, success: true });
|
|
30
|
+
// Get the recorded log from the tape
|
|
31
|
+
const recordedLog = tape.getLog();
|
|
32
|
+
// Verify the log was recorded correctly
|
|
33
|
+
expect(recordedLog).toHaveLength(1);
|
|
34
|
+
const logItem = recordedLog[0];
|
|
35
|
+
expect(logItem.name).toEqual('test-task');
|
|
36
|
+
expect(logItem.type).toEqual('success');
|
|
37
|
+
expect(logItem.input).toEqual({ value: 5 });
|
|
38
|
+
expect(logItem.output).toEqual({ result: 10, success: true });
|
|
39
|
+
expect(logItem.boundaries).toEqual({
|
|
40
|
+
fetchData: [{
|
|
41
|
+
input: [5],
|
|
42
|
+
output: 10,
|
|
43
|
+
error: null
|
|
44
|
+
}]
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
it('should record log items from safeRun successfully', async () => {
|
|
48
|
+
// Create a schema
|
|
49
|
+
const schema = new task_1.Schema({
|
|
50
|
+
value: task_1.Schema.number()
|
|
51
|
+
});
|
|
52
|
+
// Define the boundaries
|
|
53
|
+
const boundaries = {
|
|
54
|
+
fetchData: async (value) => {
|
|
55
|
+
return value * 2;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
// Create the task
|
|
59
|
+
const task = (0, task_1.createTask)(schema, boundaries, async function ({ value }, { fetchData }) {
|
|
60
|
+
const result = await fetchData(value);
|
|
61
|
+
return { result, success: true };
|
|
62
|
+
});
|
|
63
|
+
// Create a record tape
|
|
64
|
+
const tape = new index_1.RecordTape();
|
|
65
|
+
// Add listener to record the log items
|
|
66
|
+
task.addListener((record) => {
|
|
67
|
+
// Manually ensure boundary records have error field for consistency with safeRun
|
|
68
|
+
if (record.boundaries && record.boundaries.fetchData && Array.isArray(record.boundaries.fetchData)) {
|
|
69
|
+
record.boundaries.fetchData = record.boundaries.fetchData.map((entry) => {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
return (Object.assign(Object.assign({}, entry), { error: (_a = entry.error) !== null && _a !== void 0 ? _a : null, output: (_b = entry.output) !== null && _b !== void 0 ? _b : null }));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Cast the record to LogItem type to satisfy TypeScript
|
|
75
|
+
tape.addLogItem('test-task', record);
|
|
76
|
+
});
|
|
77
|
+
// Run the task with safeRun
|
|
78
|
+
const [result, error] = await task.safeRun({ value: 5 });
|
|
79
|
+
// Verify the execution was successful
|
|
80
|
+
expect(error).toBeNull();
|
|
81
|
+
expect(result).toEqual({ result: 10, success: true });
|
|
82
|
+
// Get the recorded log from the tape
|
|
83
|
+
const recordedLog = tape.getLog();
|
|
84
|
+
// Verify the log was recorded correctly
|
|
85
|
+
expect(recordedLog).toHaveLength(1);
|
|
86
|
+
expect(recordedLog[0]).toEqual({
|
|
87
|
+
name: 'test-task',
|
|
88
|
+
type: 'success',
|
|
89
|
+
input: { value: 5 },
|
|
90
|
+
output: { result: 10, success: true },
|
|
91
|
+
boundaries: {
|
|
92
|
+
fetchData: [{
|
|
93
|
+
input: [5],
|
|
94
|
+
output: 10,
|
|
95
|
+
error: null
|
|
96
|
+
}]
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it('should record error log items from safeRun', async () => {
|
|
101
|
+
// Create a schema
|
|
102
|
+
const schema = new task_1.Schema({
|
|
103
|
+
value: task_1.Schema.number()
|
|
104
|
+
});
|
|
105
|
+
// Define the boundaries with a function that will throw an error
|
|
106
|
+
const boundaries = {
|
|
107
|
+
fetchData: async (value) => {
|
|
108
|
+
if (value < 0) {
|
|
109
|
+
throw new Error('Value cannot be negative');
|
|
110
|
+
}
|
|
111
|
+
return value * 2;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
// Create the task
|
|
115
|
+
const task = (0, task_1.createTask)(schema, boundaries, async function ({ value }, { fetchData }) {
|
|
116
|
+
const result = await fetchData(value);
|
|
117
|
+
return { result, success: true };
|
|
118
|
+
});
|
|
119
|
+
// Create a record tape
|
|
120
|
+
const tape = new index_1.RecordTape();
|
|
121
|
+
// Add listener to record the log items
|
|
122
|
+
task.addListener((record) => {
|
|
123
|
+
// Manually ensure boundary records have error field for consistency with safeRun
|
|
124
|
+
if (record.boundaries && record.boundaries.fetchData && Array.isArray(record.boundaries.fetchData)) {
|
|
125
|
+
record.boundaries.fetchData = record.boundaries.fetchData.map((entry) => {
|
|
126
|
+
var _a, _b;
|
|
127
|
+
return (Object.assign(Object.assign({}, entry), { error: (_a = entry.error) !== null && _a !== void 0 ? _a : null, output: (_b = entry.output) !== null && _b !== void 0 ? _b : null }));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Cast the record to LogItem type to satisfy TypeScript
|
|
131
|
+
tape.addLogItem('test-task', record);
|
|
132
|
+
});
|
|
133
|
+
// Run the task with safeRun with a value that will cause an error
|
|
134
|
+
const [result, error] = await task.safeRun({ value: -5 });
|
|
135
|
+
// Verify the execution failed as expected
|
|
136
|
+
expect(result).toBeNull();
|
|
137
|
+
expect(error).not.toBeNull();
|
|
138
|
+
expect(error === null || error === void 0 ? void 0 : error.message).toContain('Value cannot be negative');
|
|
139
|
+
// Get the recorded log from the tape
|
|
140
|
+
const recordedLog = tape.getLog();
|
|
141
|
+
// Verify the error log was recorded correctly
|
|
142
|
+
expect(recordedLog).toHaveLength(1);
|
|
143
|
+
expect(recordedLog[0]).toEqual({
|
|
144
|
+
name: 'test-task',
|
|
145
|
+
type: 'error',
|
|
146
|
+
input: { value: -5 },
|
|
147
|
+
error: 'Value cannot be negative',
|
|
148
|
+
boundaries: {
|
|
149
|
+
fetchData: [{
|
|
150
|
+
input: [-5],
|
|
151
|
+
output: null,
|
|
152
|
+
error: 'Value cannot be negative'
|
|
153
|
+
}]
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
it('should handle error records directly with push', async () => {
|
|
158
|
+
// Create a schema
|
|
159
|
+
const schema = new task_1.Schema({
|
|
160
|
+
value: task_1.Schema.number()
|
|
161
|
+
});
|
|
162
|
+
// Define the boundaries with a function that will throw an error
|
|
163
|
+
const boundaries = {
|
|
164
|
+
fetchData: async (value) => {
|
|
165
|
+
if (value < 0) {
|
|
166
|
+
throw new Error('Value cannot be negative');
|
|
167
|
+
}
|
|
168
|
+
return value * 2;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
// Create the task
|
|
172
|
+
const task = (0, task_1.createTask)(schema, boundaries, async function ({ value }, { fetchData }) {
|
|
173
|
+
const result = await fetchData(value);
|
|
174
|
+
return { result, success: true };
|
|
175
|
+
});
|
|
176
|
+
// Create a record tape
|
|
177
|
+
const tape = new index_1.RecordTape();
|
|
178
|
+
// Run the task with safeRun with a value that will cause an error
|
|
179
|
+
const [result, error, record] = await task.safeRun({ value: -5 });
|
|
180
|
+
// Push the error record directly with type parameter
|
|
181
|
+
tape.push('test-error', record);
|
|
182
|
+
// Verify the execution failed as expected
|
|
183
|
+
expect(result).toBeNull();
|
|
184
|
+
expect(error).not.toBeNull();
|
|
185
|
+
expect(error instanceof Error).toBe(true);
|
|
186
|
+
if (error instanceof Error) {
|
|
187
|
+
expect(error.message).toContain('Value cannot be negative');
|
|
188
|
+
}
|
|
189
|
+
// Get the recorded log from the tape
|
|
190
|
+
const recordedLog = tape.getLog();
|
|
191
|
+
// Verify the error log was recorded correctly
|
|
192
|
+
expect(recordedLog).toHaveLength(1);
|
|
193
|
+
expect(recordedLog[0]).toEqual({
|
|
194
|
+
name: 'test-error',
|
|
195
|
+
type: 'error',
|
|
196
|
+
input: { value: -5 },
|
|
197
|
+
error: 'Value cannot be negative',
|
|
198
|
+
boundaries: {
|
|
199
|
+
fetchData: [{
|
|
200
|
+
input: [-5],
|
|
201
|
+
output: null,
|
|
202
|
+
error: 'Value cannot be negative'
|
|
203
|
+
}]
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
it('should handle custom execution records with push', async () => {
|
|
208
|
+
// Create a record tape
|
|
209
|
+
const tape = new index_1.RecordTape();
|
|
210
|
+
// Create a custom execution record
|
|
211
|
+
const customRecord = {
|
|
212
|
+
input: { value: 10 },
|
|
213
|
+
output: { result: 20 },
|
|
214
|
+
boundaries: {
|
|
215
|
+
fetchData: [
|
|
216
|
+
{
|
|
217
|
+
input: [10],
|
|
218
|
+
output: 20,
|
|
219
|
+
error: null
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
// Push the custom record
|
|
225
|
+
tape.push('custom-record', customRecord);
|
|
226
|
+
// Get the recorded log from the tape
|
|
227
|
+
const recordedLog = tape.getLog();
|
|
228
|
+
// Verify the log was recorded correctly
|
|
229
|
+
expect(recordedLog).toHaveLength(1);
|
|
230
|
+
expect(recordedLog[0]).toEqual({
|
|
231
|
+
name: 'custom-record',
|
|
232
|
+
type: 'success',
|
|
233
|
+
input: { value: 10 },
|
|
234
|
+
output: { result: 20 },
|
|
235
|
+
boundaries: {
|
|
236
|
+
fetchData: [{
|
|
237
|
+
input: [10],
|
|
238
|
+
output: 20,
|
|
239
|
+
error: null
|
|
240
|
+
}]
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
it('should handle execution records with Promise outputs correctly', async () => {
|
|
245
|
+
// Create a record tape
|
|
246
|
+
const tape = new index_1.RecordTape();
|
|
247
|
+
// Create a custom execution record with a Promise output
|
|
248
|
+
const promiseResult = Promise.resolve({ result: 30 });
|
|
249
|
+
const promiseRecord = {
|
|
250
|
+
input: { value: 15 },
|
|
251
|
+
output: promiseResult,
|
|
252
|
+
boundaries: {
|
|
253
|
+
fetchData: [
|
|
254
|
+
{
|
|
255
|
+
input: [15],
|
|
256
|
+
output: 30,
|
|
257
|
+
error: null
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
// Push the record with Promise output using type parameter
|
|
263
|
+
tape.push('promise-record', promiseRecord);
|
|
264
|
+
// Get the recorded log from the tape
|
|
265
|
+
const recordedLog = tape.getLog();
|
|
266
|
+
// Verify the log was recorded correctly, with Promise output set to null
|
|
267
|
+
expect(recordedLog).toHaveLength(1);
|
|
268
|
+
expect(recordedLog[0]).toEqual({
|
|
269
|
+
name: 'promise-record',
|
|
270
|
+
type: 'success',
|
|
271
|
+
input: { value: 15 },
|
|
272
|
+
output: null, // Promise output should be set to null
|
|
273
|
+
boundaries: {
|
|
274
|
+
fetchData: [{
|
|
275
|
+
input: [15],
|
|
276
|
+
output: 30,
|
|
277
|
+
error: null
|
|
278
|
+
}]
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
//# sourceMappingURL=safe-run.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-run.test.js","sourceRoot":"","sources":["../../src/tests/safe-run.test.ts"],"names":[],"mappings":";;AAAA,oCAAmD;AACnD,0CAA2F;AAE3F,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;IACpD,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,kBAAkB;QAClB,MAAM,MAAM,GAAG,IAAI,aAAM,CAAC;YACxB,KAAK,EAAE,aAAM,CAAC,MAAM,EAAE;SACvB,CAAC,CAAA;QAEF,wBAAwB;QACxB,MAAM,UAAU,GAAG;YACjB,SAAS,EAAE,KAAK,EAAE,KAAa,EAAmB,EAAE;gBAClD,OAAO,KAAK,GAAG,CAAC,CAAA;YAClB,CAAC;SACF,CAAA;QAED,kBAAkB;QAClB,MAAM,IAAI,GAAG,IAAA,iBAAU,EACrB,MAAM,EACN,UAAU,EACV,KAAK,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAA;YACrC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAClC,CAAC,CACF,CAAA;QAED,uBAAuB;QACvB,MAAM,IAAI,GAAG,IAAI,kBAAU,EAA8E,CAAA;QAEzG,yDAAyD;QACzD,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;QAChE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;QAE9B,sCAAsC;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAA;QACxB,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAErD,qCAAqC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAEjC,wCAAwC;QACxC,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAEnC,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;QAC9B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QACzC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QACvC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;QAC3C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAC7D,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC;YACjC,SAAS,EAAE,CAAC;oBACV,KAAK,EAAE,CAAC,CAAC,CAAC;oBACV,MAAM,EAAE,EAAE;oBACV,KAAK,EAAE,IAAI;iBACZ,CAAC;SACH,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,kBAAkB;QAClB,MAAM,MAAM,GAAG,IAAI,aAAM,CAAC;YACxB,KAAK,EAAE,aAAM,CAAC,MAAM,EAAE;SACvB,CAAC,CAAA;QAEF,wBAAwB;QACxB,MAAM,UAAU,GAAG;YACjB,SAAS,EAAE,KAAK,EAAE,KAAa,EAAmB,EAAE;gBAClD,OAAO,KAAK,GAAG,CAAC,CAAA;YAClB,CAAC;SACF,CAAA;QAED,kBAAkB;QAClB,MAAM,IAAI,GAAG,IAAA,iBAAU,EACrB,MAAM,EACN,UAAU,EACV,KAAK,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAA;YACrC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAClC,CAAC,CACF,CAAA;QAED,uBAAuB;QACvB,MAAM,IAAI,GAAG,IAAI,kBAAU,EAA8E,CAAA;QAEzG,uCAAuC;QACvC,IAAI,CAAC,WAAW,CAAC,CAAC,MAA2E,EAAE,EAAE;YAC/F,iFAAiF;YACjF,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnG,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAA8B,EAAE,EAAE;;oBAAC,OAAA,iCAC7F,KAAK,KACR,KAAK,EAAE,MAAA,KAAK,CAAC,KAAK,mCAAI,IAAI,EAC1B,MAAM,EAAE,MAAA,KAAK,CAAC,MAAM,mCAAI,IAAI,IAC5B,CAAA;iBAAA,CAAC,CAAA;YACL,CAAC;YAED,wDAAwD;YACxD,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,MAAqF,CAAC,CAAA;QACrH,CAAC,CAAC,CAAA;QAEF,4BAA4B;QAC5B,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAA;QAExD,sCAAsC;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAA;QACxB,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QAErD,qCAAqC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAEjC,wCAAwC;QACxC,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;YACnB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YACrC,UAAU,EAAE;gBACV,SAAS,EAAE,CAAC;wBACV,KAAK,EAAE,CAAC,CAAC,CAAC;wBACV,MAAM,EAAE,EAAE;wBACV,KAAK,EAAE,IAAI;qBACZ,CAAC;aACH;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,kBAAkB;QAClB,MAAM,MAAM,GAAG,IAAI,aAAM,CAAC;YACxB,KAAK,EAAE,aAAM,CAAC,MAAM,EAAE;SACvB,CAAC,CAAA;QAEF,iEAAiE;QACjE,MAAM,UAAU,GAAG;YACjB,SAAS,EAAE,KAAK,EAAE,KAAa,EAAmB,EAAE;gBAClD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;oBACd,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;gBAC7C,CAAC;gBACD,OAAO,KAAK,GAAG,CAAC,CAAA;YAClB,CAAC;SACF,CAAA;QAED,kBAAkB;QAClB,MAAM,IAAI,GAAG,IAAA,iBAAU,EACrB,MAAM,EACN,UAAU,EACV,KAAK,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAA;YACrC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAClC,CAAC,CACF,CAAA;QAED,uBAAuB;QACvB,MAAM,IAAI,GAAG,IAAI,kBAAU,EAA8E,CAAA;QAEzG,uCAAuC;QACvC,IAAI,CAAC,WAAW,CAAC,CAAC,MAA2E,EAAE,EAAE;YAC/F,iFAAiF;YACjF,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnG,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,KAA8B,EAAE,EAAE;;oBAAC,OAAA,iCAC7F,KAAK,KACR,KAAK,EAAE,MAAA,KAAK,CAAC,KAAK,mCAAI,IAAI,EAC1B,MAAM,EAAE,MAAA,KAAK,CAAC,MAAM,mCAAI,IAAI,IAC5B,CAAA;iBAAA,CAAC,CAAA;YACL,CAAC;YAED,wDAAwD;YACxD,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,MAAqF,CAAC,CAAA;QACrH,CAAC,CAAC,CAAA;QAEF,kEAAkE;QAClE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;QAEzD,0CAA0C;QAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;QACzB,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5B,MAAM,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,OAAO,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAA;QAE5D,qCAAqC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAEjC,8CAA8C;QAC9C,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE;YACpB,KAAK,EAAE,0BAA0B;YACjC,UAAU,EAAE;gBACV,SAAS,EAAE,CAAC;wBACV,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;wBACX,MAAM,EAAE,IAAI;wBACZ,KAAK,EAAE,0BAA0B;qBAClC,CAAC;aACH;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,kBAAkB;QAClB,MAAM,MAAM,GAAG,IAAI,aAAM,CAAC;YACxB,KAAK,EAAE,aAAM,CAAC,MAAM,EAAE;SACvB,CAAC,CAAA;QAEF,iEAAiE;QACjE,MAAM,UAAU,GAAG;YACjB,SAAS,EAAE,KAAK,EAAE,KAAa,EAAmB,EAAE;gBAClD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;oBACd,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAA;gBAC7C,CAAC;gBACD,OAAO,KAAK,GAAG,CAAC,CAAA;YAClB,CAAC;SACF,CAAA;QAED,kBAAkB;QAClB,MAAM,IAAI,GAAG,IAAA,iBAAU,EACrB,MAAM,EACN,UAAU,EACV,KAAK,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAA;YACrC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;QAClC,CAAC,CACF,CAAA;QAED,uBAAuB;QACvB,MAAM,IAAI,GAAG,IAAI,kBAAU,EAA8E,CAAA;QAEzG,kEAAkE;QAClE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAA;QAEjE,qDAAqD;QACrD,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;QAE/B,0CAA0C;QAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;QACzB,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAC5B,MAAM,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAA;QAC7D,CAAC;QAED,qCAAqC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAEjC,8CAA8C;QAC9C,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE;YACpB,KAAK,EAAE,0BAA0B;YACjC,UAAU,EAAE;gBACV,SAAS,EAAE,CAAC;wBACV,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;wBACX,MAAM,EAAE,IAAI;wBACZ,KAAK,EAAE,0BAA0B;qBAClC,CAAC;aACH;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,uBAAuB;QACvB,MAAM,IAAI,GAAG,IAAI,kBAAU,EAAwF,CAAA;QAEnH,mCAAmC;QACnC,MAAM,YAAY,GAA0G;YAC1H,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACtB,UAAU,EAAE;gBACV,SAAS,EAAE;oBACT;wBACE,KAAK,EAAE,CAAC,EAAE,CAAC;wBACX,MAAM,EAAE,EAAE;wBACV,KAAK,EAAE,IAAI;qBACZ;iBACF;aACF;SACF,CAAA;QAED,yBAAyB;QACzB,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,YAAY,CAAC,CAAA;QAExC,qCAAqC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAEjC,wCAAwC;QACxC,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,eAAe;YACrB,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACpB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACtB,UAAU,EAAE;gBACV,SAAS,EAAE,CAAC;wBACV,KAAK,EAAE,CAAC,EAAE,CAAC;wBACX,MAAM,EAAE,EAAE;wBACV,KAAK,EAAE,IAAI;qBACZ,CAAC;aACH;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,uBAAuB;QACvB,MAAM,IAAI,GAAG,IAAI,kBAAU,EAAwF,CAAA;QAEnH,yDAAyD;QACzD,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;QACrD,MAAM,aAAa,GAAmH;YACpI,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACpB,MAAM,EAAE,aAAa;YACrB,UAAU,EAAE;gBACV,SAAS,EAAE;oBACT;wBACE,KAAK,EAAE,CAAC,EAAE,CAAC;wBACX,MAAM,EAAE,EAAE;wBACV,KAAK,EAAE,IAAI;qBACZ;iBACF;aACF;SACF,CAAA;QAED,2DAA2D;QAC3D,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;QAE1C,qCAAqC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAEjC,yEAAyE;QACzE,MAAM,CAAC,WAAW,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QACnC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YACpB,MAAM,EAAE,IAAI,EAAE,uCAAuC;YACrD,UAAU,EAAE;gBACV,SAAS,EAAE,CAAC;wBACV,KAAK,EAAE,CAAC,EAAE,CAAC;wBACX,MAAM,EAAE,EAAE;wBACV,KAAK,EAAE,IAAI;qBACZ,CAAC;aACH;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgehive/record-tape",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public",
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@forgehive/schema": "^0.1.4",
|
|
11
|
+
"@forgehive/task": "^0.1.7"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
7
14
|
"devDependencies": {
|
|
8
15
|
"@types/jest": "^29.5.14",
|
|
9
16
|
"@types/node": "^20.11.24",
|
|
@@ -12,8 +19,8 @@
|
|
|
12
19
|
"typescript": "^5.3.3"
|
|
13
20
|
},
|
|
14
21
|
"dependencies": {
|
|
15
|
-
"@forgehive/
|
|
16
|
-
"@forgehive/
|
|
22
|
+
"@forgehive/task": "0.1.7",
|
|
23
|
+
"@forgehive/schema": "0.1.4"
|
|
17
24
|
},
|
|
18
25
|
"scripts": {
|
|
19
26
|
"build": "tsc",
|
package/src/index.ts
CHANGED
|
@@ -1,60 +1,56 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
2
|
import path from 'path'
|
|
3
|
+
import { type ExecutionRecord, type Boundaries } from '@forgehive/task'
|
|
3
4
|
|
|
4
|
-
export interface LogRecord<TInput = unknown
|
|
5
|
+
export interface LogRecord<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> extends ExecutionRecord<TInput, TOutput, B> {
|
|
5
6
|
name: string
|
|
6
7
|
type: 'success' | 'error'
|
|
7
|
-
|
|
8
|
-
output?: TOutput
|
|
9
|
-
error?: unknown
|
|
10
|
-
boundaries: Record<string, unknown>
|
|
8
|
+
context?: Record<string, string>
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
interface SuccessLogItem<TInput = unknown
|
|
11
|
+
export interface SuccessLogItem<TInput = unknown, TOutput = unknown> {
|
|
14
12
|
input: TInput
|
|
15
13
|
output: TOutput
|
|
16
14
|
boundaries?: Record<string, unknown>
|
|
17
15
|
}
|
|
18
16
|
|
|
19
|
-
interface ErrorLogItem<TInput = unknown
|
|
17
|
+
export interface ErrorLogItem<TInput = unknown> {
|
|
20
18
|
input: TInput
|
|
21
19
|
error: unknown
|
|
22
20
|
boundaries?: Record<string, unknown>
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
return (log as SuccessLogItem<TInput, TOutput>).output !== undefined
|
|
27
|
-
}
|
|
23
|
+
export type LogItem<TInput = unknown, TOutput = unknown> = SuccessLogItem<TInput, TOutput> | ErrorLogItem<TInput>
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
// Additional type to handle TaskRecord compatibility
|
|
26
|
+
export type TaskLogItem<TInput = unknown, TOutput = unknown> = LogItem<TInput, TOutput> | {
|
|
27
|
+
input: TInput;
|
|
28
|
+
output?: TOutput;
|
|
29
|
+
error?: unknown;
|
|
30
|
+
boundaries?: Record<string, unknown>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
interface Config<TInput = unknown[], TOutput = unknown> {
|
|
33
|
+
interface Config<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> {
|
|
36
34
|
path?: fs.PathLike
|
|
37
|
-
log?: LogRecord<TInput, TOutput>[]
|
|
35
|
+
log?: LogRecord<TInput, TOutput, B>[]
|
|
38
36
|
boundaries?: Record<string, unknown>
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
export type Mode = 'record' | 'replay'
|
|
42
40
|
|
|
43
|
-
export class RecordTape<TInput = unknown
|
|
41
|
+
export class RecordTape<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> {
|
|
44
42
|
private _path: fs.PathLike | undefined
|
|
45
43
|
private _mode: Mode
|
|
46
|
-
private
|
|
47
|
-
private _log: LogRecord<TInput, TOutput>[]
|
|
44
|
+
private _log: LogRecord<TInput, TOutput, B>[]
|
|
48
45
|
|
|
49
|
-
constructor(config: Config<TInput, TOutput> = {}) {
|
|
46
|
+
constructor(config: Config<TInput, TOutput, B> = {}) {
|
|
50
47
|
this._path = typeof config.path === 'string' ? `${config.path}.log` : undefined
|
|
51
48
|
this._log = config.log ?? []
|
|
52
|
-
this._boundaries = config.boundaries ?? {}
|
|
53
49
|
this._mode = 'record'
|
|
54
50
|
}
|
|
55
51
|
|
|
56
52
|
// Data functions
|
|
57
|
-
getLog(): LogRecord<TInput, TOutput>[] {
|
|
53
|
+
getLog(): LogRecord<TInput, TOutput, B>[] {
|
|
58
54
|
return this._log
|
|
59
55
|
}
|
|
60
56
|
|
|
@@ -71,18 +67,117 @@ export class RecordTape<TInput = unknown[], TOutput = unknown> {
|
|
|
71
67
|
return
|
|
72
68
|
}
|
|
73
69
|
|
|
74
|
-
if
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
70
|
+
// Format boundaries to ensure both error and output fields are set if needed
|
|
71
|
+
const formattedBoundaries: Record<string, unknown> = {}
|
|
72
|
+
if (logItem.boundaries) {
|
|
73
|
+
for (const key in logItem.boundaries) {
|
|
74
|
+
// Check if the source is from safe-run (if it has error field in entries)
|
|
75
|
+
const boundaryEntries = logItem.boundaries[key] as Array<Record<string, unknown>>
|
|
76
|
+
const isSafeRun = boundaryEntries.some(entry => entry.error !== undefined)
|
|
77
|
+
|
|
78
|
+
formattedBoundaries[key] = boundaryEntries.map(entry => {
|
|
79
|
+
// Only add error field if it's from safe-run
|
|
80
|
+
return isSafeRun ?
|
|
81
|
+
{
|
|
82
|
+
input: entry.input,
|
|
83
|
+
output: entry.output ?? null,
|
|
84
|
+
error: entry.error ?? null
|
|
85
|
+
} :
|
|
86
|
+
{
|
|
87
|
+
input: entry.input,
|
|
88
|
+
output: entry.output
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Handle LogItem interface - need to type cast to access properties safely
|
|
95
|
+
const typedLogItem = logItem as (SuccessLogItem<TInput, TOutput> | ErrorLogItem<TInput>)
|
|
96
|
+
|
|
97
|
+
if ('output' in typedLogItem && typedLogItem.output !== undefined) {
|
|
98
|
+
const { input, output } = typedLogItem
|
|
99
|
+
this._log.push({
|
|
100
|
+
name,
|
|
101
|
+
type: 'success',
|
|
102
|
+
input,
|
|
103
|
+
output,
|
|
104
|
+
boundaries: formattedBoundaries
|
|
105
|
+
} as LogRecord<TInput, TOutput, B>)
|
|
106
|
+
} else if ('error' in typedLogItem && typedLogItem.error !== undefined) {
|
|
107
|
+
const { input, error } = typedLogItem
|
|
108
|
+
this._log.push({
|
|
109
|
+
name,
|
|
110
|
+
type: 'error',
|
|
111
|
+
input,
|
|
112
|
+
error,
|
|
113
|
+
boundaries: formattedBoundaries
|
|
114
|
+
} as LogRecord<TInput, TOutput, B>)
|
|
80
115
|
} else {
|
|
81
116
|
throw new Error('invalid log item')
|
|
82
117
|
}
|
|
83
118
|
}
|
|
84
119
|
|
|
85
|
-
|
|
120
|
+
push(
|
|
121
|
+
name: string,
|
|
122
|
+
record: ExecutionRecord<TInput, unknown, B>,
|
|
123
|
+
context?: Record<string, string>
|
|
124
|
+
): LogRecord<TInput, TOutput, B> {
|
|
125
|
+
if (this._mode === 'replay') {
|
|
126
|
+
return {} as LogRecord<TInput, TOutput, B>
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// For safeRun records, always include both error and output fields
|
|
130
|
+
const formattedBoundaries: Record<string, unknown> = {}
|
|
131
|
+
if (record.boundaries) {
|
|
132
|
+
for (const key in record.boundaries) {
|
|
133
|
+
const boundaryArray = record.boundaries[key] as Array<Record<string, unknown>>
|
|
134
|
+
formattedBoundaries[key] = boundaryArray.map(entry => {
|
|
135
|
+
return {
|
|
136
|
+
input: entry.input,
|
|
137
|
+
output: entry.output ?? null,
|
|
138
|
+
error: entry.error ?? null
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let logRecord: LogRecord<TInput, TOutput, B>
|
|
145
|
+
|
|
146
|
+
if ('output' in record && record.output !== undefined) {
|
|
147
|
+
const input = record.input
|
|
148
|
+
// Handle Promise outputs by setting to null in the log
|
|
149
|
+
const output = record.output instanceof Promise ? null : record.output
|
|
150
|
+
|
|
151
|
+
logRecord = {
|
|
152
|
+
name,
|
|
153
|
+
type: 'success',
|
|
154
|
+
input,
|
|
155
|
+
output,
|
|
156
|
+
boundaries: formattedBoundaries,
|
|
157
|
+
context
|
|
158
|
+
} as LogRecord<TInput, TOutput, B>
|
|
159
|
+
this._log.push(logRecord)
|
|
160
|
+
} else if ('error' in record && record.error !== undefined) {
|
|
161
|
+
const input = record.input
|
|
162
|
+
const error = record.error
|
|
163
|
+
|
|
164
|
+
logRecord = {
|
|
165
|
+
name,
|
|
166
|
+
type: 'error',
|
|
167
|
+
input,
|
|
168
|
+
error,
|
|
169
|
+
boundaries: formattedBoundaries,
|
|
170
|
+
context
|
|
171
|
+
} as LogRecord<TInput, TOutput, B>
|
|
172
|
+
this._log.push(logRecord)
|
|
173
|
+
} else {
|
|
174
|
+
throw new Error('invalid record type')
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return logRecord
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
addLogRecord(logRecord: LogRecord<TInput, TOutput, B>): void {
|
|
86
181
|
this._log.push(logRecord)
|
|
87
182
|
}
|
|
88
183
|
|
|
@@ -95,12 +190,12 @@ export class RecordTape<TInput = unknown[], TOutput = unknown> {
|
|
|
95
190
|
return log
|
|
96
191
|
}
|
|
97
192
|
|
|
98
|
-
parse(content: string): LogRecord<TInput, TOutput>[] {
|
|
193
|
+
parse(content: string): LogRecord<TInput, TOutput, B>[] {
|
|
99
194
|
const items = content.split('\n')
|
|
100
|
-
const log: LogRecord<TInput, TOutput>[] = []
|
|
195
|
+
const log: LogRecord<TInput, TOutput, B>[] = []
|
|
101
196
|
for (const item of items) {
|
|
102
197
|
if (item !== '') {
|
|
103
|
-
const data = JSON.parse(item) as LogRecord<TInput, TOutput>
|
|
198
|
+
const data = JSON.parse(item) as LogRecord<TInput, TOutput, B>
|
|
104
199
|
log.push(data)
|
|
105
200
|
}
|
|
106
201
|
}
|
|
@@ -137,7 +232,7 @@ export class RecordTape<TInput = unknown[], TOutput = unknown> {
|
|
|
137
232
|
}
|
|
138
233
|
|
|
139
234
|
// Load save functions
|
|
140
|
-
async load(): Promise<LogRecord<TInput, TOutput>[]> {
|
|
235
|
+
async load(): Promise<LogRecord<TInput, TOutput, B>[]> {
|
|
141
236
|
if (typeof this._path === 'undefined') {
|
|
142
237
|
return []
|
|
143
238
|
}
|
|
@@ -167,7 +262,7 @@ export class RecordTape<TInput = unknown[], TOutput = unknown> {
|
|
|
167
262
|
return this._log
|
|
168
263
|
}
|
|
169
264
|
|
|
170
|
-
loadSync(): LogRecord<TInput, TOutput>[] {
|
|
265
|
+
loadSync(): LogRecord<TInput, TOutput, B>[] {
|
|
171
266
|
if (typeof this._path === 'undefined') { return [] }
|
|
172
267
|
|
|
173
268
|
const dirpath = path.dirname(this._path.toString())
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { RecordTape, type LogItem } from '../index'
|
|
2
|
+
import { createTask, Schema, type ExecutionRecord, type TaskRecord } from '@forgehive/task'
|
|
3
|
+
|
|
4
|
+
describe('RecordTape safeRun integration tests', () => {
|
|
5
|
+
it('should record log items directly from safeRun result', async () => {
|
|
6
|
+
// Create a schema
|
|
7
|
+
const schema = new Schema({
|
|
8
|
+
value: Schema.number()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
// Define the boundaries
|
|
12
|
+
const boundaries = {
|
|
13
|
+
fetchData: async (value: number): Promise<number> => {
|
|
14
|
+
return value * 2
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Create the task
|
|
19
|
+
const task = createTask(
|
|
20
|
+
schema,
|
|
21
|
+
boundaries,
|
|
22
|
+
async function ({ value }, { fetchData }) {
|
|
23
|
+
const result = await fetchData(value)
|
|
24
|
+
return { result, success: true }
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
// Create a record tape
|
|
29
|
+
const tape = new RecordTape<{ value: number }, { result: number; success: boolean }, typeof boundaries>()
|
|
30
|
+
|
|
31
|
+
// Run the task with safeRun and directly use the logItem
|
|
32
|
+
const [result, error, record] = await task.safeRun({ value: 5 })
|
|
33
|
+
tape.push('test-task', record)
|
|
34
|
+
|
|
35
|
+
// Verify the execution was successful
|
|
36
|
+
expect(error).toBeNull()
|
|
37
|
+
expect(result).toEqual({ result: 10, success: true })
|
|
38
|
+
|
|
39
|
+
// Get the recorded log from the tape
|
|
40
|
+
const recordedLog = tape.getLog()
|
|
41
|
+
|
|
42
|
+
// Verify the log was recorded correctly
|
|
43
|
+
expect(recordedLog).toHaveLength(1)
|
|
44
|
+
|
|
45
|
+
const logItem = recordedLog[0]
|
|
46
|
+
expect(logItem.name).toEqual('test-task')
|
|
47
|
+
expect(logItem.type).toEqual('success')
|
|
48
|
+
expect(logItem.input).toEqual({ value: 5 })
|
|
49
|
+
expect(logItem.output).toEqual({ result: 10, success: true })
|
|
50
|
+
expect(logItem.boundaries).toEqual({
|
|
51
|
+
fetchData: [{
|
|
52
|
+
input: [5],
|
|
53
|
+
output: 10,
|
|
54
|
+
error: null
|
|
55
|
+
}]
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should record log items from safeRun successfully', async () => {
|
|
60
|
+
// Create a schema
|
|
61
|
+
const schema = new Schema({
|
|
62
|
+
value: Schema.number()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// Define the boundaries
|
|
66
|
+
const boundaries = {
|
|
67
|
+
fetchData: async (value: number): Promise<number> => {
|
|
68
|
+
return value * 2
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Create the task
|
|
73
|
+
const task = createTask(
|
|
74
|
+
schema,
|
|
75
|
+
boundaries,
|
|
76
|
+
async function ({ value }, { fetchData }) {
|
|
77
|
+
const result = await fetchData(value)
|
|
78
|
+
return { result, success: true }
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
// Create a record tape
|
|
83
|
+
const tape = new RecordTape<{ value: number }, { result: number; success: boolean }, typeof boundaries>()
|
|
84
|
+
|
|
85
|
+
// Add listener to record the log items
|
|
86
|
+
task.addListener((record: TaskRecord<{ value: number }, { result: number; success: boolean }>) => {
|
|
87
|
+
// Manually ensure boundary records have error field for consistency with safeRun
|
|
88
|
+
if (record.boundaries && record.boundaries.fetchData && Array.isArray(record.boundaries.fetchData)) {
|
|
89
|
+
record.boundaries.fetchData = record.boundaries.fetchData.map((entry: Record<string, unknown>) => ({
|
|
90
|
+
...entry,
|
|
91
|
+
error: entry.error ?? null,
|
|
92
|
+
output: entry.output ?? null
|
|
93
|
+
}))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Cast the record to LogItem type to satisfy TypeScript
|
|
97
|
+
tape.addLogItem('test-task', record as unknown as LogItem<{ value: number }, { result: number; success: boolean }>)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// Run the task with safeRun
|
|
101
|
+
const [result, error] = await task.safeRun({ value: 5 })
|
|
102
|
+
|
|
103
|
+
// Verify the execution was successful
|
|
104
|
+
expect(error).toBeNull()
|
|
105
|
+
expect(result).toEqual({ result: 10, success: true })
|
|
106
|
+
|
|
107
|
+
// Get the recorded log from the tape
|
|
108
|
+
const recordedLog = tape.getLog()
|
|
109
|
+
|
|
110
|
+
// Verify the log was recorded correctly
|
|
111
|
+
expect(recordedLog).toHaveLength(1)
|
|
112
|
+
expect(recordedLog[0]).toEqual({
|
|
113
|
+
name: 'test-task',
|
|
114
|
+
type: 'success',
|
|
115
|
+
input: { value: 5 },
|
|
116
|
+
output: { result: 10, success: true },
|
|
117
|
+
boundaries: {
|
|
118
|
+
fetchData: [{
|
|
119
|
+
input: [5],
|
|
120
|
+
output: 10,
|
|
121
|
+
error: null
|
|
122
|
+
}]
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('should record error log items from safeRun', async () => {
|
|
128
|
+
// Create a schema
|
|
129
|
+
const schema = new Schema({
|
|
130
|
+
value: Schema.number()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
// Define the boundaries with a function that will throw an error
|
|
134
|
+
const boundaries = {
|
|
135
|
+
fetchData: async (value: number): Promise<number> => {
|
|
136
|
+
if (value < 0) {
|
|
137
|
+
throw new Error('Value cannot be negative')
|
|
138
|
+
}
|
|
139
|
+
return value * 2
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Create the task
|
|
144
|
+
const task = createTask(
|
|
145
|
+
schema,
|
|
146
|
+
boundaries,
|
|
147
|
+
async function ({ value }, { fetchData }) {
|
|
148
|
+
const result = await fetchData(value)
|
|
149
|
+
return { result, success: true }
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
// Create a record tape
|
|
154
|
+
const tape = new RecordTape<{ value: number }, { result: number; success: boolean }, typeof boundaries>()
|
|
155
|
+
|
|
156
|
+
// Add listener to record the log items
|
|
157
|
+
task.addListener((record: TaskRecord<{ value: number }, { result: number; success: boolean }>) => {
|
|
158
|
+
// Manually ensure boundary records have error field for consistency with safeRun
|
|
159
|
+
if (record.boundaries && record.boundaries.fetchData && Array.isArray(record.boundaries.fetchData)) {
|
|
160
|
+
record.boundaries.fetchData = record.boundaries.fetchData.map((entry: Record<string, unknown>) => ({
|
|
161
|
+
...entry,
|
|
162
|
+
error: entry.error ?? null,
|
|
163
|
+
output: entry.output ?? null
|
|
164
|
+
}))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Cast the record to LogItem type to satisfy TypeScript
|
|
168
|
+
tape.addLogItem('test-task', record as unknown as LogItem<{ value: number }, { result: number; success: boolean }>)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// Run the task with safeRun with a value that will cause an error
|
|
172
|
+
const [result, error] = await task.safeRun({ value: -5 })
|
|
173
|
+
|
|
174
|
+
// Verify the execution failed as expected
|
|
175
|
+
expect(result).toBeNull()
|
|
176
|
+
expect(error).not.toBeNull()
|
|
177
|
+
expect(error?.message).toContain('Value cannot be negative')
|
|
178
|
+
|
|
179
|
+
// Get the recorded log from the tape
|
|
180
|
+
const recordedLog = tape.getLog()
|
|
181
|
+
|
|
182
|
+
// Verify the error log was recorded correctly
|
|
183
|
+
expect(recordedLog).toHaveLength(1)
|
|
184
|
+
expect(recordedLog[0]).toEqual({
|
|
185
|
+
name: 'test-task',
|
|
186
|
+
type: 'error',
|
|
187
|
+
input: { value: -5 },
|
|
188
|
+
error: 'Value cannot be negative',
|
|
189
|
+
boundaries: {
|
|
190
|
+
fetchData: [{
|
|
191
|
+
input: [-5],
|
|
192
|
+
output: null,
|
|
193
|
+
error: 'Value cannot be negative'
|
|
194
|
+
}]
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it('should handle error records directly with push', async () => {
|
|
200
|
+
// Create a schema
|
|
201
|
+
const schema = new Schema({
|
|
202
|
+
value: Schema.number()
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
// Define the boundaries with a function that will throw an error
|
|
206
|
+
const boundaries = {
|
|
207
|
+
fetchData: async (value: number): Promise<number> => {
|
|
208
|
+
if (value < 0) {
|
|
209
|
+
throw new Error('Value cannot be negative')
|
|
210
|
+
}
|
|
211
|
+
return value * 2
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Create the task
|
|
216
|
+
const task = createTask(
|
|
217
|
+
schema,
|
|
218
|
+
boundaries,
|
|
219
|
+
async function ({ value }, { fetchData }) {
|
|
220
|
+
const result = await fetchData(value)
|
|
221
|
+
return { result, success: true }
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
// Create a record tape
|
|
226
|
+
const tape = new RecordTape<{ value: number }, { result: number; success: boolean }, typeof boundaries>()
|
|
227
|
+
|
|
228
|
+
// Run the task with safeRun with a value that will cause an error
|
|
229
|
+
const [result, error, record] = await task.safeRun({ value: -5 })
|
|
230
|
+
|
|
231
|
+
// Push the error record directly with type parameter
|
|
232
|
+
tape.push('test-error', record)
|
|
233
|
+
|
|
234
|
+
// Verify the execution failed as expected
|
|
235
|
+
expect(result).toBeNull()
|
|
236
|
+
expect(error).not.toBeNull()
|
|
237
|
+
expect(error instanceof Error).toBe(true)
|
|
238
|
+
if (error instanceof Error) {
|
|
239
|
+
expect(error.message).toContain('Value cannot be negative')
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Get the recorded log from the tape
|
|
243
|
+
const recordedLog = tape.getLog()
|
|
244
|
+
|
|
245
|
+
// Verify the error log was recorded correctly
|
|
246
|
+
expect(recordedLog).toHaveLength(1)
|
|
247
|
+
expect(recordedLog[0]).toEqual({
|
|
248
|
+
name: 'test-error',
|
|
249
|
+
type: 'error',
|
|
250
|
+
input: { value: -5 },
|
|
251
|
+
error: 'Value cannot be negative',
|
|
252
|
+
boundaries: {
|
|
253
|
+
fetchData: [{
|
|
254
|
+
input: [-5],
|
|
255
|
+
output: null,
|
|
256
|
+
error: 'Value cannot be negative'
|
|
257
|
+
}]
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('should handle custom execution records with push', async () => {
|
|
263
|
+
// Create a record tape
|
|
264
|
+
const tape = new RecordTape<{ value: number }, { result: number }, { fetchData: (n: number) => Promise<number> }>()
|
|
265
|
+
|
|
266
|
+
// Create a custom execution record
|
|
267
|
+
const customRecord: ExecutionRecord<{ value: number }, { result: number }, { fetchData: (n: number) => Promise<number> }> = {
|
|
268
|
+
input: { value: 10 },
|
|
269
|
+
output: { result: 20 },
|
|
270
|
+
boundaries: {
|
|
271
|
+
fetchData: [
|
|
272
|
+
{
|
|
273
|
+
input: [10],
|
|
274
|
+
output: 20,
|
|
275
|
+
error: null
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Push the custom record
|
|
282
|
+
tape.push('custom-record', customRecord)
|
|
283
|
+
|
|
284
|
+
// Get the recorded log from the tape
|
|
285
|
+
const recordedLog = tape.getLog()
|
|
286
|
+
|
|
287
|
+
// Verify the log was recorded correctly
|
|
288
|
+
expect(recordedLog).toHaveLength(1)
|
|
289
|
+
expect(recordedLog[0]).toEqual({
|
|
290
|
+
name: 'custom-record',
|
|
291
|
+
type: 'success',
|
|
292
|
+
input: { value: 10 },
|
|
293
|
+
output: { result: 20 },
|
|
294
|
+
boundaries: {
|
|
295
|
+
fetchData: [{
|
|
296
|
+
input: [10],
|
|
297
|
+
output: 20,
|
|
298
|
+
error: null
|
|
299
|
+
}]
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it('should handle execution records with Promise outputs correctly', async () => {
|
|
305
|
+
// Create a record tape
|
|
306
|
+
const tape = new RecordTape<{ value: number }, { result: number }, { fetchData: (n: number) => Promise<number> }>()
|
|
307
|
+
|
|
308
|
+
// Create a custom execution record with a Promise output
|
|
309
|
+
const promiseResult = Promise.resolve({ result: 30 })
|
|
310
|
+
const promiseRecord: ExecutionRecord<{ value: number }, Promise<{ result: number }>, { fetchData: (n: number) => Promise<number> }> = {
|
|
311
|
+
input: { value: 15 },
|
|
312
|
+
output: promiseResult,
|
|
313
|
+
boundaries: {
|
|
314
|
+
fetchData: [
|
|
315
|
+
{
|
|
316
|
+
input: [15],
|
|
317
|
+
output: 30,
|
|
318
|
+
error: null
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Push the record with Promise output using type parameter
|
|
325
|
+
tape.push('promise-record', promiseRecord)
|
|
326
|
+
|
|
327
|
+
// Get the recorded log from the tape
|
|
328
|
+
const recordedLog = tape.getLog()
|
|
329
|
+
|
|
330
|
+
// Verify the log was recorded correctly, with Promise output set to null
|
|
331
|
+
expect(recordedLog).toHaveLength(1)
|
|
332
|
+
expect(recordedLog[0]).toEqual({
|
|
333
|
+
name: 'promise-record',
|
|
334
|
+
type: 'success',
|
|
335
|
+
input: { value: 15 },
|
|
336
|
+
output: null, // Promise output should be set to null
|
|
337
|
+
boundaries: {
|
|
338
|
+
fetchData: [{
|
|
339
|
+
input: [15],
|
|
340
|
+
output: 30,
|
|
341
|
+
error: null
|
|
342
|
+
}]
|
|
343
|
+
}
|
|
344
|
+
})
|
|
345
|
+
})
|
|
346
|
+
})
|