@forgehive/record-tape 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +385 -0
- package/dist/index.d.ts +10 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -63
- package/dist/index.js.map +1 -1
- package/dist/tests/data-methods.test.d.ts +2 -0
- package/dist/tests/data-methods.test.d.ts.map +1 -0
- package/dist/tests/data-methods.test.js +129 -0
- package/dist/tests/data-methods.test.js.map +1 -0
- package/dist/tests/index.test.js +2 -2
- package/dist/tests/index.test.js.map +1 -1
- package/dist/tests/log-format.test.js +8 -8
- package/dist/tests/log-format.test.js.map +1 -1
- package/dist/tests/safe-run.test.js +104 -265
- package/dist/tests/safe-run.test.js.map +1 -1
- package/dist/tests/save.test.js +13 -13
- package/dist/tests/save.test.js.map +1 -1
- package/dist/tests/task-listener.test.js +21 -31
- package/dist/tests/task-listener.test.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +20 -88
- package/src/tests/data-methods.test.ts +150 -0
- package/src/tests/index.test.ts +3 -8
- package/src/tests/log-format.test.ts +8 -8
- package/src/tests/safe-run.test.ts +108 -296
- package/src/tests/save.test.ts +13 -13
- package/src/tests/task-listener.test.ts +22 -41
- package/src/tests/mode.test.ts +0 -106
package/README.md
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# @forgehive/record-tape
|
|
2
|
+
|
|
3
|
+
A lightweight TypeScript library for recording and persisting task execution logs with boundary data support. Works generically with any task type without requiring compile-time type knowledge.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎯 **Simple API**: Clean, minimal interface for recording execution data
|
|
8
|
+
- 📝 **Automatic Logging**: Seamless integration with task execution
|
|
9
|
+
- 💾 **Persistence**: Save and load execution logs to/from files
|
|
10
|
+
- 🔄 **Serialization**: Built-in JSON serialization support
|
|
11
|
+
- 🎨 **TypeScript**: Full type safety with generics
|
|
12
|
+
- 🚀 **Boundary Support**: Record external API calls and dependencies
|
|
13
|
+
- 🔧 **Generic Design**: Works with any task type without compile-time type requirements
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @forgehive/record-tape
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { RecordTape } from '@forgehive/record-tape'
|
|
25
|
+
import { createTask, Schema } from '@forgehive/task'
|
|
26
|
+
|
|
27
|
+
// Create a new recording tape
|
|
28
|
+
const tape = new RecordTape({ path: 'logs/execution' })
|
|
29
|
+
|
|
30
|
+
// Create a simple task
|
|
31
|
+
const getUserTask = createTask({
|
|
32
|
+
name: 'getUserById',
|
|
33
|
+
schema: Schema.object({
|
|
34
|
+
userId: Schema.number()
|
|
35
|
+
}),
|
|
36
|
+
boundaries: {},
|
|
37
|
+
fn: async function getUserById({ userId }) {
|
|
38
|
+
// Simulate getting user data
|
|
39
|
+
return { name: 'John Doe', email: 'john@example.com' }
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Execute the task - safeRun returns result, error, and execution record
|
|
44
|
+
const [result, error, executionRecord] = await getUserTask.safeRun({ userId: 123 })
|
|
45
|
+
|
|
46
|
+
// Manually record the execution to the tape
|
|
47
|
+
tape.push(executionRecord)
|
|
48
|
+
|
|
49
|
+
// Save recorded data to file
|
|
50
|
+
await tape.save()
|
|
51
|
+
|
|
52
|
+
// Optional: View what was recorded
|
|
53
|
+
console.log('Recorded logs:', tape.getLog())
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API Reference
|
|
57
|
+
|
|
58
|
+
### Constructor
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
new RecordTape<TInput, TOutput, B>(config?: Config)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Parameters:**
|
|
65
|
+
- `config.path?` - File path for persistence (will append `.log` extension)
|
|
66
|
+
- `config.log?` - Pre-existing log records to initialize with
|
|
67
|
+
- `config.boundaries?` - Initial boundary data
|
|
68
|
+
|
|
69
|
+
### Core Methods
|
|
70
|
+
|
|
71
|
+
#### `getLog()`
|
|
72
|
+
Get all recorded execution logs.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const logs = tape.getLog()
|
|
76
|
+
// Returns: GenericExecutionRecord<TInput, TOutput, B>[]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### `getLength()`
|
|
80
|
+
Get the number of records in the tape.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const count = tape.getLength()
|
|
84
|
+
// Returns: number
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### `shift()`
|
|
88
|
+
Remove and return the first record from the tape.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const firstRecord = tape.shift()
|
|
92
|
+
// Returns: GenericExecutionRecord<TInput, TOutput, B> | undefined
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### `push(record, metadata?)`
|
|
96
|
+
Add a new execution record to the tape.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
const logRecord = tape.push(executionRecord, { userId: '123' })
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Parameters:**
|
|
103
|
+
- `record` - ExecutionRecord with input, output, taskName, boundaries, etc.
|
|
104
|
+
- `metadata?` - Optional additional metadata to attach
|
|
105
|
+
|
|
106
|
+
**Returns:** The created GenericExecutionRecord
|
|
107
|
+
|
|
108
|
+
#### `recordFrom(task)`
|
|
109
|
+
Set up automatic recording from a task instance.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
tape.recordFrom(myTask)
|
|
113
|
+
// Now myTask will automatically send execution records to this tape
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Serialization Methods
|
|
117
|
+
|
|
118
|
+
#### `stringify()`
|
|
119
|
+
Convert all logs to a string format (one JSON object per line).
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const logString = tape.stringify()
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### `parse(content)`
|
|
126
|
+
Parse string content back into log records.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const logs = tape.parse(logString)
|
|
130
|
+
// Returns: GenericExecutionRecord<TInput, TOutput, B>[]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Persistence Methods
|
|
134
|
+
|
|
135
|
+
#### `load()` / `loadSync()`
|
|
136
|
+
Load execution logs from file.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Async version
|
|
140
|
+
const logs = await tape.load()
|
|
141
|
+
// Returns: GenericExecutionRecord<TInput, TOutput, B>[]
|
|
142
|
+
|
|
143
|
+
// Sync version
|
|
144
|
+
const logs = tape.loadSync()
|
|
145
|
+
// Returns: GenericExecutionRecord<TInput, TOutput, B>[]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### `save()` / `saveSync()`
|
|
149
|
+
Save execution logs to file.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// Async version
|
|
153
|
+
await tape.save()
|
|
154
|
+
|
|
155
|
+
// Sync version
|
|
156
|
+
tape.saveSync()
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Utility Methods
|
|
160
|
+
|
|
161
|
+
#### `compileCache()`
|
|
162
|
+
Compile boundary data from all logs into a cache structure.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const boundaryCache = tape.compileCache()
|
|
166
|
+
// Returns: Record<string, unknown>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Types
|
|
170
|
+
|
|
171
|
+
### GenericExecutionRecord
|
|
172
|
+
A generic version of ExecutionRecord that can store execution data from any task without knowing the specific types at compile time:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
interface GenericExecutionRecord<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> extends ExecutionRecord<TInput, TOutput, B> {
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The "Generic" prefix indicates that RecordTape can store logs from different tasks with varying input/output types. The default type parameters (`unknown`) allow the tape to work with any task execution without requiring specific type knowledge.
|
|
180
|
+
|
|
181
|
+
**Why Generic?**
|
|
182
|
+
- **Mixed Task Logs**: Store logs from multiple different tasks in the same tape
|
|
183
|
+
- **Runtime Flexibility**: Add logs without knowing task types at compile time
|
|
184
|
+
- **Type Safety**: Still maintains TypeScript type safety when types are known
|
|
185
|
+
|
|
186
|
+
### ExecutionRecord
|
|
187
|
+
Core execution data structure:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
interface ExecutionRecord<TInput, TOutput, B extends Boundaries> {
|
|
191
|
+
input: TInput
|
|
192
|
+
output?: TOutput | null
|
|
193
|
+
error?: string
|
|
194
|
+
boundaries: BoundaryLogsFor<B>
|
|
195
|
+
taskName?: string
|
|
196
|
+
metadata?: Record<string, string>
|
|
197
|
+
type: 'success' | 'error' | 'pending'
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Usage Examples
|
|
202
|
+
|
|
203
|
+
### Basic Recording
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { RecordTape } from '@forgehive/record-tape'
|
|
207
|
+
|
|
208
|
+
const tape = new RecordTape({ path: 'logs/user-service' })
|
|
209
|
+
|
|
210
|
+
// Record a successful execution
|
|
211
|
+
tape.push({
|
|
212
|
+
input: { userId: 123 },
|
|
213
|
+
output: { name: 'John Doe', email: 'john@example.com' },
|
|
214
|
+
taskName: 'getUser',
|
|
215
|
+
boundaries: {},
|
|
216
|
+
type: 'success'
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
// Record an error
|
|
220
|
+
tape.push({
|
|
221
|
+
input: { userId: 999 },
|
|
222
|
+
error: 'User not found',
|
|
223
|
+
taskName: 'getUser',
|
|
224
|
+
boundaries: {},
|
|
225
|
+
type: 'error'
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
await tape.save()
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Queue-like Processing
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { RecordTape } from '@forgehive/record-tape'
|
|
235
|
+
|
|
236
|
+
const tape = new RecordTape({ path: 'logs/processing-queue' })
|
|
237
|
+
|
|
238
|
+
// Add several records
|
|
239
|
+
tape.push({
|
|
240
|
+
input: { task: 'process-order-1' },
|
|
241
|
+
output: { status: 'completed' },
|
|
242
|
+
taskName: 'processOrder',
|
|
243
|
+
boundaries: {},
|
|
244
|
+
type: 'success'
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
tape.push({
|
|
248
|
+
input: { task: 'process-order-2' },
|
|
249
|
+
output: { status: 'completed' },
|
|
250
|
+
taskName: 'processOrder',
|
|
251
|
+
boundaries: {},
|
|
252
|
+
type: 'success'
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
// Check how many records we have
|
|
256
|
+
console.log(`Total records: ${tape.getLength()}`) // 2
|
|
257
|
+
|
|
258
|
+
// Process records in FIFO order
|
|
259
|
+
while (tape.getLength() > 0) {
|
|
260
|
+
const record = tape.shift()
|
|
261
|
+
console.log(`Processing: ${record?.input.task}`)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.log(`Remaining records: ${tape.getLength()}`) // 0
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### With Boundary Data
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
const tape = new RecordTape({ path: 'logs/api-calls' })
|
|
271
|
+
|
|
272
|
+
tape.push({
|
|
273
|
+
input: { query: 'nodejs' },
|
|
274
|
+
output: { results: ['result1', 'result2'] },
|
|
275
|
+
taskName: 'searchRepositories',
|
|
276
|
+
boundaries: {
|
|
277
|
+
githubAPI: [
|
|
278
|
+
{
|
|
279
|
+
input: ['/search/repositories?q=nodejs'],
|
|
280
|
+
output: { data: ['repo1', 'repo2'] },
|
|
281
|
+
error: null
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
type: 'success'
|
|
286
|
+
})
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Task Integration
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { Task } from '@forgehive/task'
|
|
293
|
+
import { RecordTape } from '@forgehive/record-tape'
|
|
294
|
+
|
|
295
|
+
const tape = new RecordTape({ path: 'logs/my-task' })
|
|
296
|
+
const myTask = new Task(myFunction, { name: 'processData' })
|
|
297
|
+
|
|
298
|
+
// Set up automatic recording
|
|
299
|
+
tape.recordFrom(myTask)
|
|
300
|
+
|
|
301
|
+
// Now all task executions will be recorded
|
|
302
|
+
await myTask.safeRun({ data: 'test' })
|
|
303
|
+
|
|
304
|
+
// Save recorded data
|
|
305
|
+
await tape.save()
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Loading and Analyzing Logs
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
const tape = new RecordTape({ path: 'logs/analysis' })
|
|
312
|
+
|
|
313
|
+
// Load existing logs
|
|
314
|
+
const logs = await tape.load()
|
|
315
|
+
|
|
316
|
+
// Analyze execution patterns
|
|
317
|
+
const successCount = logs.filter(log => log.type === 'success').length
|
|
318
|
+
const errorCount = logs.filter(log => log.type === 'error').length
|
|
319
|
+
|
|
320
|
+
console.log(`Success rate: ${(successCount / logs.length * 100).toFixed(1)}%`)
|
|
321
|
+
|
|
322
|
+
// Compile boundary cache for replay
|
|
323
|
+
const boundaryCache = tape.compileCache()
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### File Format
|
|
327
|
+
|
|
328
|
+
The tape saves logs in a simple text format with one JSON object per line:
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
{"input":{"userId":123},"output":{"name":"John"},"type":"success","boundaries":{},"metadata":{},"taskName":"getUser"}
|
|
332
|
+
{"input":{"userId":999},"error":"User not found","type":"error","boundaries":{},"metadata":{},"taskName":"getUser"}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Advanced Usage
|
|
336
|
+
|
|
337
|
+
### Custom Metadata
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
tape.push(executionRecord, {
|
|
341
|
+
requestId: 'req-123',
|
|
342
|
+
userAgent: 'MyApp/1.0',
|
|
343
|
+
timestamp: new Date().toISOString()
|
|
344
|
+
})
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Boundary Cache Compilation
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
// After recording multiple executions with boundary data
|
|
351
|
+
const cache = tape.compileCache()
|
|
352
|
+
|
|
353
|
+
// Use cache for task replay
|
|
354
|
+
const replayTask = new Task(myFunction, {
|
|
355
|
+
boundariesData: cache
|
|
356
|
+
})
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Migration Guide
|
|
360
|
+
|
|
361
|
+
### Recent API Changes
|
|
362
|
+
|
|
363
|
+
**Interface Rename**: `LogRecord` → `GenericExecutionRecord`
|
|
364
|
+
- The main interface has been renamed to better reflect its generic nature
|
|
365
|
+
- All method signatures now use `GenericExecutionRecord`
|
|
366
|
+
- The "Generic" prefix indicates the tape can store logs from different task types
|
|
367
|
+
|
|
368
|
+
**Simplified API**:
|
|
369
|
+
- Removed deprecated `setMode()`, `getMode()`, `addLogRecord()`, `addExecutionRecord()` methods
|
|
370
|
+
- Simplified `push()` method with automatic type inference
|
|
371
|
+
- Removed redundant `name` field (use `taskName` instead)
|
|
372
|
+
|
|
373
|
+
**New Queue Methods**:
|
|
374
|
+
- Added `getLength()` - returns number of records
|
|
375
|
+
- Added `shift()` - removes and returns first record (FIFO)
|
|
376
|
+
- These enable efficient log management and processing
|
|
377
|
+
|
|
378
|
+
**Task Integration**:
|
|
379
|
+
- Direct ExecutionRecord compatibility with Task package
|
|
380
|
+
- Simplified listener setup with automatic record forwarding
|
|
381
|
+
- No conversion needed between task records and tape records
|
|
382
|
+
|
|
383
|
+
## License
|
|
384
|
+
|
|
385
|
+
MIT License - see LICENSE file for details.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import { type ExecutionRecord, type Boundaries } from '@forgehive/task';
|
|
3
|
-
export interface
|
|
4
|
-
name: string;
|
|
3
|
+
export interface GenericExecutionRecord<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> extends ExecutionRecord<TInput, TOutput, B> {
|
|
5
4
|
}
|
|
6
5
|
interface Config<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> {
|
|
7
6
|
path?: fs.PathLike;
|
|
8
|
-
log?:
|
|
7
|
+
log?: GenericExecutionRecord<TInput, TOutput, B>[];
|
|
9
8
|
boundaries?: Record<string, unknown>;
|
|
10
9
|
}
|
|
11
|
-
export type Mode = 'record' | 'replay';
|
|
12
10
|
export declare class RecordTape<TInput = unknown, TOutput = unknown, B extends Boundaries = Boundaries> {
|
|
13
11
|
private _path;
|
|
14
|
-
private _mode;
|
|
15
12
|
private _log;
|
|
16
13
|
constructor(config?: Config<TInput, TOutput, B>);
|
|
17
|
-
getLog():
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
push(name: string, record: ExecutionRecord<TInput, unknown, B>, metadata?: Record<string, string>): LogRecord<TInput, TOutput, B>;
|
|
22
|
-
addLogRecord(logRecord: LogRecord<TInput, TOutput, B>): void;
|
|
14
|
+
getLog(): GenericExecutionRecord<TInput, TOutput, B>[];
|
|
15
|
+
getLength(): number;
|
|
16
|
+
shift(): GenericExecutionRecord<TInput, TOutput, B> | undefined;
|
|
17
|
+
push(record: ExecutionRecord<TInput, unknown, B>, metadata?: Record<string, string>): GenericExecutionRecord<TInput, TOutput, B>;
|
|
23
18
|
stringify(): string;
|
|
24
|
-
parse(content: string):
|
|
19
|
+
parse(content: string): GenericExecutionRecord<TInput, TOutput, B>[];
|
|
25
20
|
compileCache(): Record<string, unknown>;
|
|
26
|
-
recordFrom(
|
|
21
|
+
recordFrom(task: {
|
|
27
22
|
_listener?: unknown;
|
|
28
|
-
setBoundariesData: (data: Record<string, unknown>) => void;
|
|
29
23
|
}): void;
|
|
30
|
-
load(): Promise<
|
|
31
|
-
loadSync():
|
|
24
|
+
load(): Promise<GenericExecutionRecord<TInput, TOutput, B>[]>;
|
|
25
|
+
loadSync(): GenericExecutionRecord<TInput, TOutput, B>[];
|
|
32
26
|
save(): Promise<void>;
|
|
33
27
|
saveSync(): void;
|
|
34
28
|
}
|
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;AAEnB,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEvE,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAA;AAEnB,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEvE,MAAM,WAAW,sBAAsB,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC,SAAS,UAAU,GAAG,UAAU,CAAE,SAAQ,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;CAC1J;AAED,UAAU,MAAM,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC,SAAS,UAAU,GAAG,UAAU;IACrF,IAAI,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAA;IAClB,GAAG,CAAC,EAAE,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAA;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC;AAED,qBAAa,UAAU,CAAC,MAAM,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC,SAAS,UAAU,GAAG,UAAU;IAC5F,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,IAAI,CAA8C;gBAE9C,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAM;IAMnD,MAAM,IAAI,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE;IAItD,SAAS,IAAI,MAAM;IAInB,KAAK,IAAI,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,SAAS;IAI/D,IAAI,CACF,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAoB7C,SAAS,IAAI,MAAM;IASnB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE;IAYpE,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAgBvC,UAAU,CAAC,IAAI,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAQzC,IAAI,IAAI,OAAO,CAAC,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;IA8BnE,QAAQ,IAAI,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE;IAoBlD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,QAAQ,IAAI,IAAI;CAajB"}
|
package/dist/index.js
CHANGED
|
@@ -11,76 +11,28 @@ class RecordTape {
|
|
|
11
11
|
var _a;
|
|
12
12
|
this._path = typeof config.path === 'string' ? `${config.path}.log` : undefined;
|
|
13
13
|
this._log = (_a = config.log) !== null && _a !== void 0 ? _a : [];
|
|
14
|
-
this._mode = 'record';
|
|
15
14
|
}
|
|
16
15
|
// Data functions
|
|
17
16
|
getLog() {
|
|
18
17
|
return this._log;
|
|
19
18
|
}
|
|
20
|
-
|
|
21
|
-
return this.
|
|
19
|
+
getLength() {
|
|
20
|
+
return this._log.length;
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
this.
|
|
22
|
+
shift() {
|
|
23
|
+
return this._log.shift();
|
|
25
24
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
// Format boundaries to ensure consistent structure
|
|
31
|
-
const formattedBoundaries = {};
|
|
32
|
-
if (record.boundaries) {
|
|
33
|
-
for (const key in record.boundaries) {
|
|
34
|
-
const boundaryEntries = record.boundaries[key];
|
|
35
|
-
formattedBoundaries[key] = boundaryEntries.map(entry => {
|
|
36
|
-
var _a, _b;
|
|
37
|
-
return ({
|
|
38
|
-
input: entry.input,
|
|
39
|
-
output: (_a = entry.output) !== null && _a !== void 0 ? _a : null,
|
|
40
|
-
error: (_b = entry.error) !== null && _b !== void 0 ? _b : null
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
this._log.push(Object.assign(Object.assign({ name }, record), { boundaries: formattedBoundaries }));
|
|
46
|
-
}
|
|
47
|
-
push(name, record, metadata) {
|
|
48
|
-
if (this._mode === 'replay') {
|
|
49
|
-
return {};
|
|
50
|
-
}
|
|
51
|
-
// For safeRun records, always include both error and output fields
|
|
52
|
-
const formattedBoundaries = {};
|
|
53
|
-
if (record.boundaries) {
|
|
54
|
-
for (const key in record.boundaries) {
|
|
55
|
-
const boundaryArray = record.boundaries[key];
|
|
56
|
-
formattedBoundaries[key] = boundaryArray.map(entry => {
|
|
57
|
-
var _a, _b;
|
|
58
|
-
return {
|
|
59
|
-
input: entry.input,
|
|
60
|
-
output: (_a = entry.output) !== null && _a !== void 0 ? _a : null,
|
|
61
|
-
error: (_b = entry.error) !== null && _b !== void 0 ? _b : null
|
|
62
|
-
};
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// Use the type from ExecutionRecord if available, otherwise derive it
|
|
25
|
+
push(record, metadata) {
|
|
26
|
+
// Add type if missing
|
|
67
27
|
const recordType = ('type' in record && record.type) ? record.type :
|
|
68
28
|
(record.output !== undefined && record.output !== null) ? 'success' :
|
|
69
29
|
(record.error !== undefined) ? 'error' : 'pending';
|
|
70
|
-
// Handle Promise outputs by setting to null in the log
|
|
71
|
-
const output = record.output instanceof Promise ? null : record.output;
|
|
72
30
|
// Merge metadata from record and parameter (parameter takes precedence)
|
|
73
31
|
const mergedMetadata = Object.assign(Object.assign({}, record.metadata), metadata);
|
|
74
|
-
const logRecord = Object.assign(Object.assign({
|
|
32
|
+
const logRecord = Object.assign(Object.assign({}, record), { type: recordType, metadata: mergedMetadata });
|
|
75
33
|
this._log.push(logRecord);
|
|
76
34
|
return logRecord;
|
|
77
35
|
}
|
|
78
|
-
addLogRecord(logRecord) {
|
|
79
|
-
if (this._mode === 'replay') {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
this._log.push(logRecord);
|
|
83
|
-
}
|
|
84
36
|
stringify() {
|
|
85
37
|
let log = '';
|
|
86
38
|
for (const logItem of this._log) {
|
|
@@ -116,16 +68,11 @@ class RecordTape {
|
|
|
116
68
|
}
|
|
117
69
|
return cache;
|
|
118
70
|
}
|
|
119
|
-
recordFrom(
|
|
71
|
+
recordFrom(task) {
|
|
120
72
|
// Add listener for ExecutionRecord
|
|
121
|
-
task._listener = async (executionRecord
|
|
122
|
-
|
|
123
|
-
if (this.getMode() === 'record') {
|
|
124
|
-
this.addExecutionRecord(name, executionRecord);
|
|
125
|
-
}
|
|
73
|
+
task._listener = async (executionRecord) => {
|
|
74
|
+
this.push(executionRecord);
|
|
126
75
|
};
|
|
127
|
-
// Add cache
|
|
128
|
-
task.setBoundariesData(this.compileCache());
|
|
129
76
|
}
|
|
130
77
|
// Load save functions
|
|
131
78
|
async load() {
|
|
@@ -174,6 +121,7 @@ class RecordTape {
|
|
|
174
121
|
this._log = this.parse(content);
|
|
175
122
|
return this._log;
|
|
176
123
|
}
|
|
124
|
+
// Save functions
|
|
177
125
|
async save() {
|
|
178
126
|
if (typeof this._path === 'undefined') {
|
|
179
127
|
return;
|
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":"data-methods.test.d.ts","sourceRoot":"","sources":["../../src/tests/data-methods.test.ts"],"names":[],"mappings":""}
|