jspurefix 5.9.1 → 5.10.0

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 (145) hide show
  1. package/BACKPORT_PLAN.md +20 -7
  2. package/README.md +35 -0
  3. package/WORKLOG.md +119 -0
  4. package/dist/benchmark/bench-report.d.ts +5 -0
  5. package/dist/benchmark/bench-report.js +91 -0
  6. package/dist/benchmark/bench-report.js.map +1 -0
  7. package/dist/benchmark/bench-runner.d.ts +12 -0
  8. package/dist/benchmark/bench-runner.js +193 -0
  9. package/dist/benchmark/bench-runner.js.map +1 -0
  10. package/dist/benchmark/bench-stats.d.ts +10 -0
  11. package/dist/benchmark/bench-stats.js +56 -0
  12. package/dist/benchmark/bench-stats.js.map +1 -0
  13. package/dist/benchmark/bench-types.d.ts +74 -0
  14. package/dist/benchmark/bench-types.js +3 -0
  15. package/dist/benchmark/bench-types.js.map +1 -0
  16. package/dist/benchmark/gc-probe.d.ts +18 -0
  17. package/dist/benchmark/gc-probe.js +103 -0
  18. package/dist/benchmark/gc-probe.js.map +1 -0
  19. package/dist/benchmark/index.d.ts +6 -0
  20. package/dist/benchmark/index.js +23 -0
  21. package/dist/benchmark/index.js.map +1 -0
  22. package/dist/benchmark/parse-bench.d.ts +28 -0
  23. package/dist/benchmark/parse-bench.js +85 -0
  24. package/dist/benchmark/parse-bench.js.map +1 -0
  25. package/dist/buffer/ascii/ascii-encoder.d.ts +1 -0
  26. package/dist/buffer/ascii/ascii-encoder.js +15 -0
  27. package/dist/buffer/ascii/ascii-encoder.js.map +1 -1
  28. package/dist/buffer/ascii/ascii-parser.d.ts +1 -0
  29. package/dist/buffer/ascii/ascii-parser.js +4 -1
  30. package/dist/buffer/ascii/ascii-parser.js.map +1 -1
  31. package/dist/buffer/ascii/ascii-segment-parser.js +3 -2
  32. package/dist/buffer/ascii/ascii-segment-parser.js.map +1 -1
  33. package/dist/buffer/ascii/tag-index.js.map +1 -1
  34. package/dist/buffer/msg-encoder.d.ts +2 -0
  35. package/dist/buffer/msg-encoder.js +1 -0
  36. package/dist/buffer/msg-encoder.js.map +1 -1
  37. package/dist/buffer/msg-view.d.ts +1 -0
  38. package/dist/buffer/msg-view.js +25 -19
  39. package/dist/buffer/msg-view.js.map +1 -1
  40. package/dist/dictionary/parser/quickfix/dictionary-validator.d.ts +1 -1
  41. package/dist/dictionary/parser/quickfix/dictionary-validator.js.map +1 -1
  42. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.d.ts +1 -1
  43. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.js +1 -2
  44. package/dist/dictionary/parser/quickfix/quick-fix-graph-parser.js.map +1 -1
  45. package/dist/dictionary/parser/quickfix/validation-error.d.ts +2 -2
  46. package/dist/dictionary/parser/quickfix/validation-error.js.map +1 -1
  47. package/dist/jsfix-bench.d.ts +1 -0
  48. package/dist/jsfix-bench.js +213 -0
  49. package/dist/jsfix-bench.js.map +1 -0
  50. package/dist/runtime/session-container.d.ts +3 -0
  51. package/dist/runtime/session-container.js +8 -0
  52. package/dist/runtime/session-container.js.map +1 -1
  53. package/dist/runtime/session-launcher.d.ts +2 -1
  54. package/dist/runtime/session-launcher.js +4 -1
  55. package/dist/runtime/session-launcher.js.map +1 -1
  56. package/dist/store/file-session-store.js +1 -1
  57. package/dist/store/file-session-store.js.map +1 -1
  58. package/dist/store/file-session-stream-provider.d.ts +1 -0
  59. package/dist/store/file-session-stream-provider.js +13 -13
  60. package/dist/store/file-session-stream-provider.js.map +1 -1
  61. package/dist/store/fix-session-store-factory.d.ts +1 -1
  62. package/dist/store/fix-session-store-factory.js.map +1 -1
  63. package/dist/store/fix-session-store.d.ts +11 -11
  64. package/dist/store/fix-session-store.js.map +1 -1
  65. package/dist/store/memory-session-store.js.map +1 -1
  66. package/dist/store/session-stream-provider.d.ts +13 -13
  67. package/dist/store/session-stream-provider.js.map +1 -1
  68. package/dist/transport/ascii/ascii-msg-transmitter.d.ts +1 -0
  69. package/dist/transport/ascii/ascii-msg-transmitter.js +15 -0
  70. package/dist/transport/ascii/ascii-msg-transmitter.js.map +1 -1
  71. package/dist/transport/ascii/ascii-session-msg-factory.js +1 -7
  72. package/dist/transport/ascii/ascii-session-msg-factory.js.map +1 -1
  73. package/dist/transport/fixml/fixml-session-msg-factory.js +1 -6
  74. package/dist/transport/fixml/fixml-session-msg-factory.js.map +1 -1
  75. package/dist/transport/index.d.ts +3 -0
  76. package/dist/transport/index.js +3 -0
  77. package/dist/transport/index.js.map +1 -1
  78. package/dist/transport/msg-payload.d.ts +3 -1
  79. package/dist/transport/msg-payload.js +2 -1
  80. package/dist/transport/msg-payload.js.map +1 -1
  81. package/dist/transport/msg-transmitter.d.ts +4 -1
  82. package/dist/transport/msg-transmitter.js +18 -2
  83. package/dist/transport/msg-transmitter.js.map +1 -1
  84. package/dist/transport/send-callback.d.ts +7 -0
  85. package/dist/transport/send-callback.js +3 -0
  86. package/dist/transport/send-callback.js.map +1 -0
  87. package/dist/transport/session/fix-clock.d.ts +1 -1
  88. package/dist/transport/session/fix-clock.js.map +1 -1
  89. package/dist/transport/session/fix-session.d.ts +2 -1
  90. package/dist/transport/session/fix-session.js +12 -3
  91. package/dist/transport/session/fix-session.js.map +1 -1
  92. package/dist/transport/session/resend-request-manager.d.ts +2 -2
  93. package/dist/transport/session/resend-request-manager.js.map +1 -1
  94. package/dist/transport/session/session-description.d.ts +2 -0
  95. package/dist/transport/session/session-description.js.map +1 -1
  96. package/dist/transport/session/session-sequence-coordinator.d.ts +1 -1
  97. package/dist/transport/session/session-sequence-coordinator.js.map +1 -1
  98. package/dist/transport/session/session-sequence-store.d.ts +3 -3
  99. package/dist/transport/session/session-sequence-store.js.map +1 -1
  100. package/dist/transport/tcp/tcp-initiator.js.map +1 -1
  101. package/docs/benchmarking.md +117 -0
  102. package/docs/custom-logon.md +225 -0
  103. package/eslint.config.mjs +15 -1
  104. package/jsfix.test_client.txt +62 -62
  105. package/jsfix.test_server.txt +72 -72
  106. package/package.json +9 -1
  107. package/src/benchmark/bench-report.ts +101 -0
  108. package/src/benchmark/bench-runner.ts +196 -0
  109. package/src/benchmark/bench-stats.ts +86 -0
  110. package/src/benchmark/bench-types.ts +110 -0
  111. package/src/benchmark/gc-probe.ts +145 -0
  112. package/src/benchmark/index.ts +6 -0
  113. package/src/benchmark/parse-bench.ts +144 -0
  114. package/src/buffer/ascii/ascii-encoder.ts +20 -0
  115. package/src/buffer/ascii/ascii-parser.ts +16 -1
  116. package/src/buffer/ascii/ascii-segment-parser.ts +9 -6
  117. package/src/buffer/ascii/tag-index.ts +3 -3
  118. package/src/buffer/msg-encoder.ts +12 -0
  119. package/src/buffer/msg-view.ts +35 -18
  120. package/src/dictionary/parser/quickfix/dictionary-validator.ts +1 -1
  121. package/src/dictionary/parser/quickfix/quick-fix-graph-parser.ts +2 -3
  122. package/src/dictionary/parser/quickfix/validation-error.ts +1 -1
  123. package/src/jsfix-bench.ts +204 -0
  124. package/src/runtime/session-container.ts +20 -0
  125. package/src/runtime/session-launcher.ts +19 -2
  126. package/src/store/file-session-store.ts +2 -2
  127. package/src/store/file-session-stream-provider.ts +17 -11
  128. package/src/store/fix-session-store-factory.ts +1 -1
  129. package/src/store/fix-session-store.ts +11 -11
  130. package/src/store/memory-session-store.ts +1 -1
  131. package/src/store/session-stream-provider.ts +13 -13
  132. package/src/transport/ascii/ascii-msg-transmitter.ts +20 -0
  133. package/src/transport/ascii/ascii-session-msg-factory.ts +6 -1
  134. package/src/transport/fixml/fixml-session-msg-factory.ts +3 -1
  135. package/src/transport/index.ts +5 -0
  136. package/src/transport/msg-payload.ts +5 -1
  137. package/src/transport/msg-transmitter.ts +31 -2
  138. package/src/transport/send-callback.ts +33 -0
  139. package/src/transport/session/fix-clock.ts +1 -1
  140. package/src/transport/session/fix-session.ts +22 -3
  141. package/src/transport/session/resend-request-manager.ts +4 -4
  142. package/src/transport/session/session-description.ts +14 -0
  143. package/src/transport/session/session-sequence-coordinator.ts +1 -1
  144. package/src/transport/session/session-sequence-store.ts +3 -3
  145. package/src/transport/tcp/tcp-initiator.ts +1 -1
