@xyo-network/boundwitness-builder 2.42.16

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.
@@ -0,0 +1,33 @@
1
+ import { Account } from '@xyo-network/account';
2
+ import { XyoBoundWitness } from '@xyo-network/boundwitness-model';
3
+ import { XyoPayload } from '@xyo-network/payload-model';
4
+ import { Logger } from '@xyo-network/shared';
5
+ export interface BoundWitnessBuilderConfig {
6
+ /** Whether or not the payloads should be included in the metadata sent to and recorded by the ArchivistApi */
7
+ readonly inlinePayloads?: boolean;
8
+ readonly meta?: boolean;
9
+ readonly timestamp?: boolean;
10
+ }
11
+ export declare class BoundWitnessBuilder<TBoundWitness extends XyoBoundWitness<{
12
+ schema: string;
13
+ }> = XyoBoundWitness, TPayload extends XyoPayload = XyoPayload> {
14
+ readonly config: BoundWitnessBuilderConfig;
15
+ protected readonly logger?: Logger | undefined;
16
+ private _accounts;
17
+ private _payloadHashes;
18
+ private _payloadSchemas;
19
+ private _payloads;
20
+ private _timestamp;
21
+ constructor(config?: BoundWitnessBuilderConfig, logger?: Logger | undefined);
22
+ private get _payload_hashes();
23
+ private get _payload_schemas();
24
+ build(): [TBoundWitness, TPayload[]];
25
+ hashableFields(): TBoundWitness;
26
+ hashes(hashes: string[], schema: string[]): this;
27
+ payload(payload?: TPayload): this;
28
+ payloads(payloads?: (TPayload | null)[]): this;
29
+ witness(account: Account): this;
30
+ protected signatures(_hash: string): string[];
31
+ private inlinePayloads;
32
+ }
33
+ //# sourceMappingURL=Builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Builder.d.ts","sourceRoot":"","sources":["../../src/Builder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAyB,MAAM,iCAAiC,CAAA;AAGxF,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAE5C,MAAM,WAAW,yBAAyB;IACxC,8GAA8G;IAC9G,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAA;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED,qBAAa,mBAAmB,CAC9B,aAAa,SAAS,eAAe,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,eAAe,EAC3E,QAAQ,SAAS,UAAU,GAAG,UAAU;aAQZ,MAAM,EAAE,yBAAyB;IAA8B,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;IANrH,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,UAAU,CAAa;gBAEH,MAAM,GAAE,yBAAqD,EAAqB,MAAM,CAAC,oBAAQ;IAE7H,OAAO,KAAK,eAAe,GAO1B;IAED,OAAO,KAAK,gBAAgB,GAO3B;IAEM,KAAK,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,CAAC;IA0BpC,cAAc,IAAI,aAAa;IAuB/B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;IAOzC,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ;IAQ1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE;IASvC,OAAO,CAAC,OAAO,EAAE,OAAO;IAK/B,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM;IAIlC,OAAO,CAAC,cAAc;CAQvB"}
@@ -0,0 +1,107 @@
1
+ import { assertEx } from '@xylabs/assert';
2
+ import { Buffer } from '@xylabs/buffer';
3
+ import { XyoBoundWitnessSchema } from '@xyo-network/boundwitness-model';
4
+ import { BoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper';
5
+ import { Hasher, sortFields } from '@xyo-network/core';
6
+ export class BoundWitnessBuilder {
7
+ config;
8
+ logger;
9
+ _accounts = [];
10
+ _payloadHashes;
11
+ _payloadSchemas;
12
+ _payloads = [];
13
+ _timestamp = Date.now();
14
+ constructor(config = { inlinePayloads: false }, logger) {
15
+ this.config = config;
16
+ this.logger = logger;
17
+ }
18
+ get _payload_hashes() {
19
+ return (this._payloadHashes ??
20
+ this._payloads.map((payload) => {
21
+ return assertEx(new Hasher(payload).hash);
22
+ }));
23
+ }
24
+ get _payload_schemas() {
25
+ return (this._payloadSchemas ??
26
+ this._payloads.map((payload) => {
27
+ return assertEx(payload.schema, 'Missing Schema');
28
+ }));
29
+ }
30
+ build() {
31
+ const hashableFields = this.hashableFields();
32
+ const _hash = BoundWitnessWrapper.hash(hashableFields);
33
+ const ret = {
34
+ ...hashableFields,
35
+ _signatures: this.signatures(_hash),
36
+ };
37
+ if (this.config?.meta ?? true) {
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ const bwWithMeta = ret;
40
+ bwWithMeta._client = 'js';
41
+ bwWithMeta._hash = _hash;
42
+ bwWithMeta._timestamp = this._timestamp;
43
+ }
44
+ if (this.config.inlinePayloads) {
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
+ const anyRet = ret;
47
+ //leaving this in here to prevent breaking code (for now)
48
+ anyRet._payloads = this.inlinePayloads();
49
+ }
50
+ return [ret, this._payloads];
51
+ }
52
+ hashableFields() {
53
+ const addresses = this._accounts.map((account) => account.addressValue.hex);
54
+ const previous_hashes = this._accounts.map((account) => account.previousHash?.hex ?? null);
55
+ const result = {
56
+ addresses: assertEx(addresses, 'Missing addresses'),
57
+ payload_hashes: assertEx(this._payload_hashes, 'Missing payload_hashes'),
58
+ payload_schemas: assertEx(this._payload_schemas, 'Missing payload_schemas'),
59
+ previous_hashes,
60
+ schema: XyoBoundWitnessSchema,
61
+ };
62
+ assertEx(result.payload_hashes?.length === result.payload_schemas?.length, 'Payload hash/schema mismatch');
63
+ assertEx(!result.payload_hashes.reduce((inValid, hash) => inValid || !hash, false), 'nulls found in hashes');
64
+ assertEx(!result.payload_schemas.reduce((inValid, schema) => inValid || !schema, false), 'nulls found in schemas');
65
+ if (this.config.timestamp ?? true) {
66
+ result.timestamp = this._timestamp;
67
+ }
68
+ return result;
69
+ }
70
+ hashes(hashes, schema) {
71
+ assertEx(this.payloads.length === 0, 'Can not set hashes when payloads already set');
72
+ this._payloadHashes = hashes;
73
+ this._payloadSchemas = schema;
74
+ return this;
75
+ }
76
+ payload(payload) {
77
+ assertEx(this._payloadHashes === undefined, 'Can not set payloads when hashes already set');
78
+ if (payload) {
79
+ this._payloads.push(assertEx(sortFields(payload)));
80
+ }
81
+ return this;
82
+ }
83
+ payloads(payloads) {
84
+ payloads?.forEach((payload) => {
85
+ if (payload !== null) {
86
+ this.payload(payload);
87
+ }
88
+ });
89
+ return this;
90
+ }
91
+ witness(account) {
92
+ this._accounts?.push(account);
93
+ return this;
94
+ }
95
+ signatures(_hash) {
96
+ return this._accounts.map((account) => Buffer.from(account.sign(Buffer.from(_hash, 'hex'))).toString('hex'));
97
+ }
98
+ inlinePayloads() {
99
+ return this._payloads.map((payload, index) => {
100
+ return {
101
+ ...payload,
102
+ schema: this._payload_schemas[index],
103
+ };
104
+ });
105
+ }
106
+ }
107
+ //# sourceMappingURL=Builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Builder.js","sourceRoot":"","sources":["../../src/Builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAEvC,OAAO,EAAmB,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACxF,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AACvE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAWtD,MAAM,OAAO,mBAAmB;IAUF;IAAkF;IANtG,SAAS,GAAc,EAAE,CAAA;IACzB,cAAc,CAAsB;IACpC,eAAe,CAAsB;IACrC,SAAS,GAAe,EAAE,CAAA;IAC1B,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAE/B,YAA4B,SAAoC,EAAE,cAAc,EAAE,KAAK,EAAE,EAAqB,MAAe;QAAjG,WAAM,GAAN,MAAM,CAAuD;QAAqB,WAAM,GAAN,MAAM,CAAS;IAAG,CAAC;IAEjI,IAAY,eAAe;QACzB,OAAO,CACL,IAAI,CAAC,cAAc;YACnB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,OAAO,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAA;YAC3C,CAAC,CAAC,CACH,CAAA;IACH,CAAC;IAED,IAAY,gBAAgB;QAC1B,OAAO,CACL,IAAI,CAAC,eAAe;YACpB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC7B,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;YACnD,CAAC,CAAC,CACH,CAAA;IACH,CAAC;IAEM,KAAK;QACV,MAAM,cAAc,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QAC5C,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAEtD,MAAM,GAAG,GAAkB;YACzB,GAAG,cAAc;YACjB,WAAW,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;SACpC,CAAA;QAED,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,IAAI,EAAE;YAC7B,8DAA8D;YAC9D,MAAM,UAAU,GAAG,GAAU,CAAA;YAC7B,UAAU,CAAC,OAAO,GAAG,IAAI,CAAA;YACzB,UAAU,CAAC,KAAK,GAAG,KAAK,CAAA;YACxB,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAA;SACxC;QAED,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;YAC9B,8DAA8D;YAC9D,MAAM,MAAM,GAAG,GAAU,CAAA;YACzB,yDAAyD;YACzD,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;SACzC;QACD,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;IAC9B,CAAC;IAEM,cAAc;QACnB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;QAC3E,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,IAAI,IAAI,CAAC,CAAA;QAC1F,MAAM,MAAM,GAAkB;YAC5B,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;YACnD,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,wBAAwB,CAAC;YACxE,eAAe,EAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,yBAAyB,CAAC;YAC3E,eAAe;YACf,MAAM,EAAE,qBAAqB;SACb,CAAA;QAElB,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,KAAK,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,8BAA8B,CAAC,CAAA;QAE1G,QAAQ,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,uBAAuB,CAAC,CAAA;QAE5G,QAAQ,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,wBAAwB,CAAC,CAAA;QAElH,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,IAAI,EAAE;YACjC,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAA;SACnC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAEM,MAAM,CAAC,MAAgB,EAAE,MAAgB;QAC9C,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,8CAA8C,CAAC,CAAA;QACpF,IAAI,CAAC,cAAc,GAAG,MAAM,CAAA;QAC5B,IAAI,CAAC,eAAe,GAAG,MAAM,CAAA;QAC7B,OAAO,IAAI,CAAA;IACb,CAAC;IAEM,OAAO,CAAC,OAAkB;QAC/B,QAAQ,CAAC,IAAI,CAAC,cAAc,KAAK,SAAS,EAAE,8CAA8C,CAAC,CAAA;QAC3F,IAAI,OAAO,EAAE;YACX,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAW,OAAO,CAAC,CAAC,CAAC,CAAA;SAC7D;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAEM,QAAQ,CAAC,QAA8B;QAC5C,QAAQ,EAAE,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC5B,IAAI,OAAO,KAAK,IAAI,EAAE;gBACpB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;aACtB;QACH,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC;IAEM,OAAO,CAAC,OAAgB;QAC7B,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7B,OAAO,IAAI,CAAA;IACb,CAAC;IAES,UAAU,CAAC,KAAa;QAChC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;IAC9G,CAAC;IAEO,cAAc;QACpB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAW,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;YACrD,OAAO;gBACL,GAAG,OAAO;gBACV,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;aACrC,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export * from './Builder';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA"}
@@ -0,0 +1,2 @@
1
+ export * from './Builder';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@xyo-network/boundwitness-builder",
3
+ "author": {
4
+ "email": "support@xyo.network",
5
+ "name": "XYO Development Team",
6
+ "url": "https://xyo.network"
7
+ },
8
+ "bugs": {
9
+ "email": "support@xyo.network",
10
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/issues"
11
+ },
12
+ "dependencies": {
13
+ "@xylabs/assert": "^2.6.12",
14
+ "@xylabs/buffer": "^2.6.12",
15
+ "@xyo-network/account": "^2.42.16",
16
+ "@xyo-network/boundwitness-model": "^2.42.16",
17
+ "@xyo-network/boundwitness-wrapper": "^2.42.16",
18
+ "@xyo-network/core": "^2.42.16",
19
+ "@xyo-network/payload-model": "^2.42.15",
20
+ "@xyo-network/shared": "^2.42.16"
21
+ },
22
+ "description": "Primary SDK for using XYO Protocol 2.0",
23
+ "devDependencies": {
24
+ "@xylabs/ts-scripts-yarn3": "^2.10.25"
25
+ },
26
+ "peerDependencies": {
27
+ "axios": "^1.2.1"
28
+ },
29
+ "browser": "dist/esm/index.js",
30
+ "docs": "dist/docs.json",
31
+ "exports": {
32
+ ".": {
33
+ "node": {
34
+ "import": "./dist/esm/index.js",
35
+ "require": "./dist/cjs/index.js"
36
+ },
37
+ "browser": {
38
+ "import": "./dist/esm/index.js",
39
+ "require": "./dist/cjs/index.js"
40
+ },
41
+ "default": "./dist/esm/index.js"
42
+ },
43
+ "./dist/docs.json": {
44
+ "default": "./dist/docs.json"
45
+ },
46
+ "./package.json": "./package.json"
47
+ },
48
+ "main": "dist/cjs/index.js",
49
+ "module": "dist/esm/index.js",
50
+ "homepage": "https://xyo.network",
51
+ "license": "LGPL-3.0-only",
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js.git"
58
+ },
59
+ "sideEffects": false,
60
+ "types": "dist/esm/index.d.ts",
61
+ "version": "2.42.16"
62
+ }
@@ -0,0 +1,86 @@
1
+ /* eslint-disable sort-keys-fix/sort-keys-fix */
2
+ /* eslint-disable sort-keys */
3
+
4
+ import { Account, AddressValue } from '@xyo-network/account'
5
+ import { Hasher, StringKeyObject } from '@xyo-network/core'
6
+ import { XyoPayload } from '@xyo-network/payload-model'
7
+
8
+ import { BoundWitnessBuilder } from './Builder'
9
+
10
+ const schema = 'network.xyo.temp'
11
+ const payload1: XyoPayload<StringKeyObject & { schema: string }> = {
12
+ number_field: 1,
13
+ object_field: {
14
+ number_value: 2,
15
+ string_value: 'yo',
16
+ },
17
+ schema,
18
+ string_field: 'there',
19
+ timestamp: 1618603439107,
20
+ }
21
+ const payload2: XyoPayload<StringKeyObject & { schema: string }> = {
22
+ timestamp: 1618603439107,
23
+ string_field: 'there',
24
+ schema,
25
+ object_field: {
26
+ string_value: 'yo',
27
+ number_value: 2,
28
+ },
29
+ number_field: 1,
30
+ }
31
+ const payloads = [payload1, payload2]
32
+ const payloadHash = '3c817871cbf24708703e907dbc344b1b2aefcc3603d14d59c3a35a5c446410d1'
33
+
34
+ describe('BoundWitnessBuilder', () => {
35
+ describe('hash', () => {
36
+ it.each(payloads)('consistently hashes equivalent payload independent of the order of the keys', (payload) => {
37
+ const hash = new Hasher(payload).hash
38
+ expect(hash).toEqual(payloadHash)
39
+ })
40
+ })
41
+ describe('build', () => {
42
+ describe('_hash', () => {
43
+ it.each(payloads)('consistently hashes equivalent payloads independent of the order of the keys', (payload) => {
44
+ const address = Account.fromPhrase('test1')
45
+ let builder = new BoundWitnessBuilder({ timestamp: false })
46
+ expect(builder).toBeDefined()
47
+ builder = builder.witness(address)
48
+ expect(builder).toBeDefined()
49
+ builder = builder.payload(payload)
50
+ expect(builder).toBeDefined()
51
+
52
+ const [actual] = builder.build()
53
+
54
+ expect(actual).toBeDefined()
55
+ expect(Hasher.hash(actual)).toEqual('7f3203f2d191f12c26cd1aec62b718be8848471f82831a8870f82fc669a5f35b')
56
+
57
+ if (actual._signatures) {
58
+ const addr = new AddressValue(actual.addresses[0])
59
+ expect(addr.hex).toBe(actual.addresses[0])
60
+ const verify = new AddressValue(actual.addresses[0]).verify(Hasher.hash(actual), actual._signatures[0])
61
+ expect(verify).toBe(true)
62
+ }
63
+ })
64
+ })
65
+ describe('with inlinePayloads true', () => {
66
+ it('contains the _payloads field', () => {
67
+ const address = Account.fromPhrase('test2')
68
+ const builder = new BoundWitnessBuilder({ inlinePayloads: true }).witness(address).payload(payload1)
69
+
70
+ const [actual] = builder.build()
71
+
72
+ expect(actual).toBeDefined()
73
+ })
74
+ })
75
+ describe('with inlinePayloads false', () => {
76
+ it('omits the _payloads field', () => {
77
+ const address = Account.fromPhrase('test3')
78
+ const builder = new BoundWitnessBuilder({ inlinePayloads: false }).witness(address).payload(payload1)
79
+
80
+ const [actual] = builder.build()
81
+
82
+ expect(actual).toBeDefined()
83
+ })
84
+ })
85
+ })
86
+ })
package/src/Builder.ts ADDED
@@ -0,0 +1,137 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { Buffer } from '@xylabs/buffer'
3
+ import { Account } from '@xyo-network/account'
4
+ import { XyoBoundWitness, XyoBoundWitnessSchema } from '@xyo-network/boundwitness-model'
5
+ import { BoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
6
+ import { Hasher, sortFields } from '@xyo-network/core'
7
+ import { XyoPayload } from '@xyo-network/payload-model'
8
+ import { Logger } from '@xyo-network/shared'
9
+
10
+ export interface BoundWitnessBuilderConfig {
11
+ /** Whether or not the payloads should be included in the metadata sent to and recorded by the ArchivistApi */
12
+ readonly inlinePayloads?: boolean
13
+ readonly meta?: boolean
14
+ readonly timestamp?: boolean
15
+ }
16
+
17
+ export class BoundWitnessBuilder<
18
+ TBoundWitness extends XyoBoundWitness<{ schema: string }> = XyoBoundWitness,
19
+ TPayload extends XyoPayload = XyoPayload,
20
+ > {
21
+ private _accounts: Account[] = []
22
+ private _payloadHashes: string[] | undefined
23
+ private _payloadSchemas: string[] | undefined
24
+ private _payloads: TPayload[] = []
25
+ private _timestamp = Date.now()
26
+
27
+ constructor(public readonly config: BoundWitnessBuilderConfig = { inlinePayloads: false }, protected readonly logger?: Logger) {}
28
+
29
+ private get _payload_hashes(): string[] {
30
+ return (
31
+ this._payloadHashes ??
32
+ this._payloads.map((payload) => {
33
+ return assertEx(new Hasher(payload).hash)
34
+ })
35
+ )
36
+ }
37
+
38
+ private get _payload_schemas(): string[] {
39
+ return (
40
+ this._payloadSchemas ??
41
+ this._payloads.map((payload) => {
42
+ return assertEx(payload.schema, 'Missing Schema')
43
+ })
44
+ )
45
+ }
46
+
47
+ public build(): [TBoundWitness, TPayload[]] {
48
+ const hashableFields = this.hashableFields()
49
+ const _hash = BoundWitnessWrapper.hash(hashableFields)
50
+
51
+ const ret: TBoundWitness = {
52
+ ...hashableFields,
53
+ _signatures: this.signatures(_hash),
54
+ }
55
+
56
+ if (this.config?.meta ?? true) {
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ const bwWithMeta = ret as any
59
+ bwWithMeta._client = 'js'
60
+ bwWithMeta._hash = _hash
61
+ bwWithMeta._timestamp = this._timestamp
62
+ }
63
+
64
+ if (this.config.inlinePayloads) {
65
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
+ const anyRet = ret as any
67
+ //leaving this in here to prevent breaking code (for now)
68
+ anyRet._payloads = this.inlinePayloads()
69
+ }
70
+ return [ret, this._payloads]
71
+ }
72
+
73
+ public hashableFields(): TBoundWitness {
74
+ const addresses = this._accounts.map((account) => account.addressValue.hex)
75
+ const previous_hashes = this._accounts.map((account) => account.previousHash?.hex ?? null)
76
+ const result: TBoundWitness = {
77
+ addresses: assertEx(addresses, 'Missing addresses'),
78
+ payload_hashes: assertEx(this._payload_hashes, 'Missing payload_hashes'),
79
+ payload_schemas: assertEx(this._payload_schemas, 'Missing payload_schemas'),
80
+ previous_hashes,
81
+ schema: XyoBoundWitnessSchema,
82
+ } as TBoundWitness
83
+
84
+ assertEx(result.payload_hashes?.length === result.payload_schemas?.length, 'Payload hash/schema mismatch')
85
+
86
+ assertEx(!result.payload_hashes.reduce((inValid, hash) => inValid || !hash, false), 'nulls found in hashes')
87
+
88
+ assertEx(!result.payload_schemas.reduce((inValid, schema) => inValid || !schema, false), 'nulls found in schemas')
89
+
90
+ if (this.config.timestamp ?? true) {
91
+ result.timestamp = this._timestamp
92
+ }
93
+ return result
94
+ }
95
+
96
+ public hashes(hashes: string[], schema: string[]) {
97
+ assertEx(this.payloads.length === 0, 'Can not set hashes when payloads already set')
98
+ this._payloadHashes = hashes
99
+ this._payloadSchemas = schema
100
+ return this
101
+ }
102
+
103
+ public payload(payload?: TPayload) {
104
+ assertEx(this._payloadHashes === undefined, 'Can not set payloads when hashes already set')
105
+ if (payload) {
106
+ this._payloads.push(assertEx(sortFields<TPayload>(payload)))
107
+ }
108
+ return this
109
+ }
110
+
111
+ public payloads(payloads?: (TPayload | null)[]) {
112
+ payloads?.forEach((payload) => {
113
+ if (payload !== null) {
114
+ this.payload(payload)
115
+ }
116
+ })
117
+ return this
118
+ }
119
+
120
+ public witness(account: Account) {
121
+ this._accounts?.push(account)
122
+ return this
123
+ }
124
+
125
+ protected signatures(_hash: string) {
126
+ return this._accounts.map((account) => Buffer.from(account.sign(Buffer.from(_hash, 'hex'))).toString('hex'))
127
+ }
128
+
129
+ private inlinePayloads() {
130
+ return this._payloads.map<TPayload>((payload, index) => {
131
+ return {
132
+ ...payload,
133
+ schema: this._payload_schemas[index],
134
+ }
135
+ })
136
+ }
137
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './Builder'