@fintekkers/ledger-models 0.1.132 → 0.1.134

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 (44) hide show
  1. package/node/fintekkers/models/security/asset_class_grpc_pb.js +1 -0
  2. package/node/fintekkers/models/security/asset_class_pb.d.ts +15 -0
  3. package/node/fintekkers/models/security/asset_class_pb.js +36 -0
  4. package/node/fintekkers/models/security/security_pb.d.ts +6 -0
  5. package/node/fintekkers/models/security/security_pb.js +51 -0
  6. package/node/fintekkers/requests/price/query_price_request_pb.d.ts +3 -0
  7. package/node/fintekkers/requests/price/query_price_request_pb.js +31 -1
  8. package/node/fintekkers/requests/price/query_price_response_pb.d.ts +7 -0
  9. package/node/fintekkers/requests/price/query_price_response_pb.js +54 -1
  10. package/node/wrappers/models/security/BondSecurity.d.ts +8 -0
  11. package/node/wrappers/models/security/BondSecurity.js +13 -0
  12. package/node/wrappers/models/security/BondSecurity.js.map +1 -1
  13. package/node/wrappers/models/security/BondSecurity.ts +13 -0
  14. package/node/wrappers/models/security/asset_class.d.ts +37 -0
  15. package/node/wrappers/models/security/asset_class.js +51 -0
  16. package/node/wrappers/models/security/asset_class.js.map +1 -0
  17. package/node/wrappers/models/security/asset_class.test.d.ts +1 -0
  18. package/node/wrappers/models/security/asset_class.test.js +52 -0
  19. package/node/wrappers/models/security/asset_class.test.js.map +1 -0
  20. package/node/wrappers/models/security/asset_class.test.ts +58 -0
  21. package/node/wrappers/models/security/asset_class.ts +53 -0
  22. package/node/wrappers/models/security/identifier.d.ts +26 -0
  23. package/node/wrappers/models/security/identifier.js +39 -0
  24. package/node/wrappers/models/security/identifier.js.map +1 -1
  25. package/node/wrappers/models/security/identifier.test.js +62 -0
  26. package/node/wrappers/models/security/identifier.test.js.map +1 -1
  27. package/node/wrappers/models/security/identifier.test.ts +70 -0
  28. package/node/wrappers/models/security/identifier.ts +44 -0
  29. package/node/wrappers/models/security/security.d.ts +36 -1
  30. package/node/wrappers/models/security/security.js +45 -2
  31. package/node/wrappers/models/security/security.js.map +1 -1
  32. package/node/wrappers/models/security/security.test.js +72 -0
  33. package/node/wrappers/models/security/security.test.js.map +1 -1
  34. package/node/wrappers/models/security/security.test.ts +80 -0
  35. package/node/wrappers/models/security/security.ts +47 -3
  36. package/node/wrappers/models/security/security_type.d.ts +31 -0
  37. package/node/wrappers/models/security/security_type.js +45 -0
  38. package/node/wrappers/models/security/security_type.js.map +1 -0
  39. package/node/wrappers/models/security/security_type.test.d.ts +1 -0
  40. package/node/wrappers/models/security/security_type.test.js +64 -0
  41. package/node/wrappers/models/security/security_type.test.js.map +1 -0
  42. package/node/wrappers/models/security/security_type.test.ts +70 -0
  43. package/node/wrappers/models/security/security_type.ts +47 -0
  44. package/package.json +1 -1
@@ -3,9 +3,11 @@ import { UUID } from '../utils/uuid';
3
3
 
4
4
  import assert = require('assert');
5
5
  import Security from './security';
6
+ import BondSecurity from './BondSecurity';
6
7
 
7
8
  import { DecimalValueProto } from '../../../fintekkers/models/util/decimal_value_pb';
8
9
  import { SecurityProto } from '../../../fintekkers/models/security/security_pb';
10
+ import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
9
11
  import { CouponFrequencyProto } from '../../../fintekkers/models/security/coupon_frequency_pb';
10
12
  import { CouponTypeProto } from '../../../fintekkers/models/security/coupon_type_pb';
11
13
  import { SecurityQuantityTypeProto } from '../../../fintekkers/models/security/security_quantity_type_pb';
