@fintekkers/ledger-models 0.4.51 → 0.4.52
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/node/wrappers/models/errors.js +4 -2
- package/node/wrappers/models/errors.js.map +1 -1
- package/node/wrappers/models/errors.ts +3 -2
- package/node/wrappers/models/utils/uuid.d.ts +10 -0
- package/node/wrappers/models/utils/uuid.js +26 -0
- package/node/wrappers/models/utils/uuid.js.map +1 -1
- package/node/wrappers/models/utils/uuid.test.js +55 -0
- package/node/wrappers/models/utils/uuid.test.js.map +1 -1
- package/node/wrappers/models/utils/uuid.test.ts +64 -0
- package/node/wrappers/models/utils/uuid.ts +26 -0
- package/package.json +1 -1
|
@@ -42,7 +42,9 @@ function violation(field, objectId, message) {
|
|
|
42
42
|
}
|
|
43
43
|
exports.violation = violation;
|
|
44
44
|
function objectIdOf(v) {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
var _a;
|
|
46
|
+
const raw = (_a = v.getObjectId()) === null || _a === void 0 ? void 0 : _a.getRawUuid_asU8();
|
|
47
|
+
// A malformed id must not stop the error for another field being built (LM-334).
|
|
48
|
+
return raw && raw.length === 16 ? uuid_1.UUID.fromU8Array(raw).toString() : undefined;
|
|
47
49
|
}
|
|
48
50
|
//# sourceMappingURL=errors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["errors.ts"],"names":[],"mappings":";;;AAAA,iGAA+F;AAC/F,uCAAoC;AAEpC;;;;;GAKG;AACH,MAAa,oBAAqB,SAAQ,KAAK;IAG3C,yEAAyE;IACzE,YAAY,UAAiC;QACzC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;YACzB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;SACxE;QACD,KAAK,CAAC,UAAU;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,WAAC,OAAA,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,UAAU,EAAE,QAAQ,MAAA,UAAU,CAAC,CAAC,CAAC,mCAAI,MAAM,GAAG,CAAA,EAAA,CAAC;aAC9E,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,0EAA0E;IAC1E,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACzC,CAAC;IAED,sFAAsF;IACtF,IAAI,QAAQ;QACR,OAAO,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;CACJ;AAxBD,oDAwBC;AAED,oFAAoF;AACpF,SAAgB,SAAS,CAAC,KAAa,EAAE,QAA0B,EAAE,OAAe;IAChF,MAAM,CAAC,GAAG,IAAI,wCAAmB,EAAE,CAAC;IACpC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACtB,IAAI,QAAQ;QAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,CAAC;AACb,CAAC;AAND,8BAMC;AAED,SAAS,UAAU,CAAC,CAAsB
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["errors.ts"],"names":[],"mappings":";;;AAAA,iGAA+F;AAC/F,uCAAoC;AAEpC;;;;;GAKG;AACH,MAAa,oBAAqB,SAAQ,KAAK;IAG3C,yEAAyE;IACzE,YAAY,UAAiC;QACzC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;YACzB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;SACxE;QACD,KAAK,CAAC,UAAU;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,WAAC,OAAA,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,UAAU,EAAE,QAAQ,MAAA,UAAU,CAAC,CAAC,CAAC,mCAAI,MAAM,GAAG,CAAA,EAAA,CAAC;aAC9E,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,0EAA0E;IAC1E,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACzC,CAAC;IAED,sFAAsF;IACtF,IAAI,QAAQ;QACR,OAAO,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;CACJ;AAxBD,oDAwBC;AAED,oFAAoF;AACpF,SAAgB,SAAS,CAAC,KAAa,EAAE,QAA0B,EAAE,OAAe;IAChF,MAAM,CAAC,GAAG,IAAI,wCAAmB,EAAE,CAAC;IACpC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACtB,IAAI,QAAQ;QAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,CAAC;AACb,CAAC;AAND,8BAMC;AAED,SAAS,UAAU,CAAC,CAAsB;;IACtC,MAAM,GAAG,GAAG,MAAA,CAAC,CAAC,WAAW,EAAE,0CAAE,eAAe,EAAE,CAAC;IAC/C,iFAAiF;IACjF,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,WAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACnF,CAAC"}
|
|
@@ -43,6 +43,7 @@ export function violation(field: string, objectId: UUID | undefined, message: st
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
function objectIdOf(v: FieldViolationProto): string | undefined {
|
|
46
|
-
const
|
|
47
|
-
|
|
46
|
+
const raw = v.getObjectId()?.getRawUuid_asU8();
|
|
47
|
+
// A malformed id must not stop the error for another field being built (LM-334).
|
|
48
|
+
return raw && raw.length === 16 ? UUID.fromU8Array(raw).toString() : undefined;
|
|
48
49
|
}
|
|
@@ -7,7 +7,17 @@ declare class UUID {
|
|
|
7
7
|
toUUIDProto(): UUIDProto;
|
|
8
8
|
equals(other: UUID): boolean;
|
|
9
9
|
static random(): UUID;
|
|
10
|
+
/**
|
|
11
|
+
* Throws ModelValidationError naming `raw_uuid` when the input is neither
|
|
12
|
+
* empty nor exactly 16 bytes (LM-334). Empty is accepted as before; prefer
|
|
13
|
+
* fromUUIDProto, which reads empty as unset.
|
|
14
|
+
*/
|
|
10
15
|
static fromU8Array(uint8Array: Uint8Array): UUID;
|
|
16
|
+
/**
|
|
17
|
+
* Decodes a UUIDProto (LM-334). Unset or empty raw_uuid is undefined. Any
|
|
18
|
+
* other length but 16 throws ModelValidationError naming `raw_uuid`.
|
|
19
|
+
*/
|
|
20
|
+
static fromUUIDProto(proto?: UUIDProto): UUID | undefined;
|
|
11
21
|
static fromString(uuidString: string): number[];
|
|
12
22
|
}
|
|
13
23
|
export { UUID };
|
|
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.UUID = void 0;
|
|
27
27
|
const uuid_pb_1 = require("../../../fintekkers/models/util/uuid_pb");
|
|
28
28
|
const uuid = __importStar(require("uuid"));
|
|
29
|
+
const errors_1 = require("../errors");
|
|
29
30
|
/**
|
|
30
31
|
* Convert array of 16 byte values to UUID string format of the form:
|
|
31
32
|
* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
@@ -67,10 +68,28 @@ class UUID {
|
|
|
67
68
|
const random = uuid.v4();
|
|
68
69
|
return new UUID(UUID.fromString(random));
|
|
69
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Throws ModelValidationError naming `raw_uuid` when the input is neither
|
|
73
|
+
* empty nor exactly 16 bytes (LM-334). Empty is accepted as before; prefer
|
|
74
|
+
* fromUUIDProto, which reads empty as unset.
|
|
75
|
+
*/
|
|
70
76
|
static fromU8Array(uint8Array) {
|
|
77
|
+
if (uint8Array.length !== 0)
|
|
78
|
+
checkRawUuidLength(uint8Array);
|
|
71
79
|
const array = Array.from(uint8Array, byte => byte);
|
|
72
80
|
return new UUID(array);
|
|
73
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Decodes a UUIDProto (LM-334). Unset or empty raw_uuid is undefined. Any
|
|
84
|
+
* other length but 16 throws ModelValidationError naming `raw_uuid`.
|
|
85
|
+
*/
|
|
86
|
+
static fromUUIDProto(proto) {
|
|
87
|
+
const raw = proto === null || proto === void 0 ? void 0 : proto.getRawUuid_asU8();
|
|
88
|
+
if (!raw || raw.length === 0)
|
|
89
|
+
return undefined;
|
|
90
|
+
checkRawUuidLength(raw);
|
|
91
|
+
return new UUID(Array.from(raw, byte => byte));
|
|
92
|
+
}
|
|
74
93
|
static fromString(uuidString) {
|
|
75
94
|
// Remove hyphens and convert to a continuous hexadecimal string
|
|
76
95
|
const hexString = uuidString.replace(/-/g, '');
|
|
@@ -82,4 +101,11 @@ class UUID {
|
|
|
82
101
|
}
|
|
83
102
|
}
|
|
84
103
|
exports.UUID = UUID;
|
|
104
|
+
function checkRawUuidLength(raw) {
|
|
105
|
+
if (raw.length !== 16) {
|
|
106
|
+
throw new errors_1.ModelValidationError([
|
|
107
|
+
(0, errors_1.violation)('raw_uuid', undefined, `expected 16 bytes but got ${raw.length}`),
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
85
111
|
//# sourceMappingURL=uuid.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uuid.js","sourceRoot":"","sources":["uuid.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qEAAoE;AACpE,2CAA6B;
|
|
1
|
+
{"version":3,"file":"uuid.js","sourceRoot":"","sources":["uuid.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const assert = require("assert");
|
|
4
4
|
const uuid_1 = require("./uuid");
|
|
5
|
+
const uuid_pb_1 = require("../../../fintekkers/models/util/uuid_pb");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
5
7
|
test('test packing/unpacking string', () => {
|
|
6
8
|
const test_uuid_bytes = [217, 98, 253, 240, 51, 225, 77, 157, 153, 155, 126, 195, 80, 240, 203, 119];
|
|
7
9
|
const test_uuid = new uuid_1.UUID(test_uuid_bytes);
|
|
@@ -32,4 +34,57 @@ test('equals returns true for same instance', () => {
|
|
|
32
34
|
const uuid = uuid_1.UUID.random();
|
|
33
35
|
assert(uuid.equals(uuid));
|
|
34
36
|
});
|
|
37
|
+
// LM-334: a raw_uuid that is neither empty nor exactly 16 bytes is a typed
|
|
38
|
+
// input error naming raw_uuid.
|
|
39
|
+
function rawUuid(length) {
|
|
40
|
+
return Uint8Array.from({ length }, (_, i) => i);
|
|
41
|
+
}
|
|
42
|
+
function protoOf(raw) {
|
|
43
|
+
const proto = new uuid_pb_1.UUIDProto();
|
|
44
|
+
proto.setRawUuid(raw);
|
|
45
|
+
return proto;
|
|
46
|
+
}
|
|
47
|
+
function expectRawUuidError(decode, length) {
|
|
48
|
+
let caught;
|
|
49
|
+
try {
|
|
50
|
+
decode();
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
caught = e;
|
|
54
|
+
}
|
|
55
|
+
expect(caught).toBeInstanceOf(errors_1.ModelValidationError);
|
|
56
|
+
const err = caught;
|
|
57
|
+
expect(err.field).toBe('raw_uuid');
|
|
58
|
+
expect(err.message).toContain('raw_uuid');
|
|
59
|
+
expect(err.message).toContain(`got ${length}`);
|
|
60
|
+
}
|
|
61
|
+
test.each([15, 17])('fromUUIDProto rejects %i bytes with ModelValidationError naming raw_uuid', (length) => {
|
|
62
|
+
expectRawUuidError(() => uuid_1.UUID.fromUUIDProto(protoOf(rawUuid(length))), length);
|
|
63
|
+
});
|
|
64
|
+
test('fromUUIDProto decodes 16 bytes in byte order and round-trips', () => {
|
|
65
|
+
expect(uuid_1.UUID.fromUUIDProto(protoOf(rawUuid(16))).toString())
|
|
66
|
+
.toBe('00010203-0405-0607-0809-0a0b0c0d0e0f');
|
|
67
|
+
const original = uuid_1.UUID.random();
|
|
68
|
+
const proto = original.toUUIDProto();
|
|
69
|
+
expect(proto.getRawUuid_asU8().length).toBe(16);
|
|
70
|
+
expect(uuid_1.UUID.fromUUIDProto(proto).equals(original)).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
test('fromUUIDProto returns undefined for unset or empty', () => {
|
|
73
|
+
expect(uuid_1.UUID.fromUUIDProto(undefined)).toBeUndefined();
|
|
74
|
+
expect(uuid_1.UUID.fromUUIDProto(new uuid_pb_1.UUIDProto())).toBeUndefined();
|
|
75
|
+
expect(uuid_1.UUID.fromUUIDProto(protoOf(new Uint8Array(0)))).toBeUndefined();
|
|
76
|
+
});
|
|
77
|
+
test('fromU8Array keeps accepting empty and rejects 17 bytes', () => {
|
|
78
|
+
expect(uuid_1.UUID.fromU8Array(new Uint8Array(0)).toBytes()).toEqual([]);
|
|
79
|
+
expect(uuid_1.UUID.fromU8Array(rawUuid(16)).toString()).toBe('00010203-0405-0607-0809-0a0b0c0d0e0f');
|
|
80
|
+
expectRawUuidError(() => uuid_1.UUID.fromU8Array(rawUuid(17)), 17);
|
|
81
|
+
});
|
|
82
|
+
test('ModelValidationError with a malformed object_id still names its own field', () => {
|
|
83
|
+
const v = (0, errors_1.violation)('price', undefined, 'price is required but unset');
|
|
84
|
+
v.setObjectId(protoOf(rawUuid(17)));
|
|
85
|
+
const err = new errors_1.ModelValidationError([v]);
|
|
86
|
+
expect(err.field).toBe('price');
|
|
87
|
+
expect(err.message).toContain('price: price is required but unset');
|
|
88
|
+
expect(err.objectId).toBeUndefined();
|
|
89
|
+
});
|
|
35
90
|
//# sourceMappingURL=uuid.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uuid.test.js","sourceRoot":"","sources":["uuid.test.ts"],"names":[],"mappings":";;AAAA,iCAAkC;AAClC,iCAA8B;
|
|
1
|
+
{"version":3,"file":"uuid.test.js","sourceRoot":"","sources":["uuid.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import assert = require('assert');
|
|
2
2
|
import { UUID } from './uuid';
|
|
3
|
+
import { UUIDProto } from '../../../fintekkers/models/util/uuid_pb';
|
|
4
|
+
import { FieldViolationProto } from '../../../fintekkers/requests/util/errors/field_violation_pb';
|
|
5
|
+
import { ModelValidationError, violation } from '../errors';
|
|
3
6
|
|
|
4
7
|
test('test packing/unpacking string', () => {
|
|
5
8
|
const test_uuid_bytes = [217, 98, 253, 240, 51, 225, 77, 157, 153, 155, 126, 195, 80, 240, 203, 119];
|
|
@@ -40,3 +43,64 @@ test('equals returns true for same instance', () => {
|
|
|
40
43
|
assert(uuid.equals(uuid));
|
|
41
44
|
});
|
|
42
45
|
|
|
46
|
+
// LM-334: a raw_uuid that is neither empty nor exactly 16 bytes is a typed
|
|
47
|
+
// input error naming raw_uuid.
|
|
48
|
+
|
|
49
|
+
function rawUuid(length: number): Uint8Array {
|
|
50
|
+
return Uint8Array.from({ length }, (_, i) => i);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function protoOf(raw: Uint8Array): UUIDProto {
|
|
54
|
+
const proto = new UUIDProto();
|
|
55
|
+
proto.setRawUuid(raw);
|
|
56
|
+
return proto;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function expectRawUuidError(decode: () => unknown, length: number): void {
|
|
60
|
+
let caught: unknown;
|
|
61
|
+
try {
|
|
62
|
+
decode();
|
|
63
|
+
} catch (e) {
|
|
64
|
+
caught = e;
|
|
65
|
+
}
|
|
66
|
+
expect(caught).toBeInstanceOf(ModelValidationError);
|
|
67
|
+
const err = caught as ModelValidationError;
|
|
68
|
+
expect(err.field).toBe('raw_uuid');
|
|
69
|
+
expect(err.message).toContain('raw_uuid');
|
|
70
|
+
expect(err.message).toContain(`got ${length}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
test.each([15, 17])('fromUUIDProto rejects %i bytes with ModelValidationError naming raw_uuid', (length) => {
|
|
74
|
+
expectRawUuidError(() => UUID.fromUUIDProto(protoOf(rawUuid(length))), length);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('fromUUIDProto decodes 16 bytes in byte order and round-trips', () => {
|
|
78
|
+
expect(UUID.fromUUIDProto(protoOf(rawUuid(16)))!.toString())
|
|
79
|
+
.toBe('00010203-0405-0607-0809-0a0b0c0d0e0f');
|
|
80
|
+
|
|
81
|
+
const original = UUID.random();
|
|
82
|
+
const proto = original.toUUIDProto();
|
|
83
|
+
expect(proto.getRawUuid_asU8().length).toBe(16);
|
|
84
|
+
expect(UUID.fromUUIDProto(proto)!.equals(original)).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('fromUUIDProto returns undefined for unset or empty', () => {
|
|
88
|
+
expect(UUID.fromUUIDProto(undefined)).toBeUndefined();
|
|
89
|
+
expect(UUID.fromUUIDProto(new UUIDProto())).toBeUndefined();
|
|
90
|
+
expect(UUID.fromUUIDProto(protoOf(new Uint8Array(0)))).toBeUndefined();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('fromU8Array keeps accepting empty and rejects 17 bytes', () => {
|
|
94
|
+
expect(UUID.fromU8Array(new Uint8Array(0)).toBytes()).toEqual([]);
|
|
95
|
+
expect(UUID.fromU8Array(rawUuid(16)).toString()).toBe('00010203-0405-0607-0809-0a0b0c0d0e0f');
|
|
96
|
+
expectRawUuidError(() => UUID.fromU8Array(rawUuid(17)), 17);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('ModelValidationError with a malformed object_id still names its own field', () => {
|
|
100
|
+
const v: FieldViolationProto = violation('price', undefined, 'price is required but unset');
|
|
101
|
+
v.setObjectId(protoOf(rawUuid(17)));
|
|
102
|
+
const err = new ModelValidationError([v]);
|
|
103
|
+
expect(err.field).toBe('price');
|
|
104
|
+
expect(err.message).toContain('price: price is required but unset');
|
|
105
|
+
expect(err.objectId).toBeUndefined();
|
|
106
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { UUIDProto } from '../../../fintekkers/models/util/uuid_pb';
|
|
2
2
|
import * as uuid from 'uuid';
|
|
3
|
+
import { ModelValidationError, violation } from '../errors';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Convert array of 16 byte values to UUID string format of the form:
|
|
@@ -51,11 +52,28 @@ class UUID {
|
|
|
51
52
|
return new UUID(UUID.fromString(random));
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Throws ModelValidationError naming `raw_uuid` when the input is neither
|
|
57
|
+
* empty nor exactly 16 bytes (LM-334). Empty is accepted as before; prefer
|
|
58
|
+
* fromUUIDProto, which reads empty as unset.
|
|
59
|
+
*/
|
|
54
60
|
static fromU8Array(uint8Array: Uint8Array): UUID {
|
|
61
|
+
if (uint8Array.length !== 0) checkRawUuidLength(uint8Array);
|
|
55
62
|
const array: number[] = Array.from(uint8Array, byte => byte);
|
|
56
63
|
return new UUID(array);
|
|
57
64
|
}
|
|
58
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Decodes a UUIDProto (LM-334). Unset or empty raw_uuid is undefined. Any
|
|
68
|
+
* other length but 16 throws ModelValidationError naming `raw_uuid`.
|
|
69
|
+
*/
|
|
70
|
+
static fromUUIDProto(proto?: UUIDProto): UUID | undefined {
|
|
71
|
+
const raw = proto?.getRawUuid_asU8();
|
|
72
|
+
if (!raw || raw.length === 0) return undefined;
|
|
73
|
+
checkRawUuidLength(raw);
|
|
74
|
+
return new UUID(Array.from(raw, byte => byte));
|
|
75
|
+
}
|
|
76
|
+
|
|
59
77
|
static fromString(uuidString: string): number[] {
|
|
60
78
|
// Remove hyphens and convert to a continuous hexadecimal string
|
|
61
79
|
const hexString = uuidString.replace(/-/g, '');
|
|
@@ -70,4 +88,12 @@ class UUID {
|
|
|
70
88
|
}
|
|
71
89
|
}
|
|
72
90
|
|
|
91
|
+
function checkRawUuidLength(raw: Uint8Array): void {
|
|
92
|
+
if (raw.length !== 16) {
|
|
93
|
+
throw new ModelValidationError([
|
|
94
|
+
violation('raw_uuid', undefined, `expected 16 bytes but got ${raw.length}`),
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
73
99
|
export { UUID };
|