@homaiohq/napi-quickfix 0.1.0 → 0.3.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.
- package/CMakeLists.txt +5 -1
- package/README.md +344 -18
- package/cpp/acceptor_wrap.cpp +253 -19
- package/cpp/acceptor_wrap.h +60 -1
- package/cpp/addon.cpp +10 -6
- package/cpp/application_bridge.cpp +114 -30
- package/cpp/application_bridge.h +57 -4
- package/cpp/data_dictionary_wrap.cpp +89 -3
- package/cpp/data_dictionary_wrap.h +27 -5
- package/cpp/engine_common.h +108 -0
- package/cpp/engine_workers.h +99 -18
- package/cpp/field_map_ops.h +492 -0
- package/cpp/group_wrap.cpp +221 -0
- package/cpp/group_wrap.h +76 -0
- package/cpp/initiator_wrap.cpp +262 -25
- package/cpp/initiator_wrap.h +37 -2
- package/cpp/message_wrap.cpp +171 -78
- package/cpp/message_wrap.h +47 -5
- package/cpp/session_op_gate.h +201 -0
- package/cpp/session_static.cpp +139 -12
- package/cpp/session_wrap.cpp +438 -0
- package/cpp/session_wrap.h +144 -0
- package/dist/cjs/acceptor.d.ts +0 -1
- package/dist/cjs/acceptor.js +0 -1
- package/dist/cjs/application.d.ts +0 -1
- package/dist/cjs/application.js +0 -1
- package/dist/cjs/data-dictionary.d.ts +21 -3
- package/dist/cjs/data-dictionary.js +32 -4
- package/dist/cjs/engine.d.ts +42 -4
- package/dist/cjs/engine.js +50 -5
- package/dist/cjs/enums.d.ts +48 -14
- package/dist/cjs/enums.js +20 -25
- package/dist/cjs/field-value.d.ts +12 -0
- package/dist/cjs/field-value.js +40 -0
- package/dist/cjs/generated/fields.d.ts +0 -1
- package/dist/cjs/generated/fields.js +0 -1
- package/dist/cjs/generated/values.d.ts +8548 -0
- package/dist/cjs/generated/values.js +8580 -0
- package/dist/cjs/group.d.ts +126 -0
- package/dist/cjs/group.js +185 -0
- package/dist/cjs/index.d.ts +28 -5
- package/dist/cjs/index.js +30 -28
- package/dist/cjs/initiator.d.ts +0 -1
- package/dist/cjs/initiator.js +0 -1
- package/dist/cjs/message.d.ts +129 -5
- package/dist/cjs/message.js +146 -9
- package/dist/cjs/native.d.ts +179 -17
- package/dist/cjs/native.js +0 -1
- package/dist/cjs/session-id.d.ts +12 -1
- package/dist/cjs/session-id.js +21 -1
- package/dist/cjs/session-settings.d.ts +0 -1
- package/dist/cjs/session-settings.js +0 -1
- package/dist/cjs/session.d.ts +213 -0
- package/dist/cjs/session.js +337 -0
- package/dist/cjs/tls-tunnel.d.ts +143 -0
- package/dist/cjs/tls-tunnel.js +261 -0
- package/dist/esm/acceptor.d.ts +0 -1
- package/dist/esm/acceptor.js +0 -1
- package/dist/esm/application.d.ts +0 -1
- package/dist/esm/application.js +0 -1
- package/dist/esm/data-dictionary.d.ts +21 -3
- package/dist/esm/data-dictionary.js +32 -4
- package/dist/esm/engine.d.ts +42 -4
- package/dist/esm/engine.js +51 -6
- package/dist/esm/enums.d.ts +48 -14
- package/dist/esm/enums.js +14 -24
- package/dist/esm/field-value.d.ts +12 -0
- package/dist/esm/field-value.js +37 -0
- package/dist/esm/generated/fields.d.ts +0 -1
- package/dist/esm/generated/fields.js +0 -1
- package/dist/esm/generated/values.d.ts +8548 -0
- package/dist/esm/generated/values.js +8564 -0
- package/dist/esm/group.d.ts +126 -0
- package/dist/esm/group.js +181 -0
- package/dist/esm/index.d.ts +28 -5
- package/dist/esm/index.js +18 -26
- package/dist/esm/initiator.d.ts +0 -1
- package/dist/esm/initiator.js +0 -1
- package/dist/esm/message.d.ts +129 -5
- package/dist/esm/message.js +146 -9
- package/dist/esm/native.d.ts +179 -17
- package/dist/esm/native.js +0 -1
- package/dist/esm/session-id.d.ts +12 -1
- package/dist/esm/session-id.js +20 -1
- package/dist/esm/session-settings.d.ts +0 -1
- package/dist/esm/session-settings.js +0 -1
- package/dist/esm/session.d.ts +213 -0
- package/dist/esm/session.js +329 -0
- package/dist/esm/tls-tunnel.d.ts +143 -0
- package/dist/esm/tls-tunnel.js +256 -0
- package/package.json +13 -1
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/darwin-x64/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/node.napi.musl.node +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/cpp/enums.cpp +0 -66
- package/dist/cjs/acceptor.d.ts.map +0 -1
- package/dist/cjs/acceptor.js.map +0 -1
- package/dist/cjs/application.d.ts.map +0 -1
- package/dist/cjs/application.js.map +0 -1
- package/dist/cjs/data-dictionary.d.ts.map +0 -1
- package/dist/cjs/data-dictionary.js.map +0 -1
- package/dist/cjs/engine.d.ts.map +0 -1
- package/dist/cjs/engine.js.map +0 -1
- package/dist/cjs/enums.d.ts.map +0 -1
- package/dist/cjs/enums.js.map +0 -1
- package/dist/cjs/generated/fields.d.ts.map +0 -1
- package/dist/cjs/generated/fields.js.map +0 -1
- package/dist/cjs/index.d.ts.map +0 -1
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/initiator.d.ts.map +0 -1
- package/dist/cjs/initiator.js.map +0 -1
- package/dist/cjs/message.d.ts.map +0 -1
- package/dist/cjs/message.js.map +0 -1
- package/dist/cjs/native.d.ts.map +0 -1
- package/dist/cjs/native.js.map +0 -1
- package/dist/cjs/session-id.d.ts.map +0 -1
- package/dist/cjs/session-id.js.map +0 -1
- package/dist/cjs/session-settings.d.ts.map +0 -1
- package/dist/cjs/session-settings.js.map +0 -1
- package/dist/esm/acceptor.d.ts.map +0 -1
- package/dist/esm/acceptor.js.map +0 -1
- package/dist/esm/application.d.ts.map +0 -1
- package/dist/esm/application.js.map +0 -1
- package/dist/esm/data-dictionary.d.ts.map +0 -1
- package/dist/esm/data-dictionary.js.map +0 -1
- package/dist/esm/engine.d.ts.map +0 -1
- package/dist/esm/engine.js.map +0 -1
- package/dist/esm/enums.d.ts.map +0 -1
- package/dist/esm/enums.js.map +0 -1
- package/dist/esm/generated/fields.d.ts.map +0 -1
- package/dist/esm/generated/fields.js.map +0 -1
- package/dist/esm/index.d.ts.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/initiator.d.ts.map +0 -1
- package/dist/esm/initiator.js.map +0 -1
- package/dist/esm/message.d.ts.map +0 -1
- package/dist/esm/message.js.map +0 -1
- package/dist/esm/native.d.ts.map +0 -1
- package/dist/esm/native.js.map +0 -1
- package/dist/esm/session-id.d.ts.map +0 -1
- package/dist/esm/session-id.js.map +0 -1
- package/dist/esm/session-settings.d.ts.map +0 -1
- package/dist/esm/session-settings.js.map +0 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#ifndef NAPI_QUICKFIX_SESSION_WRAP_H
|
|
2
|
+
#define NAPI_QUICKFIX_SESSION_WRAP_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
|
|
6
|
+
#include <memory>
|
|
7
|
+
|
|
8
|
+
#include "quickfix/Session.h"
|
|
9
|
+
#include "quickfix/SessionID.h"
|
|
10
|
+
#include "session_op_gate.h"
|
|
11
|
+
|
|
12
|
+
namespace napi_quickfix {
|
|
13
|
+
|
|
14
|
+
// Napi::ObjectWrap giving JS a handle on a live FIX::Session.
|
|
15
|
+
//
|
|
16
|
+
// Lifetime: FIX::Session objects are OWNED BY THE ENGINE (Initiator/Acceptor)
|
|
17
|
+
// and FIX::Session::lookupSession returns a raw, non-owning pointer. This wrap
|
|
18
|
+
// therefore never caches that pointer: it stores the FIX::SessionID by value
|
|
19
|
+
// plus the SessionOpGate of the engine that owned the session when the handle
|
|
20
|
+
// was created, and re-resolves on EVERY call, throwing a QuickFixError with
|
|
21
|
+
// fixErrorName 'SessionNotFound' once the engine has been stopped (which
|
|
22
|
+
// destroys its sessions). The gate is what ties the handle to ONE engine: the
|
|
23
|
+
// process-wide registry lookupSession() reads is keyed by SessionID alone, so
|
|
24
|
+
// after the owner is stopped a new engine may register the same id, and a
|
|
25
|
+
// handle that only re-resolved the id would silently operate on the new
|
|
26
|
+
// engine's session. Resolve() therefore also requires the registered owner of
|
|
27
|
+
// the id (SessionOpGate::Lookup) to still be the gate captured at creation.
|
|
28
|
+
//
|
|
29
|
+
// new SessionWrap(sessionID: SessionIDWrap) -- internal; JS reaches a
|
|
30
|
+
// Session through lookupSession() / engine.getSession(), which bind the
|
|
31
|
+
// gate via NewInstance(). A handle built any other way has no gate and
|
|
32
|
+
// always throws SessionNotFound.
|
|
33
|
+
//
|
|
34
|
+
// Every member is synchronous and safe on the JS thread: none takes
|
|
35
|
+
// FIX::Session::m_mutex, which QuickFIX holds across application callbacks.
|
|
36
|
+
// getSessionID, isLoggedOn, isEnabled, sentLogon, sentLogout, receivedLogon,
|
|
37
|
+
// isInitiator, isAcceptor, isSessionTime(nowMs?), isLogonTime(nowMs?),
|
|
38
|
+
// getExpectedSenderNum, getExpectedTargetNum, setNextSenderMsgSeqNum,
|
|
39
|
+
// setNextTargetMsgSeqNum, logon, logout(reason?), refresh, and the runtime
|
|
40
|
+
// option getters/setters.
|
|
41
|
+
// FIX::Session::disconnect()/reset() are not exposed: they are only safe on
|
|
42
|
+
// the engine's own network thread (see session_wrap.cpp).
|
|
43
|
+
class SessionWrap : public Napi::ObjectWrap<SessionWrap> {
|
|
44
|
+
public:
|
|
45
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
46
|
+
|
|
47
|
+
// Build a JS Session bound to a copy of `id` and to `gate`, the
|
|
48
|
+
// SessionOpGate of the engine owning the session (SessionOpGate::Lookup(id)
|
|
49
|
+
// or the engine wrap's own gate_). Does NOT check that the session exists;
|
|
50
|
+
// callers (lookupSession / engine.getSession) do.
|
|
51
|
+
static Napi::Object NewInstance(Napi::Env env, const FIX::SessionID& id,
|
|
52
|
+
std::shared_ptr<SessionOpGate> gate);
|
|
53
|
+
|
|
54
|
+
explicit SessionWrap(const Napi::CallbackInfo& info);
|
|
55
|
+
|
|
56
|
+
const FIX::SessionID& SessionID() const { return id_; }
|
|
57
|
+
|
|
58
|
+
private:
|
|
59
|
+
static Napi::FunctionReference constructor_;
|
|
60
|
+
|
|
61
|
+
// Resolve the live FIX::Session of the engine this handle was created for,
|
|
62
|
+
// or throw FIX::SessionNotFound (session gone, or the id now belongs to a
|
|
63
|
+
// different engine). Must be called inside NQ_TRY so the exception maps to a
|
|
64
|
+
// QuickFixError.
|
|
65
|
+
FIX::Session& Resolve();
|
|
66
|
+
|
|
67
|
+
Napi::Value GetSessionID(const Napi::CallbackInfo& info);
|
|
68
|
+
|
|
69
|
+
Napi::Value IsLoggedOn(const Napi::CallbackInfo& info);
|
|
70
|
+
Napi::Value IsEnabled(const Napi::CallbackInfo& info);
|
|
71
|
+
Napi::Value SentLogon(const Napi::CallbackInfo& info);
|
|
72
|
+
Napi::Value SentLogout(const Napi::CallbackInfo& info);
|
|
73
|
+
Napi::Value ReceivedLogon(const Napi::CallbackInfo& info);
|
|
74
|
+
Napi::Value IsInitiator(const Napi::CallbackInfo& info);
|
|
75
|
+
Napi::Value IsAcceptor(const Napi::CallbackInfo& info);
|
|
76
|
+
Napi::Value IsSessionTime(const Napi::CallbackInfo& info);
|
|
77
|
+
Napi::Value IsLogonTime(const Napi::CallbackInfo& info);
|
|
78
|
+
|
|
79
|
+
Napi::Value GetExpectedSenderNum(const Napi::CallbackInfo& info);
|
|
80
|
+
Napi::Value GetExpectedTargetNum(const Napi::CallbackInfo& info);
|
|
81
|
+
Napi::Value SetNextSenderMsgSeqNum(const Napi::CallbackInfo& info);
|
|
82
|
+
Napi::Value SetNextTargetMsgSeqNum(const Napi::CallbackInfo& info);
|
|
83
|
+
|
|
84
|
+
// Runtime options (plain members on FIX::Session; no locking, no callbacks).
|
|
85
|
+
Napi::Value GetResetOnLogon(const Napi::CallbackInfo& info);
|
|
86
|
+
Napi::Value SetResetOnLogon(const Napi::CallbackInfo& info);
|
|
87
|
+
Napi::Value GetResetOnLogout(const Napi::CallbackInfo& info);
|
|
88
|
+
Napi::Value SetResetOnLogout(const Napi::CallbackInfo& info);
|
|
89
|
+
Napi::Value GetResetOnDisconnect(const Napi::CallbackInfo& info);
|
|
90
|
+
Napi::Value SetResetOnDisconnect(const Napi::CallbackInfo& info);
|
|
91
|
+
Napi::Value GetRefreshOnLogon(const Napi::CallbackInfo& info);
|
|
92
|
+
Napi::Value SetRefreshOnLogon(const Napi::CallbackInfo& info);
|
|
93
|
+
Napi::Value GetCheckCompId(const Napi::CallbackInfo& info);
|
|
94
|
+
Napi::Value SetCheckCompId(const Napi::CallbackInfo& info);
|
|
95
|
+
Napi::Value GetCheckLatency(const Napi::CallbackInfo& info);
|
|
96
|
+
Napi::Value SetCheckLatency(const Napi::CallbackInfo& info);
|
|
97
|
+
Napi::Value GetPersistMessages(const Napi::CallbackInfo& info);
|
|
98
|
+
Napi::Value SetPersistMessages(const Napi::CallbackInfo& info);
|
|
99
|
+
Napi::Value GetSendRedundantResendRequests(const Napi::CallbackInfo& info);
|
|
100
|
+
Napi::Value SetSendRedundantResendRequests(const Napi::CallbackInfo& info);
|
|
101
|
+
Napi::Value GetValidateLengthAndChecksum(const Napi::CallbackInfo& info);
|
|
102
|
+
Napi::Value SetValidateLengthAndChecksum(const Napi::CallbackInfo& info);
|
|
103
|
+
Napi::Value GetSendNextExpectedMsgSeqNum(const Napi::CallbackInfo& info);
|
|
104
|
+
Napi::Value SetSendNextExpectedMsgSeqNum(const Napi::CallbackInfo& info);
|
|
105
|
+
Napi::Value GetIsNonStopSession(const Napi::CallbackInfo& info);
|
|
106
|
+
Napi::Value SetIsNonStopSession(const Napi::CallbackInfo& info);
|
|
107
|
+
Napi::Value GetLogonTimeout(const Napi::CallbackInfo& info);
|
|
108
|
+
Napi::Value SetLogonTimeout(const Napi::CallbackInfo& info);
|
|
109
|
+
Napi::Value GetLogoutTimeout(const Napi::CallbackInfo& info);
|
|
110
|
+
Napi::Value SetLogoutTimeout(const Napi::CallbackInfo& info);
|
|
111
|
+
Napi::Value GetMaxLatency(const Napi::CallbackInfo& info);
|
|
112
|
+
Napi::Value SetMaxLatency(const Napi::CallbackInfo& info);
|
|
113
|
+
Napi::Value GetTimestampPrecision(const Napi::CallbackInfo& info);
|
|
114
|
+
Napi::Value SetTimestampPrecision(const Napi::CallbackInfo& info);
|
|
115
|
+
|
|
116
|
+
// Control. All sync: they only touch SessionState under its own mutex,
|
|
117
|
+
// which QuickFIX never holds across a callback.
|
|
118
|
+
Napi::Value Logon(const Napi::CallbackInfo& info);
|
|
119
|
+
Napi::Value Logout(const Napi::CallbackInfo& info);
|
|
120
|
+
Napi::Value Refresh(const Napi::CallbackInfo& info);
|
|
121
|
+
|
|
122
|
+
// Shared helpers for the one-liner getters/setters above.
|
|
123
|
+
template <typename Fn>
|
|
124
|
+
Napi::Value BoolGet(const Napi::CallbackInfo& info, Fn fn);
|
|
125
|
+
template <typename Fn>
|
|
126
|
+
Napi::Value IntGet(const Napi::CallbackInfo& info, Fn fn);
|
|
127
|
+
template <typename Fn>
|
|
128
|
+
Napi::Value BoolSet(const Napi::CallbackInfo& info, Fn fn, const char* name);
|
|
129
|
+
template <typename Fn>
|
|
130
|
+
Napi::Value IntSet(const Napi::CallbackInfo& info, Fn fn, const char* name);
|
|
131
|
+
Napi::Value TimeCheck(const Napi::CallbackInfo& info, bool logonTime);
|
|
132
|
+
Napi::Value SeqNumSet(const Napi::CallbackInfo& info, bool sender,
|
|
133
|
+
const char* name);
|
|
134
|
+
|
|
135
|
+
FIX::SessionID id_;
|
|
136
|
+
// The owning engine's gate at creation; held by shared_ptr so the object
|
|
137
|
+
// stays alive (and its address unique) as long as the handle does. nullptr
|
|
138
|
+
// for a handle not created through NewInstance().
|
|
139
|
+
std::shared_ptr<SessionOpGate> gate_;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
} // namespace napi_quickfix
|
|
143
|
+
|
|
144
|
+
#endif // NAPI_QUICKFIX_SESSION_WRAP_H
|
package/dist/cjs/acceptor.d.ts
CHANGED
package/dist/cjs/acceptor.js
CHANGED
package/dist/cjs/application.js
CHANGED
|
@@ -13,6 +13,8 @@ import type { Message } from './message.js';
|
|
|
13
13
|
* ```ts
|
|
14
14
|
* const dd = DataDictionary.fromFile('./spec/FIX44.xml');
|
|
15
15
|
* dd.validate(msg); // throws QuickFixError if invalid
|
|
16
|
+
* dd.getFieldName(35); // 'MsgType'
|
|
17
|
+
* Message.parse(raw, { dictionary: dd }); // structural parse (repeating groups)
|
|
16
18
|
* ```
|
|
17
19
|
*/
|
|
18
20
|
export declare class DataDictionary {
|
|
@@ -41,9 +43,25 @@ export declare class DataDictionary {
|
|
|
41
43
|
* Validate a message against this dictionary.
|
|
42
44
|
*
|
|
43
45
|
* @param msg The message to validate.
|
|
46
|
+
* @param bodyOnly When `true`, validate only as the *application* dictionary
|
|
47
|
+
* (QuickFIX's `validate(msg, true)`): the BeginString version check and the
|
|
48
|
+
* tag/value validation of the header and trailer fields are skipped. It is
|
|
49
|
+
* not a check of a draft body: `BeginString` and `MsgType` must be set, and
|
|
50
|
+
* every field the dictionary requires, header and trailer included (e.g.
|
|
51
|
+
* `BodyLength`, `CheckSum`), must be present. Defaults to `false`.
|
|
44
52
|
* @throws A `QuickFixError` on any validation failure (e.g.
|
|
45
|
-
* `
|
|
53
|
+
* `fixErrorName: 'InvalidMessage'` / `'RequiredTagMissing'` /
|
|
54
|
+
* `'IncorrectTagValue'` / `'UnsupportedVersion'`).
|
|
46
55
|
*/
|
|
47
|
-
validate(msg: Message): void;
|
|
56
|
+
validate(msg: Message, bodyOnly?: boolean): void;
|
|
57
|
+
/** The BeginString the spec declares (e.g. `'FIX.4.4'`), or `''` if it has none. */
|
|
58
|
+
getVersion(): string;
|
|
59
|
+
/** The name of a field tag (e.g. `35` → `'MsgType'`), or `undefined` if the spec does not define it. */
|
|
60
|
+
getFieldName(tag: number): string | undefined;
|
|
61
|
+
/** The tag of a field name (e.g. `'MsgType'` → `35`), or `undefined` if the spec does not define it. */
|
|
62
|
+
getFieldTag(name: string): number | undefined;
|
|
63
|
+
/** Whether the spec defines a field with this tag. */
|
|
64
|
+
isField(tag: number): boolean;
|
|
65
|
+
/** Whether the spec defines a message with this MsgType (e.g. `'D'`). */
|
|
66
|
+
isMsgType(msgType: string): boolean;
|
|
48
67
|
}
|
|
49
|
-
//# sourceMappingURL=data-dictionary.d.ts.map
|
|
@@ -15,6 +15,8 @@ const native_js_1 = require("./native.js");
|
|
|
15
15
|
* ```ts
|
|
16
16
|
* const dd = DataDictionary.fromFile('./spec/FIX44.xml');
|
|
17
17
|
* dd.validate(msg); // throws QuickFixError if invalid
|
|
18
|
+
* dd.getFieldName(35); // 'MsgType'
|
|
19
|
+
* Message.parse(raw, { dictionary: dd }); // structural parse (repeating groups)
|
|
18
20
|
* ```
|
|
19
21
|
*/
|
|
20
22
|
class DataDictionary {
|
|
@@ -66,12 +68,38 @@ class DataDictionary {
|
|
|
66
68
|
* Validate a message against this dictionary.
|
|
67
69
|
*
|
|
68
70
|
* @param msg The message to validate.
|
|
71
|
+
* @param bodyOnly When `true`, validate only as the *application* dictionary
|
|
72
|
+
* (QuickFIX's `validate(msg, true)`): the BeginString version check and the
|
|
73
|
+
* tag/value validation of the header and trailer fields are skipped. It is
|
|
74
|
+
* not a check of a draft body: `BeginString` and `MsgType` must be set, and
|
|
75
|
+
* every field the dictionary requires, header and trailer included (e.g.
|
|
76
|
+
* `BodyLength`, `CheckSum`), must be present. Defaults to `false`.
|
|
69
77
|
* @throws A `QuickFixError` on any validation failure (e.g.
|
|
70
|
-
* `
|
|
78
|
+
* `fixErrorName: 'InvalidMessage'` / `'RequiredTagMissing'` /
|
|
79
|
+
* `'IncorrectTagValue'` / `'UnsupportedVersion'`).
|
|
71
80
|
*/
|
|
72
|
-
validate(msg) {
|
|
73
|
-
this.#native.validate(msg.nativeHandle);
|
|
81
|
+
validate(msg, bodyOnly = false) {
|
|
82
|
+
this.#native.validate(msg.nativeHandle, bodyOnly);
|
|
83
|
+
}
|
|
84
|
+
/** The BeginString the spec declares (e.g. `'FIX.4.4'`), or `''` if it has none. */
|
|
85
|
+
getVersion() {
|
|
86
|
+
return this.#native.getVersion();
|
|
87
|
+
}
|
|
88
|
+
/** The name of a field tag (e.g. `35` → `'MsgType'`), or `undefined` if the spec does not define it. */
|
|
89
|
+
getFieldName(tag) {
|
|
90
|
+
return this.#native.getFieldName(tag);
|
|
91
|
+
}
|
|
92
|
+
/** The tag of a field name (e.g. `'MsgType'` → `35`), or `undefined` if the spec does not define it. */
|
|
93
|
+
getFieldTag(name) {
|
|
94
|
+
return this.#native.getFieldTag(name);
|
|
95
|
+
}
|
|
96
|
+
/** Whether the spec defines a field with this tag. */
|
|
97
|
+
isField(tag) {
|
|
98
|
+
return this.#native.isField(tag);
|
|
99
|
+
}
|
|
100
|
+
/** Whether the spec defines a message with this MsgType (e.g. `'D'`). */
|
|
101
|
+
isMsgType(msgType) {
|
|
102
|
+
return this.#native.isMsgType(msgType);
|
|
74
103
|
}
|
|
75
104
|
}
|
|
76
105
|
exports.DataDictionary = DataDictionary;
|
|
77
|
-
//# sourceMappingURL=data-dictionary.js.map
|
package/dist/cjs/engine.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { EventEmitter } from 'node:events';
|
|
|
8
8
|
import { type NativeEngineConstructor } from './native.js';
|
|
9
9
|
import { Message } from './message.js';
|
|
10
10
|
import { SessionID } from './session-id.js';
|
|
11
|
+
import { Session } from './session.js';
|
|
11
12
|
import type { ApplicationHandlers } from './application.js';
|
|
12
13
|
import type { SessionSettings } from './session-settings.js';
|
|
13
14
|
/** Options for constructing an {@link Initiator} or {@link Acceptor}. */
|
|
@@ -73,7 +74,11 @@ export declare abstract class Engine extends EventEmitter {
|
|
|
73
74
|
* Stop the engine.
|
|
74
75
|
*
|
|
75
76
|
* Runs off the main thread and resolves once shutdown completes, keeping the
|
|
76
|
-
* event loop free for any in-flight callbacks.
|
|
77
|
+
* event loop free for any in-flight callbacks. Once it settles the engine's
|
|
78
|
+
* sessions are destroyed. A `stop()` called while another is still in flight
|
|
79
|
+
* (even from a `'logout'` listener that stop fired) returns the same Promise,
|
|
80
|
+
* so it too settles only once the sessions are gone; the first call's
|
|
81
|
+
* `force` applies to both.
|
|
77
82
|
*
|
|
78
83
|
* @param force When `true`, aborts immediately instead of draining gracefully.
|
|
79
84
|
*
|
|
@@ -83,8 +88,42 @@ export declare abstract class Engine extends EventEmitter {
|
|
|
83
88
|
* ```
|
|
84
89
|
*/
|
|
85
90
|
stop(force?: boolean): Promise<void>;
|
|
86
|
-
/**
|
|
87
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Whether a session is logged on.
|
|
93
|
+
*
|
|
94
|
+
* With no argument: `true` if **any** of this engine's sessions is logged on.
|
|
95
|
+
* With a {@link SessionID}: `true` only if that session belongs to this engine
|
|
96
|
+
* and is logged on (`false`, not an error, for a foreign id). Always `false`
|
|
97
|
+
* before {@link Engine.start} and once {@link Engine.stop} has settled; while
|
|
98
|
+
* a graceful stop is still in progress it reports the live state.
|
|
99
|
+
*
|
|
100
|
+
* @throws {TypeError} if `sessionID` is given but is not a {@link SessionID}
|
|
101
|
+
* (it does not fall back to the engine-wide form).
|
|
102
|
+
*/
|
|
103
|
+
isLoggedOn(sessionID?: SessionID): boolean;
|
|
104
|
+
/**
|
|
105
|
+
* The ids of the sessions this engine was configured with (every `[SESSION]`
|
|
106
|
+
* in its settings). Stable for the engine's lifetime, including after
|
|
107
|
+
* {@link Engine.stop}.
|
|
108
|
+
*/
|
|
109
|
+
getSessions(): SessionID[];
|
|
110
|
+
/**
|
|
111
|
+
* A handle on one of this engine's sessions.
|
|
112
|
+
*
|
|
113
|
+
* @returns The {@link Session}, or `undefined` if `sessionID` is not one of
|
|
114
|
+
* this engine's sessions or {@link Engine.stop} has settled (that destroys
|
|
115
|
+
* its sessions). While a stop is still in progress the sessions are alive,
|
|
116
|
+
* so a `'logout'` listener can still read e.g. the final sequence numbers.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* initiator.on('logon', (id) => {
|
|
121
|
+
* const session = initiator.getSession(id)!;
|
|
122
|
+
* console.log('next seq', session.getExpectedSenderNum());
|
|
123
|
+
* });
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
getSession(sessionID: SessionID): Session | undefined;
|
|
88
127
|
/**
|
|
89
128
|
* Keep the Node.js event loop alive while the engine is running (default once
|
|
90
129
|
* started). Pair with {@link Engine.unref} to let a short script exit.
|
|
@@ -111,4 +150,3 @@ export interface Engine {
|
|
|
111
150
|
/** List the listeners registered for an event. */
|
|
112
151
|
listeners<E extends keyof EngineEvents>(event: E): Array<(...args: EngineEvents[E]) => void>;
|
|
113
152
|
}
|
|
114
|
-
//# sourceMappingURL=engine.d.ts.map
|
package/dist/cjs/engine.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.Engine = void 0;
|
|
|
10
10
|
const node_events_1 = require("node:events");
|
|
11
11
|
const message_js_1 = require("./message.js");
|
|
12
12
|
const session_id_js_1 = require("./session-id.js");
|
|
13
|
+
const session_js_1 = require("./session.js");
|
|
13
14
|
/**
|
|
14
15
|
* Base class for the FIX session engines.
|
|
15
16
|
*
|
|
@@ -106,7 +107,11 @@ class Engine extends node_events_1.EventEmitter {
|
|
|
106
107
|
* Stop the engine.
|
|
107
108
|
*
|
|
108
109
|
* Runs off the main thread and resolves once shutdown completes, keeping the
|
|
109
|
-
* event loop free for any in-flight callbacks.
|
|
110
|
+
* event loop free for any in-flight callbacks. Once it settles the engine's
|
|
111
|
+
* sessions are destroyed. A `stop()` called while another is still in flight
|
|
112
|
+
* (even from a `'logout'` listener that stop fired) returns the same Promise,
|
|
113
|
+
* so it too settles only once the sessions are gone; the first call's
|
|
114
|
+
* `force` applies to both.
|
|
110
115
|
*
|
|
111
116
|
* @param force When `true`, aborts immediately instead of draining gracefully.
|
|
112
117
|
*
|
|
@@ -118,9 +123,50 @@ class Engine extends node_events_1.EventEmitter {
|
|
|
118
123
|
stop(force) {
|
|
119
124
|
return this.#native.stop(force);
|
|
120
125
|
}
|
|
121
|
-
/**
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Whether a session is logged on.
|
|
128
|
+
*
|
|
129
|
+
* With no argument: `true` if **any** of this engine's sessions is logged on.
|
|
130
|
+
* With a {@link SessionID}: `true` only if that session belongs to this engine
|
|
131
|
+
* and is logged on (`false`, not an error, for a foreign id). Always `false`
|
|
132
|
+
* before {@link Engine.start} and once {@link Engine.stop} has settled; while
|
|
133
|
+
* a graceful stop is still in progress it reports the live state.
|
|
134
|
+
*
|
|
135
|
+
* @throws {TypeError} if `sessionID` is given but is not a {@link SessionID}
|
|
136
|
+
* (it does not fall back to the engine-wide form).
|
|
137
|
+
*/
|
|
138
|
+
isLoggedOn(sessionID) {
|
|
139
|
+
return sessionID === undefined
|
|
140
|
+
? this.#native.isLoggedOn()
|
|
141
|
+
: this.#native.isLoggedOn((0, session_id_js_1.toNativeSessionID)(sessionID, 'sessionID'));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The ids of the sessions this engine was configured with (every `[SESSION]`
|
|
145
|
+
* in its settings). Stable for the engine's lifetime, including after
|
|
146
|
+
* {@link Engine.stop}.
|
|
147
|
+
*/
|
|
148
|
+
getSessions() {
|
|
149
|
+
return this.#native.getSessions().map((h) => session_id_js_1.SessionID.fromNative(h));
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* A handle on one of this engine's sessions.
|
|
153
|
+
*
|
|
154
|
+
* @returns The {@link Session}, or `undefined` if `sessionID` is not one of
|
|
155
|
+
* this engine's sessions or {@link Engine.stop} has settled (that destroys
|
|
156
|
+
* its sessions). While a stop is still in progress the sessions are alive,
|
|
157
|
+
* so a `'logout'` listener can still read e.g. the final sequence numbers.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* initiator.on('logon', (id) => {
|
|
162
|
+
* const session = initiator.getSession(id)!;
|
|
163
|
+
* console.log('next seq', session.getExpectedSenderNum());
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
getSession(sessionID) {
|
|
168
|
+
const handle = this.#native.getSession((0, session_id_js_1.toNativeSessionID)(sessionID, 'sessionID'));
|
|
169
|
+
return handle ? session_js_1.Session.fromNative(handle) : undefined;
|
|
124
170
|
}
|
|
125
171
|
/**
|
|
126
172
|
* Keep the Node.js event loop alive while the engine is running (default once
|
|
@@ -135,4 +181,3 @@ class Engine extends node_events_1.EventEmitter {
|
|
|
135
181
|
}
|
|
136
182
|
}
|
|
137
183
|
exports.Engine = Engine;
|
|
138
|
-
//# sourceMappingURL=engine.js.map
|
package/dist/cjs/enums.d.ts
CHANGED
|
@@ -1,22 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FIX constants.
|
|
3
|
+
*
|
|
4
|
+
* - {@link FIELD} — field-name → tag-number (e.g. `FIELD.MsgType === 35`).
|
|
5
|
+
* Generated from QuickFIX's `FixFieldNumbers.h` (see `src/generated/fields.ts`),
|
|
6
|
+
* so it carries every `FIX::FIELD::*` name the bundled engine knows.
|
|
7
|
+
* - value groups such as {@link MsgType} and {@link Side} (e.g.
|
|
8
|
+
* `MsgType.Logon === 'A'`, `Side.Buy === '1'`) — one per field, generated from
|
|
9
|
+
* QuickFIX's `FixValues.h` (see `src/generated/values.ts`), so every
|
|
10
|
+
* `FIX::<Field>_<VALUE>` constant is here. {@link VALUES} holds all of them
|
|
11
|
+
* keyed by field name, and each group is also importable from
|
|
12
|
+
* `@homaiohq/napi-quickfix/values` without loading the native addon.
|
|
13
|
+
*
|
|
14
|
+
* Everything carries literal types and is frozen, so a misspelt name is a
|
|
15
|
+
* compile error and consumers cannot mutate the shared constant tables.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { FIELD, MsgType, enums } from '@homaiohq/napi-quickfix';
|
|
20
|
+
* msg.setField(FIELD.MsgType, MsgType.Logon);
|
|
21
|
+
* const side = enums.Side.Buy;
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import { FIELD } from './generated/fields.js';
|
|
25
|
+
import { type ValueGroups } from './generated/values.js';
|
|
1
26
|
export { FIELD, type FieldName } from './generated/fields.js';
|
|
2
|
-
|
|
27
|
+
export { VALUES, MsgType, Side, OrdType, TimeInForce, type ValueGroups, type ValueGroupName, } from './generated/values.js';
|
|
28
|
+
/**
|
|
29
|
+
* A single group of FIX constants widened to a string-indexed map (name → value).
|
|
30
|
+
*
|
|
31
|
+
* Every value group and {@link FIELD} is assignable to it, so use it where a group
|
|
32
|
+
* is looked up by a `string` key the compiler cannot narrow (a name read from
|
|
33
|
+
* configuration, say) instead of the literally-typed group itself:
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const group: EnumGroup = enums[name as ValueGroupName];
|
|
38
|
+
* const code = group[valueName];
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
3
41
|
export type EnumGroup = Readonly<Record<string, number | string>>;
|
|
4
|
-
/**
|
|
5
|
-
|
|
42
|
+
/**
|
|
43
|
+
* The full, frozen tree of FIX constants: every value group of {@link ValueGroups}
|
|
44
|
+
* plus the {@link FIELD} tag table.
|
|
45
|
+
*/
|
|
46
|
+
export type Enums = ValueGroups & {
|
|
47
|
+
readonly FIELD: typeof FIELD;
|
|
48
|
+
};
|
|
6
49
|
/**
|
|
7
50
|
* The complete tree of FIX constants (frozen), e.g. `enums.FIELD.MsgType`,
|
|
8
51
|
* `enums.MsgType.Logon`, `enums.Side.Buy`.
|
|
9
52
|
*
|
|
10
|
-
* `enums.FIELD` is the same table as {@link FIELD};
|
|
11
|
-
* the
|
|
53
|
+
* `enums.FIELD` is the same table as {@link FIELD}; every other member is the
|
|
54
|
+
* same object as the corresponding {@link VALUES} group.
|
|
12
55
|
*/
|
|
13
56
|
export declare const enums: Enums;
|
|
14
|
-
/** A group of numeric FIX constants (name → number). */
|
|
15
|
-
export type NumericEnumGroup = Readonly<Record<string, number>>;
|
|
16
|
-
/** A group of string-valued FIX constants (name → string), e.g. {@link MsgType}. */
|
|
17
|
-
export type StringEnumGroup = Readonly<Record<string, string>>;
|
|
18
|
-
/** MsgType values (strings), e.g. `MsgType.Logon === 'A'`. */
|
|
19
|
-
export declare const MsgType: StringEnumGroup;
|
|
20
|
-
/** Side values (strings), e.g. `Side.Buy === '1'`. */
|
|
21
|
-
export declare const Side: StringEnumGroup;
|
|
22
|
-
//# sourceMappingURL=enums.d.ts.map
|
package/dist/cjs/enums.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Side = exports.MsgType = exports.
|
|
3
|
+
exports.enums = exports.TimeInForce = exports.OrdType = exports.Side = exports.MsgType = exports.VALUES = exports.FIELD = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* FIX constants.
|
|
6
6
|
*
|
|
7
7
|
* - {@link FIELD} — field-name → tag-number (e.g. `FIELD.MsgType === 35`).
|
|
8
8
|
* Generated from QuickFIX's `FixFieldNumbers.h` (see `src/generated/fields.ts`),
|
|
9
|
-
* so it carries every `FIX::FIELD::*` name the bundled engine knows
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* so it carries every `FIX::FIELD::*` name the bundled engine knows.
|
|
10
|
+
* - value groups such as {@link MsgType} and {@link Side} (e.g.
|
|
11
|
+
* `MsgType.Logon === 'A'`, `Side.Buy === '1'`) — one per field, generated from
|
|
12
|
+
* QuickFIX's `FixValues.h` (see `src/generated/values.ts`), so every
|
|
13
|
+
* `FIX::<Field>_<VALUE>` constant is here. {@link VALUES} holds all of them
|
|
14
|
+
* keyed by field name, and each group is also importable from
|
|
15
|
+
* `@homaiohq/napi-quickfix/values` without loading the native addon.
|
|
13
16
|
*
|
|
14
|
-
* Everything
|
|
15
|
-
* constant tables.
|
|
17
|
+
* Everything carries literal types and is frozen, so a misspelt name is a
|
|
18
|
+
* compile error and consumers cannot mutate the shared constant tables.
|
|
16
19
|
*
|
|
17
20
|
* @example
|
|
18
21
|
* ```ts
|
|
@@ -22,28 +25,20 @@ exports.Side = exports.MsgType = exports.enums = exports.FIELD = void 0;
|
|
|
22
25
|
* ```
|
|
23
26
|
*/
|
|
24
27
|
const fields_js_1 = require("./generated/fields.js");
|
|
25
|
-
const
|
|
28
|
+
const values_js_1 = require("./generated/values.js");
|
|
26
29
|
var fields_js_2 = require("./generated/fields.js");
|
|
27
30
|
Object.defineProperty(exports, "FIELD", { enumerable: true, get: function () { return fields_js_2.FIELD; } });
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
out.FIELD = fields_js_1.FIELD;
|
|
35
|
-
return Object.freeze(out);
|
|
36
|
-
}
|
|
31
|
+
var values_js_2 = require("./generated/values.js");
|
|
32
|
+
Object.defineProperty(exports, "VALUES", { enumerable: true, get: function () { return values_js_2.VALUES; } });
|
|
33
|
+
Object.defineProperty(exports, "MsgType", { enumerable: true, get: function () { return values_js_2.MsgType; } });
|
|
34
|
+
Object.defineProperty(exports, "Side", { enumerable: true, get: function () { return values_js_2.Side; } });
|
|
35
|
+
Object.defineProperty(exports, "OrdType", { enumerable: true, get: function () { return values_js_2.OrdType; } });
|
|
36
|
+
Object.defineProperty(exports, "TimeInForce", { enumerable: true, get: function () { return values_js_2.TimeInForce; } });
|
|
37
37
|
/**
|
|
38
38
|
* The complete tree of FIX constants (frozen), e.g. `enums.FIELD.MsgType`,
|
|
39
39
|
* `enums.MsgType.Logon`, `enums.Side.Buy`.
|
|
40
40
|
*
|
|
41
|
-
* `enums.FIELD` is the same table as {@link FIELD};
|
|
42
|
-
* the
|
|
41
|
+
* `enums.FIELD` is the same table as {@link FIELD}; every other member is the
|
|
42
|
+
* same object as the corresponding {@link VALUES} group.
|
|
43
43
|
*/
|
|
44
|
-
exports.enums =
|
|
45
|
-
/** MsgType values (strings), e.g. `MsgType.Logon === 'A'`. */
|
|
46
|
-
exports.MsgType = (exports.enums.MsgType ?? Object.freeze({}));
|
|
47
|
-
/** Side values (strings), e.g. `Side.Buy === '1'`. */
|
|
48
|
-
exports.Side = (exports.enums.Side ?? Object.freeze({}));
|
|
49
|
-
//# sourceMappingURL=enums.js.map
|
|
44
|
+
exports.enums = Object.freeze({ ...values_js_1.VALUES, FIELD: fields_js_1.FIELD });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire formatting of the `string | number` field values `Message` and `Group`
|
|
3
|
+
* accept.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A field value as FIX text. Strings pass through. A number keeps its shortest
|
|
7
|
+
* round-trip digits but is written without exponent notation, which FIX numeric
|
|
8
|
+
* fields do not allow (`1e-7` → `'0.0000001'`, `1e21` →
|
|
9
|
+
* `'1000000000000000000000'`, where `String` gives `'1e-7'` and `'1e+21'`).
|
|
10
|
+
* @throws `RangeError` for `NaN` and `±Infinity`, which have no FIX form.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatFieldValue(value: string | number): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Wire formatting of the `string | number` field values `Message` and `Group`
|
|
4
|
+
* accept.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.formatFieldValue = formatFieldValue;
|
|
8
|
+
/**
|
|
9
|
+
* A field value as FIX text. Strings pass through. A number keeps its shortest
|
|
10
|
+
* round-trip digits but is written without exponent notation, which FIX numeric
|
|
11
|
+
* fields do not allow (`1e-7` → `'0.0000001'`, `1e21` →
|
|
12
|
+
* `'1000000000000000000000'`, where `String` gives `'1e-7'` and `'1e+21'`).
|
|
13
|
+
* @throws `RangeError` for `NaN` and `±Infinity`, which have no FIX form.
|
|
14
|
+
*/
|
|
15
|
+
function formatFieldValue(value) {
|
|
16
|
+
if (typeof value !== 'number') {
|
|
17
|
+
return String(value);
|
|
18
|
+
}
|
|
19
|
+
if (!Number.isFinite(value)) {
|
|
20
|
+
throw new RangeError(`field value must be a finite number, got ${value}`);
|
|
21
|
+
}
|
|
22
|
+
const text = String(value);
|
|
23
|
+
const e = text.indexOf('e');
|
|
24
|
+
if (e === -1) {
|
|
25
|
+
return text;
|
|
26
|
+
}
|
|
27
|
+
// `[-]d[.ddd]e±n`: move the decimal point of the mantissa n places.
|
|
28
|
+
const sign = value < 0 ? '-' : '';
|
|
29
|
+
const mantissa = text.slice(sign.length, e);
|
|
30
|
+
const point = mantissa.indexOf('.');
|
|
31
|
+
const digits = mantissa.replace('.', '');
|
|
32
|
+
const at = (point === -1 ? mantissa.length : point) + Number(text.slice(e + 1));
|
|
33
|
+
if (at <= 0) {
|
|
34
|
+
return `${sign}0.${'0'.repeat(-at)}${digits}`;
|
|
35
|
+
}
|
|
36
|
+
if (at >= digits.length) {
|
|
37
|
+
return `${sign}${digits}${'0'.repeat(at - digits.length)}`;
|
|
38
|
+
}
|
|
39
|
+
return `${sign}${digits.slice(0, at)}.${digits.slice(at)}`;
|
|
40
|
+
}
|