@@ -4,6 +4,7 @@ import { FixSessionState } from './fix-session-state'
4
4
  import { MsgTransport } from '../factory'
5
5
  import { MsgTag } from '../../types'
6
6
  import { ILooseObject } from '../../collections/collection'
7
+ import { SendCallback } from '../send-callback'
7
8
 
8
9
  import * as events from 'events'
9
10
  import { SessionState } from './session-state'
@@ -401,17 +402,35 @@ export abstract class FixSession extends events.EventEmitter {
401
402
  }
402
403
  }
403
404
 
404
- protected send (msgType: string, obj: ILooseObject): void {
405
+ /**
406
+ * @param callback optional, invoked once the message has been encoded and handed to
407
+ * the transport, or as soon as that fails. Without it a send is fire and forget:
408
+ * nothing tells the caller which sequence number the message went out under, and a
409
+ * message dropped because the session is down, or refused by the encoder, goes
410
+ * unanswered. See https://github.com/TimelordUK/jspurefix/issues/86
411
+ */
412
+ protected send (msgType: string, obj: ILooseObject, callback: SendCallback | null = null): void {
405
413
  const state = this.sessionState.state
406
414
  switch (state) {
407
415
  case SessionState.Stopped: {
408
- this.sessionLogger.warning(`can't send in state ${this.stateString()}`)
416
+ const msg = `can't send in state ${this.stateString()}`
417
+ this.sessionLogger.warning(msg)
418
+ // the message is dropped either way - but a caller that asked to be told is
419
+ // now told, instead of watching for a log line
420
+ callback?.(new Error(msg), { msgType, header: null, encoded: null })
409
421
  break
410
422
  }
411
423
 
412
424
  default: {
413
425
  this.sessionState.LastSentAt = new Date()
414
- this.transport?.transmitter.send(msgType, obj)
426
+ const transmitter = this.transport?.transmitter
427
+ if (!transmitter) {
428
+ const msg = `no transport to send ${msgType} on`
429
+ this.sessionLogger.warning(msg)
430
+ callback?.(new Error(msg), { msgType, header: null, encoded: null })
431
+ break
432
+ }
433
+ transmitter.send(msgType, obj, callback)
415
434
  break
416
435
  }
417
436
  }
@@ -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)
@@ -1,5 +1,6 @@
1
1
  import { IMsgApplication } from '../msg-application'
2
2
  import { StoreConfig } from '../../store/store-config'
3
+ import { ILooseObject } from '../../collections/collection'
3
4
 
4
5
  export interface IDynamicSessionParams {
5
6
  readonly Name: string
@@ -15,6 +16,19 @@ export interface IDynamicSessionParams {
15
16
 
16
17
  export interface ISessionDescription extends IDynamicSessionParams {
17
18
  readonly application?: IMsgApplication
19
+ /**
20
+ * Extra fields to place on the outbound Logon, merged over the ones the engine
21
+ * derives from this description. Counterparties routinely demand a tag the
22
+ * standard Logon does not carry - an account, a default application version, a
23
+ * free text token - and this is the no-code way to send it:
24
+ *
25
+ * "Logon": { "Account": "TVKD_001", "DefaultApplVerID": "9" }
26
+ *
27
+ * A field named here still has to exist on Logon in the dictionary the session
28
+ * loads, otherwise the encoder has no tag to write it to. Set a field to null to
29
+ * suppress one the engine would otherwise send. See issues #93, #39, #96.
30
+ */
31
+ readonly Logon?: ILooseObject
18
32
  HeartBtInt: number
19
33
  LastSentSeqNum?: number
20
34
  readonly LastReceivedSeqNum?: number
@@ -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