@@ -21,6 +23,52 @@ function testSerialization(): void {
21
23
  assert(security.getMaturityDate().toDate().getFullYear() == 2026);
22
24
  }
23
25
 
26
+ test('equity routes to base Security and isBond() returns false', () => {
27
+ const equity = dummyEquity();
28
+ expect(equity).toBeInstanceOf(Security);
29
+ expect(equity).not.toBeInstanceOf(BondSecurity);
30
+ expect(equity.isBond()).toBe(false);
31
+ });
32
+
33
+ test('bond routes to BondSecurity and isBond() returns true (narrows type)', () => {
34
+ const bond = dummyBondSecurity();
35
+ expect(bond.isBond()).toBe(true);
36
+ if (bond.isBond()) {
37
+ // Inside the narrowed branch TS knows bond: BondSecurity.
38
+ // Calling a BondSecurity-only method here proves the narrowing works.
39
+ expect(bond.getCouponRate()).toBeDefined();
40
+ }
41
+ });
42
+
43
+ test('Security.getIssueDate returns null on equity (no throw)', () => {
44
+ const equity = dummyEquity();
45
+ // Phase 1 behavior change: was throw "Issue date is required", now returns null.
46
+ // This is the symptom fix that motivated #205 — equity wrappers no longer
47
+ // explode on per-record post-processing in ui-service.
48
+ expect(equity.getIssueDate()).toBeNull();
49
+ });
50
+
51
+ test('BondSecurity.getIssueDate returns LocalDate (non-nullable) on bond', () => {
52
+ const bond = dummyBondSecurity();
53
+ if (!bond.isBond()) throw new Error('test setup: expected bond');
54
+ const issueDate = bond.getIssueDate();
55
+ expect(issueDate).not.toBeNull();
56
+ expect(issueDate.toDate().getFullYear()).toBe(2021);
57
+ });
58
+
59
+ test('Security.getMaturityDate still throws on equity (Phase 1 deprecation, not removal)', () => {
60
+ const equity = dummyEquity();
61
+ // Behavior preserved deliberately for Phase 1 — callers still get a
62
+ // loud error if they don't narrow first. Removal happens in Phase 2.
63
+ expect(() => equity.getMaturityDate()).toThrow('Maturity date is required');
64
+ });
65
+
66
+ test('BondSecurity.getMaturityDate works on bond (inherited from Security)', () => {
67
+ const bond = dummyBondSecurity();
68
+ if (!bond.isBond()) throw new Error('test setup: expected bond');
69
+ expect(bond.getMaturityDate().toDate().getFullYear()).toBe(2026);
70
+ });
71
+
24
72
  function dummySecurity() {
25
73
  return Security.create(new SecurityProto()
26
74
  .setObjectClass('Transaction').setVersion('0.0.1').setUuid(UUID.random().toUUIDProto())
@@ -39,3 +87,35 @@ function dummySecurity() {
39
87
  );
40
88
  }
41
89
 
90
+ function dummyBondSecurity() {
91
+ // Same dummy security but with securityType set so the factory routes
92
+ // to BondSecurity.
93
+ return Security.create(new SecurityProto()
94
+ .setObjectClass('Security').setVersion('0.0.1').setUuid(UUID.random().toUUIDProto())
95
+ .setSecurityType(SecurityTypeProto.BOND_SECURITY)
96
+ .setFaceValue(new DecimalValueProto().setArbitraryPrecisionValue('1000.00'))
97
+ .setQuantityType(SecurityQuantityTypeProto.ORIGINAL_FACE_VALUE)
98
+ .setAssetClass("Bond")
99
+ .setIssuerName("Dummy issuer")
100
+ .setCouponRate(new DecimalValueProto().setArbitraryPrecisionValue('0.05'))
101
+ .setCouponFrequency(CouponFrequencyProto.SEMIANNUALLY)
102
+ .setCouponType(CouponTypeProto.FIXED)
103
+ .setMaturityDate(new LocalDateProto().setYear(2026).setMonth(1).setDay(1))
104
+ .setIssueDate(new LocalDateProto().setYear(2021).setMonth(1).setDay(1))
105
+ .setDescription("Dummy bond")
106
+ );
107
+ }
108
+
109
+ function dummyEquity() {
110
+ // Equity has no maturity / issue date in the proto, exercising the
111
+ // null-return behavior on getIssueDate and the throw-on-missing
112
+ // behavior on getMaturityDate.
113
+ return Security.create(new SecurityProto()
114
+ .setObjectClass('Security').setVersion('0.0.1').setUuid(UUID.random().toUUIDProto())
115
+ .setSecurityType(SecurityTypeProto.EQUITY_SECURITY)
116
+ .setAssetClass("Equity")
117
+ .setIssuerName("Dummy issuer Inc.")
118
+ .setDescription("Dummy equity")
119
+ );
120
+ }
121
+
@@ -29,6 +29,25 @@ class Security {
29
29
  }
30
30
  }
