@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,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ergonomic wrapper around the native `FIX::Group`: one entry of a repeating
|
|
3
|
+
* group.
|
|
4
|
+
*/
|
|
5
|
+
import { type NativeGroup } from './native.js';
|
|
6
|
+
/**
|
|
7
|
+
* One entry of a FIX repeating group.
|
|
8
|
+
*
|
|
9
|
+
* A group is identified by its **count tag** (`field`, e.g. `453 NoPartyIDs`)
|
|
10
|
+
* and its **delimiter** (`delim`, the first tag of every entry, e.g.
|
|
11
|
+
* `448 PartyID`). Build an entry, fill its fields, then
|
|
12
|
+
* {@link Message.addGroup} it; QuickFIX maintains the count field for you.
|
|
13
|
+
*
|
|
14
|
+
* Field values are accepted as `string | number` on input (numbers are written
|
|
15
|
+
* without exponent notation) and always returned as `string`, exactly as on
|
|
16
|
+
* {@link Message}. Groups nest: an entry can carry its own repeating groups
|
|
17
|
+
* through the same `addGroup` / `getGroup` API.
|
|
18
|
+
*
|
|
19
|
+
* Entries read back with `getGroup` are **snapshot copies**: mutating one does
|
|
20
|
+
* not change the message it came from. Write it back with
|
|
21
|
+
* {@link Message.replaceGroup}.
|
|
22
|
+
*
|
|
23
|
+
* Group indices are **1-based**, as in QuickFIX.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* import { Group, Message, FIELD } from '@homaiohq/napi-quickfix';
|
|
28
|
+
*
|
|
29
|
+
* const party = new Group(FIELD.NoPartyIDs, FIELD.PartyID)
|
|
30
|
+
* .setField(FIELD.PartyID, 'TRADER-1')
|
|
31
|
+
* .setField(FIELD.PartyIDSource, 'D')
|
|
32
|
+
* .setField(FIELD.PartyRole, 11);
|
|
33
|
+
* order.addGroup(party);
|
|
34
|
+
*
|
|
35
|
+
* order.groupCount(FIELD.NoPartyIDs); // 1
|
|
36
|
+
* order.getGroup(1, FIELD.NoPartyIDs).getField(FIELD.PartyID); // 'TRADER-1'
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class Group {
|
|
40
|
+
#private;
|
|
41
|
+
/**
|
|
42
|
+
* Create an empty group entry.
|
|
43
|
+
*
|
|
44
|
+
* @param field The group's count tag (e.g. `FIELD.NoPartyIDs`), or an
|
|
45
|
+
* existing native handle to adopt (internal).
|
|
46
|
+
* @param delim The delimiter: the first tag of every entry (e.g.
|
|
47
|
+
* `FIELD.PartyID`).
|
|
48
|
+
* @param order Optional complete field order of an entry, delimiter first
|
|
49
|
+
* (e.g. `[448, 447, 452]`). Fields not listed sort after the listed ones by
|
|
50
|
+
* tag number. Without it, fields sort delimiter-first then by tag number,
|
|
51
|
+
* which already matches the standard dictionaries for most groups.
|
|
52
|
+
*/
|
|
53
|
+
constructor(field: number | NativeGroup, delim?: number, order?: readonly number[]);
|
|
54
|
+
/** @internal Wrap an existing native group handle. */
|
|
55
|
+
static fromNative(handle: NativeGroup): Group;
|
|
56
|
+
/** @internal The native handle backing this group. */
|
|
57
|
+
get nativeHandle(): NativeGroup;
|
|
58
|
+
/** The group's count tag (e.g. `453` for `NoPartyIDs`). */
|
|
59
|
+
get field(): number;
|
|
60
|
+
/** The delimiter: the first tag of every entry (e.g. `448` for `PartyID`). */
|
|
61
|
+
get delim(): number;
|
|
62
|
+
/**
|
|
63
|
+
* Read a field by tag.
|
|
64
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) if absent.
|
|
65
|
+
*/
|
|
66
|
+
getField(tag: number): string;
|
|
67
|
+
/** Set a field. Returns `this` for chaining. */
|
|
68
|
+
setField(tag: number, value: string | number): this;
|
|
69
|
+
/** Whether a field is present. */
|
|
70
|
+
isSetField(tag: number): boolean;
|
|
71
|
+
/** Remove a field (no-op if absent). Returns `this` for chaining. */
|
|
72
|
+
removeField(tag: number): this;
|
|
73
|
+
/** Read a field by tag, or `undefined` if absent. */
|
|
74
|
+
getFieldIfSet(tag: number): string | undefined;
|
|
75
|
+
/** The number of fields, including every field of every nested group entry. */
|
|
76
|
+
totalFields(): number;
|
|
77
|
+
/** Whether the entry has no fields of its own. */
|
|
78
|
+
isEmpty(): boolean;
|
|
79
|
+
/** Remove every field and nested group. Returns `this` for chaining. */
|
|
80
|
+
clear(): this;
|
|
81
|
+
/** The entry's own fields, in wire order, as `[tag, value]` pairs. */
|
|
82
|
+
fields(): [number, string][];
|
|
83
|
+
/** Iterates the entry's own fields as `[tag, value]` pairs (see {@link Group.fields}). */
|
|
84
|
+
[Symbol.iterator](): IterableIterator<[number, string]>;
|
|
85
|
+
/**
|
|
86
|
+
* Append a nested group entry under its own count tag (a copy is stored; the
|
|
87
|
+
* count field is updated). Returns `this` for chaining.
|
|
88
|
+
* @throws `TypeError` when `group.delim` differs from the delimiter of the
|
|
89
|
+
* entries already stored under `group.field`.
|
|
90
|
+
*/
|
|
91
|
+
addGroup(group: Group): this;
|
|
92
|
+
/**
|
|
93
|
+
* A snapshot copy of the `index`-th entry (1-based) of the nested group `tag`.
|
|
94
|
+
* Mutations do not affect this entry; write them back with
|
|
95
|
+
* {@link Group.replaceGroup}.
|
|
96
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when the tag
|
|
97
|
+
* has no entries or `index` is out of range.
|
|
98
|
+
*/
|
|
99
|
+
getGroup(index: number, tag: number): Group;
|
|
100
|
+
/**
|
|
101
|
+
* Overwrite the `index`-th entry (1-based) under `group.field` with a copy of
|
|
102
|
+
* `group`. Returns `this` for chaining.
|
|
103
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when that
|
|
104
|
+
* entry does not exist.
|
|
105
|
+
* @throws `TypeError` when `group.delim` differs from the stored entry's
|
|
106
|
+
* delimiter.
|
|
107
|
+
*/
|
|
108
|
+
replaceGroup(index: number, group: Group): this;
|
|
109
|
+
/**
|
|
110
|
+
* Remove every entry of the nested group `tag` (and its count field), or
|
|
111
|
+
* only the `index`-th entry (1-based). Returns `this`.
|
|
112
|
+
*
|
|
113
|
+
* Removing every entry of a tag that has none is a no-op.
|
|
114
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when the
|
|
115
|
+
* `index`-th entry does not exist.
|
|
116
|
+
*/
|
|
117
|
+
removeGroup(tag: number): this;
|
|
118
|
+
removeGroup(index: number, tag: number): this;
|
|
119
|
+
/** Whether the nested group `tag` has any entry, or has an `index`-th entry (1-based). */
|
|
120
|
+
hasGroup(tag: number): boolean;
|
|
121
|
+
hasGroup(index: number, tag: number): boolean;
|
|
122
|
+
/** The number of entries of the nested group `tag` (0 if none). */
|
|
123
|
+
groupCount(tag: number): number;
|
|
124
|
+
/** The entry's fields (and nested groups) as a SOH-delimited string, in wire order. */
|
|
125
|
+
toString(): string;
|
|
126
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ergonomic wrapper around the native `FIX::Group`: one entry of a repeating
|
|
3
|
+
* group.
|
|
4
|
+
*/
|
|
5
|
+
import { native } from './native.js';
|
|
6
|
+
import { formatFieldValue } from './field-value.js';
|
|
7
|
+
/**
|
|
8
|
+
* One entry of a FIX repeating group.
|
|
9
|
+
*
|
|
10
|
+
* A group is identified by its **count tag** (`field`, e.g. `453 NoPartyIDs`)
|
|
11
|
+
* and its **delimiter** (`delim`, the first tag of every entry, e.g.
|
|
12
|
+
* `448 PartyID`). Build an entry, fill its fields, then
|
|
13
|
+
* {@link Message.addGroup} it; QuickFIX maintains the count field for you.
|
|
14
|
+
*
|
|
15
|
+
* Field values are accepted as `string | number` on input (numbers are written
|
|
16
|
+
* without exponent notation) and always returned as `string`, exactly as on
|
|
17
|
+
* {@link Message}. Groups nest: an entry can carry its own repeating groups
|
|
18
|
+
* through the same `addGroup` / `getGroup` API.
|
|
19
|
+
*
|
|
20
|
+
* Entries read back with `getGroup` are **snapshot copies**: mutating one does
|
|
21
|
+
* not change the message it came from. Write it back with
|
|
22
|
+
* {@link Message.replaceGroup}.
|
|
23
|
+
*
|
|
24
|
+
* Group indices are **1-based**, as in QuickFIX.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { Group, Message, FIELD } from '@homaiohq/napi-quickfix';
|
|
29
|
+
*
|
|
30
|
+
* const party = new Group(FIELD.NoPartyIDs, FIELD.PartyID)
|
|
31
|
+
* .setField(FIELD.PartyID, 'TRADER-1')
|
|
32
|
+
* .setField(FIELD.PartyIDSource, 'D')
|
|
33
|
+
* .setField(FIELD.PartyRole, 11);
|
|
34
|
+
* order.addGroup(party);
|
|
35
|
+
*
|
|
36
|
+
* order.groupCount(FIELD.NoPartyIDs); // 1
|
|
37
|
+
* order.getGroup(1, FIELD.NoPartyIDs).getField(FIELD.PartyID); // 'TRADER-1'
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export class Group {
|
|
41
|
+
/** @internal Underlying native handle. */
|
|
42
|
+
#native;
|
|
43
|
+
/**
|
|
44
|
+
* Create an empty group entry.
|
|
45
|
+
*
|
|
46
|
+
* @param field The group's count tag (e.g. `FIELD.NoPartyIDs`), or an
|
|
47
|
+
* existing native handle to adopt (internal).
|
|
48
|
+
* @param delim The delimiter: the first tag of every entry (e.g.
|
|
49
|
+
* `FIELD.PartyID`).
|
|
50
|
+
* @param order Optional complete field order of an entry, delimiter first
|
|
51
|
+
* (e.g. `[448, 447, 452]`). Fields not listed sort after the listed ones by
|
|
52
|
+
* tag number. Without it, fields sort delimiter-first then by tag number,
|
|
53
|
+
* which already matches the standard dictionaries for most groups.
|
|
54
|
+
*/
|
|
55
|
+
constructor(field, delim, order) {
|
|
56
|
+
if (typeof field !== 'number') {
|
|
57
|
+
// Adopt an existing native handle (getGroup path).
|
|
58
|
+
this.#native = field;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (typeof delim !== 'number') {
|
|
62
|
+
throw new TypeError('new Group(field: number, delim: number, order?: number[])');
|
|
63
|
+
}
|
|
64
|
+
this.#native = new native.GroupWrap(field, delim, order);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** @internal Wrap an existing native group handle. */
|
|
68
|
+
static fromNative(handle) {
|
|
69
|
+
return new Group(handle);
|
|
70
|
+
}
|
|
71
|
+
/** @internal The native handle backing this group. */
|
|
72
|
+
get nativeHandle() {
|
|
73
|
+
return this.#native;
|
|
74
|
+
}
|
|
75
|
+
/** The group's count tag (e.g. `453` for `NoPartyIDs`). */
|
|
76
|
+
get field() {
|
|
77
|
+
return this.#native.field();
|
|
78
|
+
}
|
|
79
|
+
/** The delimiter: the first tag of every entry (e.g. `448` for `PartyID`). */
|
|
80
|
+
get delim() {
|
|
81
|
+
return this.#native.delim();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Read a field by tag.
|
|
85
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) if absent.
|
|
86
|
+
*/
|
|
87
|
+
getField(tag) {
|
|
88
|
+
return this.#native.getField(tag);
|
|
89
|
+
}
|
|
90
|
+
/** Set a field. Returns `this` for chaining. */
|
|
91
|
+
setField(tag, value) {
|
|
92
|
+
this.#native.setField(tag, formatFieldValue(value));
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
/** Whether a field is present. */
|
|
96
|
+
isSetField(tag) {
|
|
97
|
+
return this.#native.isSetField(tag);
|
|
98
|
+
}
|
|
99
|
+
/** Remove a field (no-op if absent). Returns `this` for chaining. */
|
|
100
|
+
removeField(tag) {
|
|
101
|
+
this.#native.removeField(tag);
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
/** Read a field by tag, or `undefined` if absent. */
|
|
105
|
+
getFieldIfSet(tag) {
|
|
106
|
+
return this.#native.getFieldIfSet(tag);
|
|
107
|
+
}
|
|
108
|
+
/** The number of fields, including every field of every nested group entry. */
|
|
109
|
+
totalFields() {
|
|
110
|
+
return this.#native.totalFields();
|
|
111
|
+
}
|
|
112
|
+
/** Whether the entry has no fields of its own. */
|
|
113
|
+
isEmpty() {
|
|
114
|
+
return this.#native.isEmpty();
|
|
115
|
+
}
|
|
116
|
+
/** Remove every field and nested group. Returns `this` for chaining. */
|
|
117
|
+
clear() {
|
|
118
|
+
this.#native.clear();
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
/** The entry's own fields, in wire order, as `[tag, value]` pairs. */
|
|
122
|
+
fields() {
|
|
123
|
+
return this.#native.fields();
|
|
124
|
+
}
|
|
125
|
+
/** Iterates the entry's own fields as `[tag, value]` pairs (see {@link Group.fields}). */
|
|
126
|
+
[Symbol.iterator]() {
|
|
127
|
+
return this.fields()[Symbol.iterator]();
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Append a nested group entry under its own count tag (a copy is stored; the
|
|
131
|
+
* count field is updated). Returns `this` for chaining.
|
|
132
|
+
* @throws `TypeError` when `group.delim` differs from the delimiter of the
|
|
133
|
+
* entries already stored under `group.field`.
|
|
134
|
+
*/
|
|
135
|
+
addGroup(group) {
|
|
136
|
+
this.#native.addGroup(group.nativeHandle);
|
|
137
|
+
return this;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* A snapshot copy of the `index`-th entry (1-based) of the nested group `tag`.
|
|
141
|
+
* Mutations do not affect this entry; write them back with
|
|
142
|
+
* {@link Group.replaceGroup}.
|
|
143
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when the tag
|
|
144
|
+
* has no entries or `index` is out of range.
|
|
145
|
+
*/
|
|
146
|
+
getGroup(index, tag) {
|
|
147
|
+
return Group.fromNative(this.#native.getGroup(index, tag));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Overwrite the `index`-th entry (1-based) under `group.field` with a copy of
|
|
151
|
+
* `group`. Returns `this` for chaining.
|
|
152
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when that
|
|
153
|
+
* entry does not exist.
|
|
154
|
+
* @throws `TypeError` when `group.delim` differs from the stored entry's
|
|
155
|
+
* delimiter.
|
|
156
|
+
*/
|
|
157
|
+
replaceGroup(index, group) {
|
|
158
|
+
this.#native.replaceGroup(index, group.nativeHandle);
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
removeGroup(a, b) {
|
|
162
|
+
if (b === undefined) {
|
|
163
|
+
this.#native.removeGroup(a);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
this.#native.removeGroup(a, b);
|
|
167
|
+
}
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
hasGroup(a, b) {
|
|
171
|
+
return b === undefined ? this.#native.hasGroup(a) : this.#native.hasGroup(a, b);
|
|
172
|
+
}
|
|
173
|
+
/** The number of entries of the nested group `tag` (0 if none). */
|
|
174
|
+
groupCount(tag) {
|
|
175
|
+
return this.#native.groupCount(tag);
|
|
176
|
+
}
|
|
177
|
+
/** The entry's fields (and nested groups) as a SOH-delimited string, in wire order. */
|
|
178
|
+
toString() {
|
|
179
|
+
return this.#native.toString();
|
|
180
|
+
}
|
|
181
|
+
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Message } from './message.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type SessionID } from './session-id.js';
|
|
3
3
|
export { Message, createMessage, parseMessage } from './message.js';
|
|
4
4
|
export type { MessageParseOptions, MessageJSON } from './message.js';
|
|
5
|
+
export { Group } from './group.js';
|
|
5
6
|
export { SessionID } from './session-id.js';
|
|
6
7
|
export { SessionSettings } from './session-settings.js';
|
|
7
8
|
export { DataDictionary } from './data-dictionary.js';
|
|
@@ -9,11 +10,14 @@ export { Initiator } from './initiator.js';
|
|
|
9
10
|
export { Acceptor } from './acceptor.js';
|
|
10
11
|
export { Engine } from './engine.js';
|
|
11
12
|
export type { EngineOptions, EngineEvents } from './engine.js';
|
|
13
|
+
export { Session, lookupSession, doesSessionExist, getSessions, numSessions } from './session.js';
|
|
12
14
|
export { FixReject, fixReject } from './application.js';
|
|
13
15
|
export type { ApplicationHandlers, FixRejectKind } from './application.js';
|
|
14
16
|
export type { QuickFixError } from './native.js';
|
|
15
|
-
export {
|
|
16
|
-
export type {
|
|
17
|
+
export { createTlsTunnel } from './tls-tunnel.js';
|
|
18
|
+
export type { TlsTunnel, TlsTunnelOptions, TlsTunnelEvents, TlsTunnelSecureConnectInfo, } from './tls-tunnel.js';
|
|
19
|
+
export { enums, FIELD, VALUES, MsgType, Side, OrdType, TimeInForce } from './enums.js';
|
|
20
|
+
export type { Enums, EnumGroup, FieldName, ValueGroups, ValueGroupName } from './enums.js';
|
|
17
21
|
/**
|
|
18
22
|
* Send a message to the target session identified by `sessionID`.
|
|
19
23
|
*
|
|
@@ -23,11 +27,17 @@ export type { Enums, EnumGroup, FieldName } from './enums.js';
|
|
|
23
27
|
* Runs off the main thread and resolves once the engine has accepted (or
|
|
24
28
|
* rejected) the message, so the event loop stays free for callbacks. On a
|
|
25
29
|
* missing session the returned Promise rejects with a
|
|
26
|
-
* {@link QuickFixError} (`fixErrorName: 'SessionNotFound'`).
|
|
30
|
+
* {@link QuickFixError} (`fixErrorName: 'SessionNotFound'`). The send is
|
|
31
|
+
* bound to the engine that owns the session when it is called: if that
|
|
32
|
+
* engine is stopped before the send reaches its session, the Promise rejects
|
|
33
|
+
* with `SessionNotFound` rather than running through an engine created later
|
|
34
|
+
* with the same id.
|
|
27
35
|
*
|
|
28
36
|
* @param message The message to send.
|
|
29
37
|
* @param sessionID The destination session.
|
|
30
38
|
* @returns A Promise resolving to `true` if the message was accepted for sending.
|
|
39
|
+
* @throws {TypeError} synchronously if `sessionID` is neither a {@link SessionID}
|
|
40
|
+
* nor a qualifier string (it is not routed by the header instead).
|
|
31
41
|
*
|
|
32
42
|
* @example
|
|
33
43
|
* ```ts
|
|
@@ -37,6 +47,20 @@ export type { Enums, EnumGroup, FieldName } from './enums.js';
|
|
|
37
47
|
* ```
|
|
38
48
|
*/
|
|
39
49
|
export declare function sendToTarget(message: Message, sessionID: SessionID): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Send a message to the session identified by the message's **own header**
|
|
52
|
+
* (`BeginString`, `SenderCompID`, `TargetCompID`) plus an optional session
|
|
53
|
+
* qualifier.
|
|
54
|
+
*
|
|
55
|
+
* Wraps the `FIX::Session::sendToTarget(message, qualifier)` overload. Same
|
|
56
|
+
* threading and error behaviour as the SessionID form; a message whose header
|
|
57
|
+
* does not identify an existing session rejects with
|
|
58
|
+
* `fixErrorName: 'SessionNotFound'`.
|
|
59
|
+
*
|
|
60
|
+
* @param message The message to send; its header must carry tags 8, 49 and 56.
|
|
61
|
+
* @param qualifier Optional session qualifier (`SessionQualifier` in the settings).
|
|
62
|
+
*/
|
|
63
|
+
export declare function sendToTarget(message: Message, qualifier?: string): Promise<boolean>;
|
|
40
64
|
/** The QuickFIX engine / addon version string. */
|
|
41
65
|
export declare const version: () => string;
|
|
42
66
|
/**
|
|
@@ -44,4 +68,3 @@ export declare const version: () => string;
|
|
|
44
68
|
* prefer {@link Message.parse} + {@link Message.getMsgType} for general use.
|
|
45
69
|
*/
|
|
46
70
|
export declare const quickfixParseMsgType: (raw: string) => string;
|
|
47
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.js
CHANGED
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
* @packageDocumentation
|
|
6
6
|
*/
|
|
7
7
|
import { native } from './native.js';
|
|
8
|
+
import { toNativeSessionID } from './session-id.js';
|
|
8
9
|
// --- Pure layer -----------------------------------------------------------
|
|
9
10
|
export { Message, createMessage, parseMessage } from './message.js';
|
|
11
|
+
export { Group } from './group.js';
|
|
10
12
|
export { SessionID } from './session-id.js';
|
|
11
13
|
export { SessionSettings } from './session-settings.js';
|
|
12
14
|
export { DataDictionary } from './data-dictionary.js';
|
|
@@ -14,33 +16,24 @@ export { DataDictionary } from './data-dictionary.js';
|
|
|
14
16
|
export { Initiator } from './initiator.js';
|
|
15
17
|
export { Acceptor } from './acceptor.js';
|
|
16
18
|
export { Engine } from './engine.js';
|
|
19
|
+
export { Session, lookupSession, doesSessionExist, getSessions, numSessions } from './session.js';
|
|
17
20
|
export { FixReject, fixReject } from './application.js';
|
|
21
|
+
export { createTlsTunnel } from './tls-tunnel.js';
|
|
18
22
|
// --- Enums / constants ----------------------------------------------------
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* @returns A Promise resolving to `true` if the message was accepted for sending.
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* import { sendToTarget, createMessage, SessionID, FIELD, MsgType } from '@homaiohq/napi-quickfix';
|
|
38
|
-
* const order = createMessage({ [FIELD.MsgType]: MsgType.NewOrderSingle });
|
|
39
|
-
* await sendToTarget(order, new SessionID('FIX.4.4', 'CLIENT', 'BROKER'));
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export function sendToTarget(message, sessionID) {
|
|
43
|
-
return native.sendToTarget(message.nativeHandle, sessionID.nativeHandle);
|
|
23
|
+
// Every other value group (ExecType, OrdStatus, SecurityType, ...) is reachable
|
|
24
|
+
// as `enums.<Field>` / `VALUES.<Field>`, or by name from the
|
|
25
|
+
// `@homaiohq/napi-quickfix/values` subpath, which keeps this namespace small.
|
|
26
|
+
export { enums, FIELD, VALUES, MsgType, Side, OrdType, TimeInForce } from './enums.js';
|
|
27
|
+
export function sendToTarget(message, sessionIDOrQualifier) {
|
|
28
|
+
// Dispatch on the primitive, not `instanceof SessionID`: this package ships
|
|
29
|
+
// ESM and CJS builds, and a SessionID created by the other build is a
|
|
30
|
+
// different class with the same shape (see toNativeSessionID). Anything
|
|
31
|
+
// else is a TypeError here rather than an `undefined` target the native
|
|
32
|
+
// layer would read as "route by the message header".
|
|
33
|
+
const target = typeof sessionIDOrQualifier === 'string' || sessionIDOrQualifier === undefined
|
|
34
|
+
? sessionIDOrQualifier
|
|
35
|
+
: toNativeSessionID(sessionIDOrQualifier, 'sessionID');
|
|
36
|
+
return native.sendToTarget(message.nativeHandle, target);
|
|
44
37
|
}
|
|
45
38
|
/** The QuickFIX engine / addon version string. */
|
|
46
39
|
export const version = () => native.version();
|
|
@@ -49,4 +42,3 @@ export const version = () => native.version();
|
|
|
49
42
|
* prefer {@link Message.parse} + {@link Message.getMsgType} for general use.
|
|
50
43
|
*/
|
|
51
44
|
export const quickfixParseMsgType = (raw) => native.quickfixParseMsgType(raw);
|
|
52
|
-
//# sourceMappingURL=index.js.map
|
package/dist/esm/initiator.d.ts
CHANGED
package/dist/esm/initiator.js
CHANGED
package/dist/esm/message.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Ergonomic wrapper around the native `FIX::Message`.
|
|
3
3
|
*/
|
|
4
4
|
import { type NativeMessage } from './native.js';
|
|
5
|
+
import { Group } from './group.js';
|
|
6
|
+
import type { DataDictionary } from './data-dictionary.js';
|
|
5
7
|
/** Options controlling how a raw FIX string is parsed into a {@link Message}. */
|
|
6
8
|
export interface MessageParseOptions {
|
|
7
9
|
/**
|
|
@@ -11,6 +13,26 @@ export interface MessageParseOptions {
|
|
|
11
13
|
* {@link DataDictionary} instead.
|
|
12
14
|
*/
|
|
13
15
|
validate?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Parse with this dictionary as both the session and application dictionary
|
|
18
|
+
* (the usual choice for FIX 4.x). With a dictionary, repeating groups are
|
|
19
|
+
* parsed into nested {@link Group} entries readable with
|
|
20
|
+
* {@link Message.getGroup}; without one the parse is **flat** and group
|
|
21
|
+
* fields are left as plain repeated body fields.
|
|
22
|
+
*/
|
|
23
|
+
dictionary?: DataDictionary;
|
|
24
|
+
/**
|
|
25
|
+
* The session (transport) dictionary, e.g. `FIXT11.xml`. Governs header,
|
|
26
|
+
* trailer and admin messages. Overrides {@link MessageParseOptions.dictionary}
|
|
27
|
+
* for that role.
|
|
28
|
+
*/
|
|
29
|
+
sessionDictionary?: DataDictionary;
|
|
30
|
+
/**
|
|
31
|
+
* The application dictionary, e.g. `FIX50SP2.xml`. Governs the body of
|
|
32
|
+
* application messages. Overrides {@link MessageParseOptions.dictionary} for
|
|
33
|
+
* that role.
|
|
34
|
+
*/
|
|
35
|
+
applicationDictionary?: DataDictionary;
|
|
14
36
|
}
|
|
15
37
|
/** A structured, best-effort view of a parsed message returned by {@link Message.toJSON}. */
|
|
16
38
|
export interface MessageJSON {
|
|
@@ -23,7 +45,9 @@ export interface MessageJSON {
|
|
|
23
45
|
* A FIX message.
|
|
24
46
|
*
|
|
25
47
|
* Field values are accepted as `string | number` on input (numbers are
|
|
26
|
-
* stringified, since FIX is string-on-the-wire
|
|
48
|
+
* stringified, since FIX is string-on-the-wire, without exponent notation:
|
|
49
|
+
* `1e-7` is written `0.0000001`) and always returned as `string`. `NaN` and
|
|
50
|
+
* `±Infinity` throw a `RangeError`.
|
|
27
51
|
*
|
|
28
52
|
* @example
|
|
29
53
|
* ```ts
|
|
@@ -36,6 +60,12 @@ export interface MessageJSON {
|
|
|
36
60
|
*
|
|
37
61
|
* const parsed = Message.parse(msg.toString());
|
|
38
62
|
* console.log(parsed.getMsgType());
|
|
63
|
+
*
|
|
64
|
+
* // Repeating groups: build entries with Group, read them back by 1-based index.
|
|
65
|
+
* msg.addGroup(new Group(FIELD.NoPartyIDs, FIELD.PartyID).setField(FIELD.PartyID, 'TRADER-1'));
|
|
66
|
+
* const dd = DataDictionary.fromFile('FIX44.xml');
|
|
67
|
+
* const withGroups = Message.parse(msg.toString(), { dictionary: dd });
|
|
68
|
+
* withGroups.getGroup(1, FIELD.NoPartyIDs).getField(FIELD.PartyID); // 'TRADER-1'
|
|
39
69
|
* ```
|
|
40
70
|
*/
|
|
41
71
|
export declare class Message {
|
|
@@ -55,8 +85,18 @@ export declare class Message {
|
|
|
55
85
|
/**
|
|
56
86
|
* Parse a raw FIX wire string into a {@link Message}.
|
|
57
87
|
*
|
|
88
|
+
* Pass a `dictionary` to parse repeating groups structurally; without one
|
|
89
|
+
* the parse is flat (see {@link MessageParseOptions}).
|
|
90
|
+
*
|
|
58
91
|
* @param raw Raw FIX wire string (SOH-delimited).
|
|
59
92
|
* @param opts Optional parse options.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* const dd = DataDictionary.fromFile('./spec/FIX44.xml');
|
|
97
|
+
* const msg = Message.parse(raw, { dictionary: dd });
|
|
98
|
+
* msg.getGroup(1, FIELD.NoPartyIDs).getField(FIELD.PartyID);
|
|
99
|
+
* ```
|
|
60
100
|
*/
|
|
61
101
|
static parse(raw: string, opts?: MessageParseOptions): Message;
|
|
62
102
|
/** @internal Wrap an existing native message handle (used by the engine bridge). */
|
|
@@ -64,12 +104,97 @@ export declare class Message {
|
|
|
64
104
|
/** @internal The native handle backing this message (for the engine / sendToTarget / validation). */
|
|
65
105
|
get nativeHandle(): NativeMessage;
|
|
66
106
|
/**
|
|
67
|
-
* Read a
|
|
68
|
-
*
|
|
107
|
+
* Read a field by tag. Standard header/trailer tags (`MsgType`,
|
|
108
|
+
* `SenderCompID`, `CheckSum`, ...) are read from their section, and so are
|
|
109
|
+
* the header/trailer fields of the session dictionary the message was
|
|
110
|
+
* parsed with (`sessionDictionary` / `dictionary`) or delivered with (a
|
|
111
|
+
* message handed to an engine handler). Any other tag is read from the body,
|
|
112
|
+
* or from the header or trailer if that is where it is.
|
|
113
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) if absent.
|
|
69
114
|
*/
|
|
70
115
|
getField(tag: number): string;
|
|
71
|
-
/**
|
|
116
|
+
/**
|
|
117
|
+
* Set a field. Standard header/trailer tags and the session dictionary's
|
|
118
|
+
* header/trailer fields auto-route to their section (see
|
|
119
|
+
* {@link Message.getField}). Any other tag is updated in place if the header
|
|
120
|
+
* or trailer already holds it; otherwise it goes to the body. On a message
|
|
121
|
+
* without a session dictionary (built with `new Message()`), put a new
|
|
122
|
+
* custom header field in the header with {@link Message.setHeaderField}.
|
|
123
|
+
* Returns `this` for chaining.
|
|
124
|
+
*/
|
|
72
125
|
setField(tag: number, value: string | number): this;
|
|
126
|
+
/** Whether a field is present (same auto-routing as {@link Message.getField}). */
|
|
127
|
+
isSetField(tag: number): boolean;
|
|
128
|
+
/** Remove a field (no-op if absent; same auto-routing). Returns `this` for chaining. */
|
|
129
|
+
removeField(tag: number): this;
|
|
130
|
+
/** Read a field by tag, or `undefined` if absent (same auto-routing). */
|
|
131
|
+
getFieldIfSet(tag: number): string | undefined;
|
|
132
|
+
/** Whether the header, body and trailer have no fields of their own. */
|
|
133
|
+
isEmpty(): boolean;
|
|
134
|
+
/** The number of body fields, including every field of every group entry. */
|
|
135
|
+
totalFields(): number;
|
|
136
|
+
/** Remove every header, body and trailer field and group. Returns `this` for chaining. */
|
|
137
|
+
clear(): this;
|
|
138
|
+
/** The body's own fields, in wire order, as `[tag, value]` pairs (group entries excluded). */
|
|
139
|
+
fields(): [number, string][];
|
|
140
|
+
/** The header fields, in wire order, as `[tag, value]` pairs. */
|
|
141
|
+
headerFields(): [number, string][];
|
|
142
|
+
/** The trailer fields, in wire order, as `[tag, value]` pairs. */
|
|
143
|
+
trailerFields(): [number, string][];
|
|
144
|
+
/** Iterates the body's own fields as `[tag, value]` pairs (see {@link Message.fields}). */
|
|
145
|
+
[Symbol.iterator](): IterableIterator<[number, string]>;
|
|
146
|
+
/**
|
|
147
|
+
* Append a repeating-group entry under its count tag (`group.field`). A copy
|
|
148
|
+
* is stored and the count field is updated. Header groups (e.g. `NoHops`)
|
|
149
|
+
* auto-route to the header. Returns `this` for chaining.
|
|
150
|
+
*
|
|
151
|
+
* @throws `TypeError` when `group.delim` differs from the delimiter of the
|
|
152
|
+
* entries already stored under `group.field`.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* order.addGroup(new Group(FIELD.NoPartyIDs, FIELD.PartyID).setField(FIELD.PartyID, 'X'));
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
addGroup(group: Group): this;
|
|
160
|
+
/**
|
|
161
|
+
* A **snapshot copy** of the `index`-th entry (1-based) of the repeating
|
|
162
|
+
* group `tag`. Mutating the returned {@link Group} does not change this
|
|
163
|
+
* message; write it back with {@link Message.replaceGroup}.
|
|
164
|
+
*
|
|
165
|
+
* Groups exist only on messages built with {@link Message.addGroup} or
|
|
166
|
+
* parsed with a dictionary, which includes every message the engine hands
|
|
167
|
+
* to your handlers when the session has `UseDataDictionary=Y` (the
|
|
168
|
+
* default); a flat parse, or `UseDataDictionary=N`, leaves none.
|
|
169
|
+
*
|
|
170
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when the tag
|
|
171
|
+
* has no entries or `index` is out of range.
|
|
172
|
+
*/
|
|
173
|
+
getGroup(index: number, tag: number): Group;
|
|
174
|
+
/**
|
|
175
|
+
* Overwrite the `index`-th entry (1-based) under `group.field` with a copy of
|
|
176
|
+
* `group`. Returns `this` for chaining.
|
|
177
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when that
|
|
178
|
+
* entry does not exist.
|
|
179
|
+
* @throws `TypeError` when `group.delim` differs from the stored entry's
|
|
180
|
+
* delimiter.
|
|
181
|
+
*/
|
|
182
|
+
replaceGroup(index: number, group: Group): this;
|
|
183
|
+
/**
|
|
184
|
+
* Remove every entry of the repeating group `tag` (and its count field), or
|
|
185
|
+
* only the `index`-th entry (1-based). Returns `this`.
|
|
186
|
+
*
|
|
187
|
+
* Removing every entry of a tag that has none is a no-op.
|
|
188
|
+
* @throws A `QuickFixError` (`fixErrorName: 'FieldNotFound'`) when the
|
|
189
|
+
* `index`-th entry does not exist.
|
|
190
|
+
*/
|
|
191
|
+
removeGroup(tag: number): this;
|
|
192
|
+
removeGroup(index: number, tag: number): this;
|
|
193
|
+
/** Whether the repeating group `tag` has any entry, or has an `index`-th entry (1-based). */
|
|
194
|
+
hasGroup(tag: number): boolean;
|
|
195
|
+
hasGroup(index: number, tag: number): boolean;
|
|
196
|
+
/** The number of entries of the repeating group `tag` (0 if none). */
|
|
197
|
+
groupCount(tag: number): number;
|
|
73
198
|
/**
|
|
74
199
|
* Read a header field by tag.
|
|
75
200
|
* @throws A `QuickFixError` (`fixError: 'FieldNotFound'`) if absent.
|
|
@@ -111,4 +236,3 @@ export declare function createMessage(fields?: Record<number, string | number>):
|
|
|
111
236
|
* Parse a raw FIX wire string into a {@link Message}. Alias of {@link Message.parse}.
|
|
112
237
|
*/
|
|
113
238
|
export declare function parseMessage(raw: string, opts?: MessageParseOptions): Message;
|
|
114
|
-
//# sourceMappingURL=message.d.ts.map
|