jspurefix 5.9.1 → 5.9.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.
Files changed (94) hide show
  1. package/BACKPORT_PLAN.md +20 -7
  2. package/WORKLOG.md +119 -0
  3. package/dist/benchmark/bench-report.d.ts +5 -0
  4. package/dist/benchmark/bench-report.js +91 -0
  5. package/dist/benchmark/bench-report.js.map +1 -0
  6. package/dist/benchmark/bench-runner.d.ts +12 -0
  7. package/dist/benchmark/bench-runner.js +193 -0
  8. package/dist/benchmark/bench-runner.js.map +1 -0
  9. package/dist/benchmark/bench-stats.d.ts +10 -0
  10. package/dist/benchmark/bench-stats.js +56 -0
  11. package/dist/benchmark/bench-stats.js.map +1 -0
  12. package/dist/benchmark/bench-types.d.ts +74 -0
  13. package/dist/benchmark/bench-types.js +3 -0
  14. package/dist/benchmark/bench-types.js.map +1 -0
  15. package/dist/benchmark/gc-probe.d.ts +18 -0
  16. package/dist/benchmark/gc-probe.js +103 -0
  17. package/dist/benchmark/gc-probe.js.map +1 -0
  18. package/dist/benchmark/index.d.ts +6 -0
  19. package/dist/benchmark/index.js +23 -0
  20. package/dist/benchmark/index.js.map +1 -0
  21. package/dist/benchmark/parse-bench.d.ts +28 -0
  22. package/dist/benchmark/parse-bench.js +85 -0
  23. package/dist/benchmark/parse-bench.js.map +1 -0
  24. package/dist/buffer/ascii/ascii-parser.d.ts +1 -0
  25. package/dist/buffer/ascii/ascii-parser.js +4 -1
  26. package/dist/buffer/ascii/ascii-parser.js.map +1 -1
  27. package/dist/buffer/ascii/ascii-segment-parser.js +3 -2
  28. package/dist/buffer/ascii/ascii-segment-parser.js.map +1 -1
  29. package/dist/buffer/ascii/tag-index.js.map +1 -1
  30. package/dist/buffer/msg-view.d.ts +1 -0
  31. package/dist/buffer/msg-view.js +25 -19
  32. package/dist/buffer/msg-view.js.map +1 -1
  33. package/dist/dictionary/parser/quickfix/dictionary-validator.d.ts +1 -1
  34. package/dist/dictionary/parser/quickfix/dictionary-validator.js.map +1 -1
  35. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.d.ts +1 -1
  36. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.js +1 -2
  37. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.js.map +1 -1
  38. package/dist/dictionary/parser/quickfix/validation-error.d.ts +2 -2
  39. package/dist/dictionary/parser/quickfix/validation-error.js.map +1 -1
  40. package/dist/jsfix-bench.d.ts +1 -0
  41. package/dist/jsfix-bench.js +213 -0
  42. package/dist/jsfix-bench.js.map +1 -0
  43. package/dist/store/file-session-store.js +1 -1
  44. package/dist/store/file-session-store.js.map +1 -1
  45. package/dist/store/file-session-stream-provider.d.ts +1 -0
  46. package/dist/store/file-session-stream-provider.js +13 -13
  47. package/dist/store/file-session-stream-provider.js.map +1 -1
  48. package/dist/store/fix-session-store-factory.d.ts +1 -1
  49. package/dist/store/fix-session-store-factory.js.map +1 -1
  50. package/dist/store/fix-session-store.d.ts +11 -11
  51. package/dist/store/fix-session-store.js.map +1 -1
  52. package/dist/store/memory-session-store.js.map +1 -1
  53. package/dist/store/session-stream-provider.d.ts +13 -13
  54. package/dist/store/session-stream-provider.js.map +1 -1
  55. package/dist/transport/session/fix-clock.d.ts +1 -1
  56. package/dist/transport/session/fix-clock.js.map +1 -1
  57. package/dist/transport/session/resend-request-manager.d.ts +2 -2
  58. package/dist/transport/session/resend-request-manager.js.map +1 -1
  59. package/dist/transport/session/session-sequence-coordinator.d.ts +1 -1
  60. package/dist/transport/session/session-sequence-coordinator.js.map +1 -1
  61. package/dist/transport/session/session-sequence-store.d.ts +3 -3
  62. package/dist/transport/session/session-sequence-store.js.map +1 -1
  63. package/dist/transport/tcp/tcp-initiator.js.map +1 -1
  64. package/docs/benchmarking.md +117 -0
  65. package/eslint.config.mjs +15 -1
  66. package/jsfix.test_client.txt +62 -62
  67. package/jsfix.test_server.txt +72 -72
  68. package/package.json +9 -1
  69. package/src/benchmark/bench-report.ts +101 -0
  70. package/src/benchmark/bench-runner.ts +196 -0
  71. package/src/benchmark/bench-stats.ts +86 -0
  72. package/src/benchmark/bench-types.ts +110 -0
  73. package/src/benchmark/gc-probe.ts +145 -0
  74. package/src/benchmark/index.ts +6 -0
  75. package/src/benchmark/parse-bench.ts +144 -0
  76. package/src/buffer/ascii/ascii-parser.ts +16 -1
  77. package/src/buffer/ascii/ascii-segment-parser.ts +9 -6
  78. package/src/buffer/ascii/tag-index.ts +3 -3
  79. package/src/buffer/msg-view.ts +35 -18
  80. package/src/dictionary/parser/quickfix/dictionary-validator.ts +1 -1
  81. package/src/dictionary/parser/quickfix/quick-fix-graph-parser.ts +2 -3
  82. package/src/dictionary/parser/quickfix/validation-error.ts +1 -1
  83. package/src/jsfix-bench.ts +204 -0
  84. package/src/store/file-session-store.ts +2 -2
  85. package/src/store/file-session-stream-provider.ts +17 -11
  86. package/src/store/fix-session-store-factory.ts +1 -1
  87. package/src/store/fix-session-store.ts +11 -11
  88. package/src/store/memory-session-store.ts +1 -1
  89. package/src/store/session-stream-provider.ts +13 -13
  90. package/src/transport/session/fix-clock.ts +1 -1
  91. package/src/transport/session/resend-request-manager.ts +4 -4
  92. package/src/transport/session/session-sequence-coordinator.ts +1 -1
  93. package/src/transport/session/session-sequence-store.ts +3 -3
  94. package/src/transport/tcp/tcp-initiator.ts +1 -1