31
31
 
32
+ /**
33
+ * Type guard: true iff this Security is a BondSecurity (BOND_SECURITY,
34
+ * TIPS, or FRN). Use to narrow before calling bond-specific getters:
35
+ *
36
+ * if (sec.isBond()) {
37
+ * // sec: BondSecurity here — TS knows about getCouponRate(), etc.
38
+ * console.log(sec.getMaturityDate());
39
+ * }
40
+ *
41
+ * Implemented as a runtime check on the proto's securityType so it
42
+ * works regardless of how the wrapper was constructed.
43
+ */
44
+ isBond(): this is import('./BondSecurity').default {
45
+ const t = this.proto.getSecurityType();
46
+ return t === SecurityTypeProto.BOND_SECURITY
47
+ || t === SecurityTypeProto.TIPS
48
+ || t === SecurityTypeProto.FRN;
49
+ }
50
+
32
51
 
33
52
  toString(): string {
34
53
  return `ID[${this.getID().toString()}], ${this.getSecurityID()}[${this.getIssuerName()}]`;
@@ -57,8 +76,11 @@ class Security {
57
76
  case FieldProto.ADJUSTED_TENOR:
58
77
  throw new Error('Not implemented yet');
59
78
  case FieldProto.MATURITY_DATE:
60
- return this.getMaturityDate();
79
+ // Maturity date is bond-only. Mirror Java's Security.getField:
80
+ // delegate to BondSecurity, return null for non-bonds.
81
+ return this.isBond() ? this.getMaturityDate() : null;
61
82
  case FieldProto.ISSUE_DATE:
83
+ // getIssueDate already returns null on non-bonds; just forward.
62
84
  return this.getIssueDate();
63
85
  default:
64
86
  throw new Error(`Field not mapped in Security wrapper: ${field}`);
@@ -109,14 +131,36 @@ class Security {
109
131
  return identifier;
110
132
  }
111
133
 
112
- getIssueDate(): LocalDate {
134
+ /**
135
+ * Returns the issue date if set, else null. Per-type semantic:
136
+ * - Bond / TIPS / FRN: auction date.
137
+ * - Equity: IPO listing date (when present in source data).
138
+ * - CPI series: first observation date.
139
+ * - Cash / FX: typically null.
140
+ *
141
+ * Returns null on equities/cash/etc. that don't have an issue date set,
142
+ * rather than throwing — issue date is optional on the base Security.
143
+ * For bond-specific code paths, prefer narrowing first via isBond() and
144
+ * calling BondSecurity.getIssueDate() (which returns LocalDate, not null).
145
+ */
146
+ getIssueDate(): LocalDate | null {
113
147
  // Prefer oneof bond sub-message if available, fall back to flat fields
114
148
  const bond = this.getBondLikeDetails();
115
149
  const date = bond ? bond.getIssueDate() : this.proto.getIssueDate();
116
- if (!date) throw new Error("Issue date is required");
150
+ if (!date) return null;
117
151
  return new LocalDate(date);
118
152
  }
119
153
 
154
+ /**
155
+ * @deprecated Maturity date is a bond-only concept. On the base Security
156
+ * this still throws when unset for backwards compatibility. Prefer
157
+ * narrowing first:
158
+ *
159
+ * if (sec.isBond()) sec.getMaturityDate(); // BondSecurity, returns LocalDate
160
+ *
161
+ * In a future major version this method will move to BondSecurity only
162
+ * and TS will catch the misuse at compile time.
163
+ */
120
164
  getMaturityDate(): LocalDate {
121
165
  // Prefer oneof bond sub-message if available, fall back to flat fields
122
166
  const bond = this.getBondLikeDetails();
@@ -0,0 +1,31 @@
1
+ import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
2
+ /**
3
+ * Static helpers around the SecurityType proto enum, mirroring the
4
+ * Identifier wrapper pattern shipped in v0.1.133 (PR #188).
5
+ *
6
+ * Lets TS/JS consumers stop hand-typing literal unions and switch
7
+ * statements over `'BOND_SECURITY' | 'TIPS' | 'FRN' | ...` — adding a
8
+ * new variant on the proto side propagates automatically.
9
+ */
10
+ export declare class SecurityType {
11
+ /**
12
+ * Returns the names of all known SecurityTypeProto values, EXCLUDING
13
+ * the sentinel `UNKNOWN_SECURITY_TYPE`. Drives UI dropdowns / pickers
14
+ * so a new proto enum variant auto-propagates to consumers without
15
+ * any UI-side code change.
16
+ *
17
+ * Order matches proto declaration order (Object.keys preserves
18
+ * insertion order on the generated JS enum object).
19
+ */
20
+ static getAllTypeNames(): string[];
21
+ /**
22
+ * Resolve a proto enum NAME (e.g., "BOND_SECURITY", "EQUITY_SECURITY")
23
+ * to its numeric SecurityTypeProto value. Throws on unknown name; the
24
+ * error lists the valid names so typos are fixable without grepping
25
+ * the proto.
26
+ *
27
+ * @param name proto enum key (e.g., "BOND_SECURITY")
28
+ * @returns the numeric SecurityTypeProto value
29
+ */
30
+ static fromName(name: string): SecurityTypeProto;
31
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SecurityType = void 0;
4
+ const security_type_pb_1 = require("../../../fintekkers/models/security/security_type_pb");
5
+ /**
6
+ * Static helpers around the SecurityType proto enum, mirroring the
7
+ * Identifier wrapper pattern shipped in v0.1.133 (PR #188).
8
+ *
9
+ * Lets TS/JS consumers stop hand-typing literal unions and switch
10
+ * statements over `'BOND_SECURITY' | 'TIPS' | 'FRN' | ...` — adding a
11
+ * new variant on the proto side propagates automatically.
12
+ */
13
+ class SecurityType {
14
+ /**
15
+ * Returns the names of all known SecurityTypeProto values, EXCLUDING
16
+ * the sentinel `UNKNOWN_SECURITY_TYPE`. Drives UI dropdowns / pickers
17
+ * so a new proto enum variant auto-propagates to consumers without
18
+ * any UI-side code change.
19
+ *
20
+ * Order matches proto declaration order (Object.keys preserves
21
+ * insertion order on the generated JS enum object).
22
+ */
23
+ static getAllTypeNames() {
24
+ return Object.keys(security_type_pb_1.SecurityTypeProto).filter(k => k !== 'UNKNOWN_SECURITY_TYPE');
25
+ }
26
+ /**
27
+ * Resolve a proto enum NAME (e.g., "BOND_SECURITY", "EQUITY_SECURITY")
28
+ * to its numeric SecurityTypeProto value. Throws on unknown name; the
29
+ * error lists the valid names so typos are fixable without grepping
30
+ * the proto.
31
+ *
32
+ * @param name proto enum key (e.g., "BOND_SECURITY")
33
+ * @returns the numeric SecurityTypeProto value
34
+ */
35
+ static fromName(name) {
36
+ const enumObj = security_type_pb_1.SecurityTypeProto;
37
+ const enumValue = enumObj[name];
38
+ if (enumValue === undefined) {
39
+ throw new Error(`Unknown SecurityType name: '${name}'. Valid names: ${SecurityType.getAllTypeNames().join(', ')}`);
40
+ }
41
+ return enumValue;
42
+ }
43
+ }
44
+ exports.SecurityType = SecurityType;
45
+ //# sourceMappingURL=security_type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security_type.js","sourceRoot":"","sources":["security_type.ts"],"names":[],"mappings":";;;AAAA,2FAAyF;AAEzF;;;;;;;GAOG;AACH,MAAa,YAAY;IAErB;;;;;;;;OAQG;IACH,MAAM,CAAC,eAAe;QAClB,OAAO,MAAM,CAAC,IAAI,CAAC,oCAAiB,CAAC,CAAC,MAAM,CACxC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,uBAAuB,CACrC,CAAC;IACN,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAY;QACxB,MAAM,OAAO,GAAG,oCAAsD,CAAC;QACvE,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,SAAS,KAAK,SAAS,EAAE;YACzB,MAAM,IAAI,KAAK,CACX,+BAA+B,IAAI,mBAAmB,YAAY,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpG,CAAC;SACL;QACD,OAAO,SAA8B,CAAC;IAC1C,CAAC;CACJ;AApCD,oCAoCC"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const security_type_1 = require("./security_type");
4
+ const security_type_pb_1 = require("../../../fintekkers/models/security/security_type_pb");
5
+ describe('SecurityType.fromName', () => {
6
+ // Round-trip: every name returned by getAllTypeNames must resolve to
7
+ // a numeric enum value that maps back to the same name.
8
+ test.each(security_type_1.SecurityType.getAllTypeNames())('fromName("%s") returns the matching numeric enum value', (name) => {
9
+ const value = security_type_1.SecurityType.fromName(name);
10
+ // The proto-generated enum is bidirectionally indexable
11
+ // (Object.keys / numeric-key lookups both work in google-protobuf JS).
12
+ const expected = security_type_pb_1.SecurityTypeProto[name];
13
+ expect(value).toBe(expected);
14
+ });
15
+ test('throws on unknown name and lists valid names in the error', () => {
16
+ let err;
17
+ try {
18
+ security_type_1.SecurityType.fromName('NOT_A_REAL_TYPE');
19
+ }
20
+ catch (e) {
21
+ err = e;
22
+ }
23
+ expect(err).toBeDefined();
24
+ expect(err.message).toContain('NOT_A_REAL_TYPE');
25
+ // Error message should hint with known valid entries.
26
+ expect(err.message).toContain('BOND_SECURITY');
27
+ expect(err.message).toContain('EQUITY_SECURITY');
28
+ });
29
+ test('accepts UNKNOWN_SECURITY_TYPE — sentinel is a valid enum key', () => {
30
+ // It's excluded from getAllTypeNames (so it doesn't appear in
31
+ // dropdowns), but it IS a valid proto enum value, so fromName
32
+ // accepts it. Pinning the existing behavior — flip if policy
33
+ // ever tightens.
34
+ expect(security_type_1.SecurityType.fromName('UNKNOWN_SECURITY_TYPE')).toBe(security_type_pb_1.SecurityTypeProto.UNKNOWN_SECURITY_TYPE);
35
+ });
36
+ });
37
+ describe('SecurityType.getAllTypeNames', () => {
38
+ test('returns the expected set in proto-declaration order, excluding UNKNOWN', () => {
39
+ // Proto-declared order in security_type.proto:
40
+ // UNKNOWN_SECURITY_TYPE = 0; (excluded)
41
+ // CASH_SECURITY = 1;
42
+ // EQUITY_SECURITY = 2;
43
+ // BOND_SECURITY = 3;
44
+ // TIPS = 4;
45
+ // FRN = 5;
46
+ // INDEX_SECURITY = 6;
47
+ // FX_SPOT = 7;
48
+ // EQUITY_INDEX_SECURITY = 8;
49
+ expect(security_type_1.SecurityType.getAllTypeNames()).toEqual([
50
+ 'CASH_SECURITY',
51
+ 'EQUITY_SECURITY',
52
+ 'BOND_SECURITY',
53
+ 'TIPS',
54
+ 'FRN',
55
+ 'INDEX_SECURITY',
56
+ 'FX_SPOT',
57
+ 'EQUITY_INDEX_SECURITY',
58
+ ]);
59
+ });
60
+ test('excludes the UNKNOWN_SECURITY_TYPE sentinel', () => {
61
+ expect(security_type_1.SecurityType.getAllTypeNames()).not.toContain('UNKNOWN_SECURITY_TYPE');
62
+ });
63
+ });
64
+ //# sourceMappingURL=security_type.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security_type.test.js","sourceRoot":"","sources":["security_type.test.ts"],"names":[],"mappings":";;AAAA,mDAA+C;AAC/C,2FAAyF;AAEzF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACnC,qEAAqE;IACrE,wDAAwD;IACxD,IAAI,CAAC,IAAI,CAAC,4BAAY,CAAC,eAAe,EAAE,CAAC,CACrC,wDAAwD,EACxD,CAAC,IAAY,EAAE,EAAE;QACb,MAAM,KAAK,GAAG,4BAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1C,wDAAwD;QACxD,uEAAuE;QACvE,MAAM,QAAQ,GAAI,oCAAuD,CAAC,IAAI,CAAC,CAAC;QAChF,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC,CACJ,CAAC;IAEF,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,IAAI,GAAsB,CAAC;QAC3B,IAAI;YACA,4BAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;SAC5C;QAAC,OAAO,CAAC,EAAE;YACR,GAAG,GAAG,CAAU,CAAC;SACpB;QACD,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAClD,sDAAsD;QACtD,MAAM,CAAC,GAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAChD,MAAM,CAAC,GAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,8DAA8D;QAC9D,8DAA8D;QAC9D,6DAA6D;QAC7D,iBAAiB;QACjB,MAAM,CAAC,4BAAY,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CACvD,oCAAiB,CAAC,qBAAqB,CAC1C,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC1C,IAAI,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,+CAA+C;QAC/C,2CAA2C;QAC3C,uBAAuB;QACvB,yBAAyB;QACzB,uBAAuB;QACvB,cAAc;QACd,aAAa;QACb,wBAAwB;QACxB,iBAAiB;QACjB,+BAA+B;QAC/B,MAAM,CAAC,4BAAY,CAAC,eAAe,EAAE,CAAC,CAAC,OAAO,CAAC;YAC3C,eAAe;YACf,iBAAiB;YACjB,eAAe;YACf,MAAM;YACN,KAAK;YACL,gBAAgB;YAChB,SAAS;YACT,uBAAuB;SAC1B,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,4BAAY,CAAC,eAAe,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { SecurityType } from './security_type';
2
+ import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
3
+
4
+ describe('SecurityType.fromName', () => {
5
+ // Round-trip: every name returned by getAllTypeNames must resolve to
6
+ // a numeric enum value that maps back to the same name.
7
+ test.each(SecurityType.getAllTypeNames())(
8
+ 'fromName("%s") returns the matching numeric enum value',
9
+ (name: string) => {
10
+ const value = SecurityType.fromName(name);
11
+ // The proto-generated enum is bidirectionally indexable
12
+ // (Object.keys / numeric-key lookups both work in google-protobuf JS).
13
+ const expected = (SecurityTypeProto as unknown as Record<string, number>)[name];
14
+ expect(value).toBe(expected);
15
+ }
16
+ );
17
+
18
+ test('throws on unknown name and lists valid names in the error', () => {
19
+ let err: Error | undefined;
20
+ try {
21
+ SecurityType.fromName('NOT_A_REAL_TYPE');
22
+ } catch (e) {
23
+ err = e as Error;
24
+ }
25
+ expect(err).toBeDefined();
26
+ expect(err!.message).toContain('NOT_A_REAL_TYPE');
27
+ // Error message should hint with known valid entries.
28
+ expect(err!.message).toContain('BOND_SECURITY');
29
+ expect(err!.message).toContain('EQUITY_SECURITY');
30
+ });
31
+
32
+ test('accepts UNKNOWN_SECURITY_TYPE — sentinel is a valid enum key', () => {
33
+ // It's excluded from getAllTypeNames (so it doesn't appear in
34
+ // dropdowns), but it IS a valid proto enum value, so fromName
35
+ // accepts it. Pinning the existing behavior — flip if policy
36
+ // ever tightens.
37
+ expect(SecurityType.fromName('UNKNOWN_SECURITY_TYPE')).toBe(
38
+ SecurityTypeProto.UNKNOWN_SECURITY_TYPE
39
+ );
40
+ });
41
+ });
42
+
43
+ describe('SecurityType.getAllTypeNames', () => {
44
+ test('returns the expected set in proto-declaration order, excluding UNKNOWN', () => {
45
+ // Proto-declared order in security_type.proto:
46
+ // UNKNOWN_SECURITY_TYPE = 0; (excluded)
47
+ // CASH_SECURITY = 1;
48
+ // EQUITY_SECURITY = 2;
49
+ // BOND_SECURITY = 3;
50
+ // TIPS = 4;
51
+ // FRN = 5;
52
+ // INDEX_SECURITY = 6;
53
+ // FX_SPOT = 7;
54
+ // EQUITY_INDEX_SECURITY = 8;
55
+ expect(SecurityType.getAllTypeNames()).toEqual([
56
+ 'CASH_SECURITY',
57
+ 'EQUITY_SECURITY',
58
+ 'BOND_SECURITY',
59
+ 'TIPS',
60
+ 'FRN',
61
+ 'INDEX_SECURITY',
62
+ 'FX_SPOT',
63
+ 'EQUITY_INDEX_SECURITY',
64
+ ]);
65
+ });
66
+
67
+ test('excludes the UNKNOWN_SECURITY_TYPE sentinel', () => {
68
+ expect(SecurityType.getAllTypeNames()).not.toContain('UNKNOWN_SECURITY_TYPE');
69
+ });
70
+ });
@@ -0,0 +1,47 @@
1
+ import { SecurityTypeProto } from '../../../fintekkers/models/security/security_type_pb';
2
+
3
+ /**
4
+ * Static helpers around the SecurityType proto enum, mirroring the
5
+ * Identifier wrapper pattern shipped in v0.1.133 (PR #188).
6
+ *
7
+ * Lets TS/JS consumers stop hand-typing literal unions and switch
8
+ * statements over `'BOND_SECURITY' | 'TIPS' | 'FRN' | ...` — adding a
9
+ * new variant on the proto side propagates automatically.
10
+ */
11
+ export class SecurityType {
12
+
13
+ /**
14
+ * Returns the names of all known SecurityTypeProto values, EXCLUDING
15
+ * the sentinel `UNKNOWN_SECURITY_TYPE`. Drives UI dropdowns / pickers
16
+ * so a new proto enum variant auto-propagates to consumers without
17
+ * any UI-side code change.
18
+ *
19
+ * Order matches proto declaration order (Object.keys preserves
20
+ * insertion order on the generated JS enum object).
21
+ */
22
+ static getAllTypeNames(): string[] {
23
+ return Object.keys(SecurityTypeProto).filter(
24
+ k => k !== 'UNKNOWN_SECURITY_TYPE'
25
+ );
26
+ }
27
+
28
+ /**
29
+ * Resolve a proto enum NAME (e.g., "BOND_SECURITY", "EQUITY_SECURITY")
30
+ * to its numeric SecurityTypeProto value. Throws on unknown name; the
31
+ * error lists the valid names so typos are fixable without grepping
32
+ * the proto.
33
+ *
34
+ * @param name proto enum key (e.g., "BOND_SECURITY")
35
+ * @returns the numeric SecurityTypeProto value
36
+ */
37
+ static fromName(name: string): SecurityTypeProto {
38
+ const enumObj = SecurityTypeProto as unknown as Record<string, number>;
39
+ const enumValue = enumObj[name];
40
+ if (enumValue === undefined) {
41
+ throw new Error(
42
+ `Unknown SecurityType name: '${name}'. Valid names: ${SecurityType.getAllTypeNames().join(', ')}`
43
+ );
44
+ }
45
+ return enumValue as SecurityTypeProto;
46
+ }
47
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fintekkers/ledger-models",
3
3
  "todo": "Replace the version with build script version number",
4
- "version": "0.1.132",
4
+ "version": "0.1.134",
5
5
  "description": "ledger model protos ",
6
6
  "authors": [
7
7
  "David Doherty",