@@ -0,0 +1,204 @@
1
+ import 'reflect-metadata'
2
+
3
+ import * as path from 'path'
4
+ import * as fs from 'fs'
5
+ import minimist = require('minimist')
6
+ import buildOptions from 'minimist-options'
7
+
8
+ import { AsciiChars } from './buffer/ascii'
9
+ import { IJsFixConfig } from './config'
10
+ import { DefinitionFactory } from './util'
11
+ import { SessionContainer } from './runtime'
12
+ import { DITokens } from './runtime/di-tokens'
13
+ import {
14
+ BenchRunner,
15
+ IBenchCase,
16
+ IBenchOptions,
17
+ IBenchSuiteResult,
18
+ ParseCase,
19
+ ParseDepth,
20
+ defaultBenchOptions,
21
+ formatComparison,
22
+ formatSuite
23
+ } from './benchmark'
24
+
25
+ const options = buildOptions({
26
+ dict: {
27
+ type: 'string',
28
+ alias: 'd',
29
+ default: 'qf44'
30
+ },
31
+
32
+ fix: {
33
+ type: 'string',
34
+ alias: 'f',
35
+ default: 'data/examples/FIX.4.4/quickfix/execution-report/fix.txt'
36
+ },
37
+
38
+ session: {
39
+ type: 'string',
40
+ alias: 's',
41
+ default: 'data/session/test-initiator.json'
42
+ },
43
+
44
+ delimiter: {
45
+ type: 'string',
46
+ alias: 'l',
47
+ default: '|'
48
+ },
49
+
50
+ depth: {
51
+ type: 'string',
52
+ default: 'view,object'
53
+ },
54
+
55
+ rounds: {
56
+ type: 'number',
57
+ default: defaultBenchOptions.rounds
58
+ },
59
+
60
+ msgs: {
61
+ type: 'number',
62
+ default: defaultBenchOptions.operationsPerRound
63
+ },
64
+
65
+ warmup: {
66
+ type: 'number',
67
+ default: defaultBenchOptions.warmupOperations
68
+ },
69
+
70
+ label: {
71
+ type: 'string',
72
+ default: 'jspurefix'
73
+ },
74
+
75
+ save: {
76
+ type: 'string'
77
+ },
78
+
79
+ baseline: {
80
+ type: 'string'
81
+ },
82
+
83
+ json: {
84
+ type: 'boolean',
85
+ default: false
86
+ },
87
+
88
+ help: {
89
+ type: 'boolean',
90
+ alias: 'h',
91
+ default: false
92
+ }
93
+ })
94
+
95
+ const argv: any = minimist(process.argv.slice(2), options)
96
+
97
+ const root: string = path.join(__dirname, '../')
98
+
99
+ function norm (p: string): string {
100
+ return path.isAbsolute(p) ? p : path.join(root, p)
101
+ }
102
+
103
+ function usage (): void {
104
+ console.log('measure the parse path and what it costs in time and in garbage')
105
+ console.log()
106
+ console.log(' --fix=<path> fix log to parse, defaults to a 4.4 execution report')
107
+ console.log(' --dict=<name> dictionary, e.g. qf44, repo44, qf50sp2')
108
+ console.log(' --delimiter=<char> field delimiter in the log, defaults to |')
109
+ console.log(' --depth=view,object which stages to measure, comma separated')
110
+ console.log(' --rounds=<n> measured rounds, one sample each')
111
+ console.log(' --msgs=<n> messages per round')
112
+ console.log(' --warmup=<n> messages discarded before measuring')
113
+ console.log(' --save=<path> write the suite to json')
114
+ console.log(' --baseline=<path> compare against a previously saved suite')
115
+ console.log(' --json print the suite as json instead of a report')
116
+ console.log()
117
+ console.log('run under --expose-gc so rounds can be isolated and heap read cleanly:')
118
+ console.log(' node --expose-gc dist/jsfix-bench --fix=data/examples/FIX.4.4/quickfix/execution-report/fix.txt')
119
+ console.log(' npm run bench')
120
+ }
121
+
122
+ async function makeConfig (): Promise<IJsFixConfig> {
123
+ const sys = new SessionContainer()
124
+ sys.registerGlobal('error')
125
+ const sessionDescription = require(norm(argv.session))
126
+ const container = await sys.makeSystem(sessionDescription)
127
+ const config = container.resolve<IJsFixConfig>(DITokens.IJsFixConfig)
128
+ config.definitions = await new DefinitionFactory().getDefinitions(argv.dict)
129
+ // the parser reads the delimiter when it is constructed, so this has to be
130
+ // settled before any case is built
131
+ config.delimiter = AsciiChars.firstChar(argv.delimiter)
132
+ return config
133
+ }
134
+
135
+ function requestedDepths (): ParseDepth[] {
136
+ const known = new Map<string, ParseDepth>([
137
+ ['view', ParseDepth.View],
138
+ ['object', ParseDepth.Object]
139
+ ])
140
+ const asked = String(argv.depth).split(',').map(d => d.trim().toLowerCase()).filter(d => d.length > 0)
141
+ return asked.map(d => {
142
+ const depth = known.get(d)
143
+ if (!depth) {
144
+ throw new Error(`unknown depth ${d}, expected view or object`)
145
+ }
146
+ return depth
147
+ })
148
+ }
149
+
150
+ function readSuite (p: string): IBenchSuiteResult {
151
+ return JSON.parse(fs.readFileSync(norm(p), 'utf8'))
152
+ }
153
+
154
+ async function main (): Promise<void> {
155
+ if (argv.help) {
156
+ usage()
157
+ return
158
+ }
159
+ const fixPath = norm(argv.fix)
160
+ if (!fs.existsSync(fixPath)) {
161
+ throw new Error(`no such fix log ${fixPath}`)
162
+ }
163
+ const contents = fs.readFileSync(fixPath, 'utf8')
164
+ const config = await makeConfig()
165
+
166
+ const cases: ParseCase[] = requestedDepths().map(depth =>
167
+ new ParseCase(`parse:${depth}`, { config, contents, depth }))
168
+
169
+ // every case walks the same input, so one alignment covers the suite and all
170
+ // of them stay directly comparable
171
+ const perInvocation = cases[0].operationsPerInvocation
172
+ const operationsPerRound = cases[0].alignOperations(argv.msgs)
173
+ const benchOptions: IBenchOptions = {
174
+ warmupOperations: cases[0].alignOperations(argv.warmup),
175
+ rounds: argv.rounds,
176
+ operationsPerRound,
177
+ gcBetweenRounds: true
178
+ }
179
+
180
+ console.log(`${path.relative(root, fixPath)} ${perInvocation} msg/pass dict ${argv.dict}`)
181
+ const suite = await new BenchRunner(benchOptions).runAll(argv.label, cases as IBenchCase[])
182
+
183
+ if (argv.json) {
184
+ console.log(JSON.stringify(suite, null, 2))
185
+ } else {
186
+ console.log()
187
+ console.log(formatSuite(suite))
188
+ }
189
+ if (argv.baseline) {
190
+ console.log()
191
+ console.log(formatComparison(readSuite(argv.baseline), suite))
192
+ }
193
+ if (argv.save) {
194
+ const target = norm(argv.save)
195
+ fs.mkdirSync(path.dirname(target), { recursive: true })
196
+ fs.writeFileSync(target, JSON.stringify(suite, null, 2), 'utf8')
197
+ console.log(`saved ${path.relative(root, target)}`)
198
+ }
199
+ }
200
+
201
+ main().catch(e => {
202
+ console.error(e instanceof Error ? e.message : e)
203
+ process.exit(1)
204
+ })
@@ -22,7 +22,7 @@ export class FileSessionStore implements IFixSessionStore {
22
22
  private creationTimeValue: Date = new Date()
23
23
 
24
24
  // In-memory index: seqnum -> { offset, length }
25
- private readonly headerIndex: Map<number, { offset: number, length: number }> = new Map()
25
+ private readonly headerIndex = new Map<number, { offset: number, length: number }>()
26
26
 
27
27
  /**
28
28
  * Creates a FileSessionStore with the default file-based stream provider.
@@ -285,7 +285,7 @@ export class FileSessionStore implements IFixSessionStore {
285
285
  */
286
286
  static parseSessionTime (str: string): Date | null {
287
287
  // Format: YYYYMMDD-HH:MM:SS.ffffff
288
- const match = str.match(/^(\d{4})(\d{2})(\d{2})-(\d{2}):(\d{2}):(\d{2})\.(\d{3,6})$/)
288
+ const match = /^(\d{4})(\d{2})(\d{2})-(\d{2}):(\d{2}):(\d{2})\.(\d{3,6})$/.exec(str)
289
289
  if (!match) return null
290
290
  const [, y, M, d, h, m, s, frac] = match
291
291
  const ms = parseInt(frac.substring(0, 3), 10)
@@ -32,28 +32,34 @@ export class FileSessionStreamProvider implements ISessionStreamProvider {
32
32
  }
33
33
 
34
34
  openBody (): void {
35
- if (this.bodyFd !== null) return
36
- this.bodyFd = fs.openSync(this.bodyPath, 'a+')
37
- const stat = fs.fstatSync(this.bodyFd)
38
- this.bodySize = stat.size
35
+ this.openBodyFd()
39
36
  }
40
37
 
41
- async appendBody (data: Buffer): Promise<number> {
38
+ /**
39
+ * open the body file on first use and hand back the descriptor - returning it
40
+ * keeps callers free of a null check the compiler cannot see through.
41
+ */
42
+ private openBodyFd (): number {
42
43
  if (this.bodyFd === null) {
43
- this.openBody()
44
+ this.bodyFd = fs.openSync(this.bodyPath, 'a+')
45
+ const stat = fs.fstatSync(this.bodyFd)
46
+ this.bodySize = stat.size
44
47
  }
48
+ return this.bodyFd
49
+ }
50
+
51
+ async appendBody (data: Buffer): Promise<number> {
52
+ const fd = this.openBodyFd()
45
53
  const offset = this.bodySize
46
- fs.writeSync(this.bodyFd!, data, 0, data.length, offset)
54
+ fs.writeSync(fd, data, 0, data.length, offset)
47
55
  this.bodySize += data.length
48
56
  return offset
49
57
  }
50
58
 
51
59
  async readBody (offset: number, length: number): Promise<Buffer> {
52
- if (this.bodyFd === null) {
53
- this.openBody()
54
- }
60
+ const fd = this.openBodyFd()
55
61
  const buf = Buffer.alloc(length)
56
- fs.readSync(this.bodyFd!, buf, 0, length, offset)
62
+ fs.readSync(fd, buf, 0, length, offset)
57
63
  return buf
58
64
  }
59
65
 
@@ -7,7 +7,7 @@ import { FileSessionStore } from './file-session-store'
7
7
  * Factory for creating session stores.
8
8
  */
9
9
  export interface IFixSessionStoreFactory {
10
- create (sessionId: SessionId): IFixSessionStore
10
+ create: (sessionId: SessionId) => IFixSessionStore
11
11
  }
12
12
 
13
13
  /**
@@ -14,24 +14,24 @@ export interface IFixSessionStore {
14
14
  readonly sessionId: SessionId
15
15
 
16
16
  // Message Operations
17
- put (record: IFixMsgStoreRecord): Promise<void>
18
- get (seqNum: number): Promise<IFixMsgStoreRecord | null>
19
- getRange (fromSeqNum: number, toSeqNum: number): Promise<IFixMsgStoreRecord[]>
17
+ put: (record: IFixMsgStoreRecord) => Promise<void>
18
+ get: (seqNum: number) => Promise<IFixMsgStoreRecord | null>
19
+ getRange: (fromSeqNum: number, toSeqNum: number) => Promise<IFixMsgStoreRecord[]>
20
20
 
21
21
  // Sequence Number Operations
22
22
  senderSeqNum: number
23
23
  targetSeqNum: number
24
- setSenderSeqNum (value: number): Promise<void>
25
- setTargetSeqNum (value: number): Promise<void>
26
- nextSenderSeqNum (): Promise<number>
27
- nextTargetSeqNum (): Promise<number>
24
+ setSenderSeqNum: (value: number) => Promise<void>
25
+ setTargetSeqNum: (value: number) => Promise<void>
26
+ nextSenderSeqNum: () => Promise<number>
27
+ nextTargetSeqNum: () => Promise<number>
28
28
 
29
29
  // Session Operations
30
30
  readonly creationTime: Date
31
- reset (): Promise<void>
31
+ reset: () => Promise<void>
32
32
 
33
33
  // Lifecycle
34
- initialize (): Promise<void>
35
- flush (): Promise<void>
36
- dispose (): Promise<void>
34
+ initialize: () => Promise<void>
35
+ flush: () => Promise<void>
36
+ dispose: () => Promise<void>
37
37
  }
@@ -7,7 +7,7 @@ import { IFixMsgStoreRecord } from './fix-msg-store-record'
7
7
  * Not persistent - all data lost on dispose.
8
8
  */
9
9
  export class MemorySessionStore implements IFixSessionStore {
10
- private readonly messages: Map<number, IFixMsgStoreRecord> = new Map()
10
+ private readonly messages = new Map<number, IFixMsgStoreRecord>()
11
11
  private senderSeqNumValue: number = 1
12
12
  private targetSeqNumValue: number = 1
13
13
  private creationTimeValue: Date = new Date()
@@ -7,68 +7,68 @@ export interface ISessionStreamProvider {
7
7
  * Opens or creates a read-write buffer for the message body file.
8
8
  * Must support random-access reads (by offset+length).
9
9
  */
10
- openBody (): void
10
+ openBody: () => void
11
11
 
12
12
  /**
13
13
  * Appends data to the body. Returns the offset at which data was written.
14
14
  */
15
- appendBody (data: Buffer): Promise<number>
15
+ appendBody: (data: Buffer) => Promise<number>
16
16
 
17
17
  /**
18
18
  * Reads data from the body at the given offset and length.
19
19
  */
20
- readBody (offset: number, length: number): Promise<Buffer>
20
+ readBody: (offset: number, length: number) => Promise<Buffer>
21
21
 
22
22
  /**
23
23
  * Gets the current body size (for calculating offsets).
24
24
  */
25
- getBodySize (): number
25
+ getBodySize: () => number
26
26
 
27
27
  /**
28
28
  * Appends a line to the header index file.
29
29
  */
30
- appendHeaderLine (line: string): Promise<void>
30
+ appendHeaderLine: (line: string) => Promise<void>
31
31
 
32
32
  /**
33
33
  * Reads all lines from the header index file.
34
34
  * Returns empty array if no data exists.
35
35
  */
36
- readHeaderLines (): Promise<string[]>
36
+ readHeaderLines: () => Promise<string[]>
37
37
 
38
38
  /**
39
39
  * Reads the sequence numbers string.
40
40
  * Returns null if no data exists.
41
41
  */
42
- readSeqNums (): Promise<string | null>
42
+ readSeqNums: () => Promise<string | null>
43
43
 
44
44
  /**
45
45
  * Writes the sequence numbers string.
46
46
  */
47
- writeSeqNums (content: string): Promise<void>
47
+ writeSeqNums: (content: string) => Promise<void>
48
48
 
49
49
  /**
50
50
  * Reads the session time string.
51
51
  * Returns null if no data exists.
52
52
  */
53
- readSessionTime (): Promise<string | null>
53
+ readSessionTime: () => Promise<string | null>
54
54
 
55
55
  /**
56
56
  * Writes the session time string.
57
57
  */
58
- writeSessionTime (content: string): Promise<void>
58
+ writeSessionTime: (content: string) => Promise<void>
59
59
 
60
60
  /**
61
61
  * Resets all streams/files for a new session.
62
62
  */
63
- reset (): Promise<void>
63
+ reset: () => Promise<void>
64
64
 
65
65
  /**
66
66
  * Flushes any pending writes.
67
67
  */
68
- flush (): Promise<void>
68
+ flush: () => Promise<void>
69
69
 
70
70
  /**
71
71
  * Disposes of all resources.
72
72
  */
73
- dispose (): Promise<void>
73
+ dispose: () => Promise<void>
74
74
  }
@@ -1,5 +1,5 @@
1
1
  export interface IFixClock {
2
- now (): Date
2
+ now: () => Date
3
3
  }
4
4
 
5
5
  export class DefaultFixClock implements IFixClock {
@@ -46,7 +46,7 @@ export class ResendAction {
46
46
  }
47
47
 
48
48
  export class PendingResendRange {
49
- private readonly receivedSeqs: Set<number> = new Set()
49
+ private readonly receivedSeqs = new Set<number>()
50
50
 
51
51
  constructor (
52
52
  public readonly begin: number,
@@ -190,11 +190,11 @@ export class ResendRequestManager {
190
190
  // keep requestHistory for debugging
191
191
  }
192
192
 
193
- get pending (): ReadonlyArray<PendingResendRange> {
193
+ get pending (): readonly PendingResendRange[] {
194
194
  return this.pendingRequests.slice()
195
195
  }
196
196
 
197
- get history (): ReadonlyArray<ResendRequestRecord> {
197
+ get history (): readonly ResendRequestRecord[] {
198
198
  return this.requestHistory.slice()
199
199
  }
200
200
 
@@ -240,7 +240,7 @@ export class ResendRequestManager {
240
240
  return { begin: gapBegin, end: gapEnd }
241
241
  }
242
242
 
243
- const covered: Set<number> = new Set()
243
+ const covered = new Set<number>()
244
244
  for (const pending of this.pendingRequests) {
245
245
  for (let seq = pending.begin; seq <= pending.end; seq++) {
246
246
  covered.add(seq)
@@ -160,7 +160,7 @@ export class SessionSequenceCoordinator {
160
160
  this.resendManager.recordRequestSent(begin, end, now)
161
161
  }
162
162
 
163
- get pendingResendRequests (): ReadonlyArray<PendingResendRange> {
163
+ get pendingResendRequests (): readonly PendingResendRange[] {
164
164
  return this.resendManager.pending
165
165
  }
166
166
 
@@ -6,9 +6,9 @@
6
6
  export interface ISessionSequenceStore {
7
7
  senderSeqNum: number
8
8
  targetSeqNum: number
9
- setSenderSeqNum (value: number): Promise<void>
10
- setTargetSeqNum (value: number): Promise<void>
11
- reset (): Promise<void>
9
+ setSenderSeqNum: (value: number) => Promise<void>
10
+ setTargetSeqNum: (value: number) => Promise<void>
11
+ reset: () => Promise<void>
12
12
  }
13
13
 
14
14
  /**
@@ -198,7 +198,7 @@ export class TcpInitiator extends FixInitiator {
198
198
  const timeoutPromise = promisify(setTimeout)
199
199
  const reconnectSeconds = application?.reconnectSeconds ?? 5
200
200
  let retries = 0
201
- let lastError: Error = initialError as Error
201
+ let lastError: Error | undefined = initialError
202
202
  const name = application?.name ?? 'initiator'
203
203
  this.th = setInterval(() => {
204
204
  ++retries