@ar.io/sdk 3.4.1 → 3.5.0-alpha.2
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/README.md +11 -6
- package/bundles/web.bundle.min.js +3 -3
- package/lib/cjs/types/ant.js +1 -0
- package/lib/cjs/types/ant.test.js +125 -0
- package/lib/cjs/types/token.test.js +83 -0
- package/lib/cjs/utils/ant.js +42 -0
- package/lib/cjs/utils/ant.test.js +69 -0
- package/lib/cjs/utils/b64.test.js +72 -0
- package/lib/cjs/utils/index.js +1 -0
- package/lib/cjs/utils/utils.test.js +106 -0
- package/lib/cjs/version.js +1 -1
- package/lib/esm/types/ant.js +1 -0
- package/lib/esm/types/ant.test.js +123 -0
- package/lib/esm/types/token.test.js +81 -0
- package/lib/esm/utils/ant.js +38 -0
- package/lib/esm/utils/ant.test.js +67 -0
- package/lib/esm/utils/b64.test.js +70 -0
- package/lib/esm/utils/index.js +1 -0
- package/lib/esm/utils/utils.test.js +104 -0
- package/lib/esm/version.js +1 -1
- package/lib/types/types/ant.d.ts +19 -1
- package/lib/types/types/ant.test.d.ts +1 -0
- package/lib/types/types/io.d.ts +6 -0
- package/lib/types/types/token.test.d.ts +1 -0
- package/lib/types/utils/ant.d.ts +26 -0
- package/lib/types/utils/ant.test.d.ts +1 -0
- package/lib/types/utils/b64.test.d.ts +1 -0
- package/lib/types/utils/index.d.ts +1 -0
- package/lib/types/utils/utils.test.d.ts +1 -0
- package/lib/types/version.d.ts +1 -1
- package/package.json +2 -2
package/lib/cjs/types/ant.js
CHANGED
|
@@ -50,6 +50,7 @@ exports.AntKeywordsSchema = zod_1.z.array(zod_1.z.string()); // TODO: add specif
|
|
|
50
50
|
exports.AntRecordSchema = zod_1.z.object({
|
|
51
51
|
transactionId: exports.ArweaveTxIdSchema.describe('The Target ID of the undername'),
|
|
52
52
|
ttlSeconds: zod_1.z.number(),
|
|
53
|
+
priority: zod_1.z.number().optional(),
|
|
53
54
|
});
|
|
54
55
|
exports.AntRecordsSchema = zod_1.z.record(zod_1.z.string(), exports.AntRecordSchema);
|
|
55
56
|
exports.AntControllersSchema = zod_1.z.array(exports.ArweaveTxIdSchema.describe('Controller address'));
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_assert_1 = require("node:assert");
|
|
4
|
+
const node_test_1 = require("node:test");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const ant_js_1 = require("./ant.js");
|
|
7
|
+
const stub_address = 'valid-address'.padEnd(43, '1');
|
|
8
|
+
(0, node_test_1.describe)('ANT Schemas', () => {
|
|
9
|
+
(0, node_test_1.it)('should validate AntStateSchema', () => {
|
|
10
|
+
const validState = {
|
|
11
|
+
Name: 'TestToken',
|
|
12
|
+
Ticker: 'TST',
|
|
13
|
+
Description: 'Test description',
|
|
14
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
15
|
+
Denomination: 0,
|
|
16
|
+
Owner: stub_address,
|
|
17
|
+
Controllers: [stub_address],
|
|
18
|
+
Records: {
|
|
19
|
+
record1: {
|
|
20
|
+
transactionId: stub_address,
|
|
21
|
+
ttlSeconds: 3600,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
Balances: {
|
|
25
|
+
[stub_address]: 1,
|
|
26
|
+
},
|
|
27
|
+
Logo: stub_address,
|
|
28
|
+
TotalSupply: 1,
|
|
29
|
+
Initialized: true,
|
|
30
|
+
};
|
|
31
|
+
const invalidState = {
|
|
32
|
+
Name: 'TestToken',
|
|
33
|
+
Ticker: 'TST',
|
|
34
|
+
Description: 'Test description',
|
|
35
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
36
|
+
Denomination: 0,
|
|
37
|
+
Owner: stub_address,
|
|
38
|
+
Controllers: [stub_address],
|
|
39
|
+
Records: {
|
|
40
|
+
record1: {
|
|
41
|
+
transactionId: 'invalid-id',
|
|
42
|
+
ttlSeconds: '3600',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
Balances: {
|
|
46
|
+
[stub_address]: 1,
|
|
47
|
+
},
|
|
48
|
+
Logo: stub_address,
|
|
49
|
+
TotalSupply: -1,
|
|
50
|
+
Initialized: true,
|
|
51
|
+
};
|
|
52
|
+
node_assert_1.strict.doesNotThrow(() => ant_js_1.AntStateSchema.parse(validState));
|
|
53
|
+
node_assert_1.strict.throws(() => ant_js_1.AntStateSchema.parse(invalidState), zod_1.z.ZodError);
|
|
54
|
+
});
|
|
55
|
+
(0, node_test_1.it)('should validate AntInfoSchema', () => {
|
|
56
|
+
const validInfo = {
|
|
57
|
+
Name: 'TestToken',
|
|
58
|
+
Owner: stub_address,
|
|
59
|
+
Ticker: 'TST',
|
|
60
|
+
Description: 'Test description',
|
|
61
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
62
|
+
['Total-Supply']: '1',
|
|
63
|
+
Logo: stub_address,
|
|
64
|
+
Denomination: '0',
|
|
65
|
+
Handlers: ant_js_1.AntHandlerNames,
|
|
66
|
+
};
|
|
67
|
+
const invalidInfo = {
|
|
68
|
+
Name: 'TestToken',
|
|
69
|
+
Owner: stub_address,
|
|
70
|
+
Ticker: 'TST',
|
|
71
|
+
['Total-Supply']: 1000,
|
|
72
|
+
Logo: stub_address,
|
|
73
|
+
Denomination: '1',
|
|
74
|
+
Handlers: ant_js_1.AntHandlerNames,
|
|
75
|
+
};
|
|
76
|
+
node_assert_1.strict.doesNotThrow(() => ant_js_1.AntInfoSchema.parse(validInfo));
|
|
77
|
+
node_assert_1.strict.throws(() => ant_js_1.AntInfoSchema.parse(invalidInfo), zod_1.z.ZodError);
|
|
78
|
+
});
|
|
79
|
+
(0, node_test_1.it)('should validate isAoANTState', () => {
|
|
80
|
+
const validState = {
|
|
81
|
+
Name: 'TestToken',
|
|
82
|
+
Ticker: 'TST',
|
|
83
|
+
Description: 'Test description',
|
|
84
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
85
|
+
Denomination: 0,
|
|
86
|
+
Owner: stub_address,
|
|
87
|
+
Controllers: [stub_address],
|
|
88
|
+
Records: {
|
|
89
|
+
record1: {
|
|
90
|
+
transactionId: stub_address,
|
|
91
|
+
ttlSeconds: 3600,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
Balances: {
|
|
95
|
+
[stub_address]: 1,
|
|
96
|
+
},
|
|
97
|
+
Logo: stub_address,
|
|
98
|
+
TotalSupply: 0,
|
|
99
|
+
Initialized: true,
|
|
100
|
+
};
|
|
101
|
+
const invalidState = {
|
|
102
|
+
Name: 'TestToken',
|
|
103
|
+
Ticker: 'TST',
|
|
104
|
+
Description: 'Test description',
|
|
105
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
106
|
+
Denomination: 0,
|
|
107
|
+
Owner: stub_address,
|
|
108
|
+
Controllers: [stub_address],
|
|
109
|
+
Records: {
|
|
110
|
+
record1: {
|
|
111
|
+
transactionId: 'invalid-id',
|
|
112
|
+
ttlSeconds: '3600',
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
Balances: {
|
|
116
|
+
[stub_address]: 1,
|
|
117
|
+
},
|
|
118
|
+
Logo: stub_address,
|
|
119
|
+
TotalSupply: -1,
|
|
120
|
+
Initialized: true,
|
|
121
|
+
};
|
|
122
|
+
node_assert_1.strict.strictEqual((0, ant_js_1.isAoANTState)(validState), true);
|
|
123
|
+
node_assert_1.strict.strictEqual((0, ant_js_1.isAoANTState)(invalidState), false);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_assert_1 = require("node:assert");
|
|
4
|
+
const node_test_1 = require("node:test");
|
|
5
|
+
const token_js_1 = require("./token.js");
|
|
6
|
+
(0, node_test_1.describe)('ARIOToken', () => {
|
|
7
|
+
(0, node_test_1.it)('should throw an error on invalid input', () => {
|
|
8
|
+
node_assert_1.strict.throws(() => new token_js_1.ARIOToken(-1));
|
|
9
|
+
});
|
|
10
|
+
(0, node_test_1.it)('should round at 6 decimal places', () => {
|
|
11
|
+
const token = new token_js_1.ARIOToken(1.123456789);
|
|
12
|
+
node_assert_1.strict.strictEqual(token.valueOf(), 1.123457);
|
|
13
|
+
});
|
|
14
|
+
(0, node_test_1.it)('should convert to mARIOToken', () => {
|
|
15
|
+
const token = new token_js_1.ARIOToken(1);
|
|
16
|
+
const mToken = token.toMARIO();
|
|
17
|
+
node_assert_1.strict.strictEqual(mToken.valueOf(), 1000000);
|
|
18
|
+
});
|
|
19
|
+
(0, node_test_1.it)('should print as a string', () => {
|
|
20
|
+
const token = new token_js_1.ARIOToken(1);
|
|
21
|
+
node_assert_1.strict.strictEqual(`${token}`, '1');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
(0, node_test_1.describe)('mARIOToken', () => {
|
|
25
|
+
(0, node_test_1.it)('should multiply by a number', () => {
|
|
26
|
+
const token = new token_js_1.mARIOToken(1);
|
|
27
|
+
const result = token.multiply(2);
|
|
28
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 2);
|
|
29
|
+
});
|
|
30
|
+
(0, node_test_1.it)('should multiply by another mARIOToken', () => {
|
|
31
|
+
const token = new token_js_1.mARIOToken(1);
|
|
32
|
+
const result = token.multiply(new token_js_1.mARIOToken(2));
|
|
33
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 2);
|
|
34
|
+
});
|
|
35
|
+
(0, node_test_1.it)('should divide by a number', () => {
|
|
36
|
+
const token = new token_js_1.mARIOToken(2);
|
|
37
|
+
const result = token.divide(2);
|
|
38
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 1);
|
|
39
|
+
});
|
|
40
|
+
(0, node_test_1.it)('should divide by another mARIOToken', () => {
|
|
41
|
+
const token = new token_js_1.mARIOToken(2);
|
|
42
|
+
const result = token.divide(new token_js_1.mARIOToken(2));
|
|
43
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 1);
|
|
44
|
+
});
|
|
45
|
+
(0, node_test_1.it)('should throw an error on division by zero', () => {
|
|
46
|
+
const token = new token_js_1.mARIOToken(2);
|
|
47
|
+
node_assert_1.strict.throws(() => token.divide(0));
|
|
48
|
+
});
|
|
49
|
+
(0, node_test_1.it)('should round down on multiplication of a number', () => {
|
|
50
|
+
const token = new token_js_1.mARIOToken(1);
|
|
51
|
+
const result = token.multiply(1.5);
|
|
52
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 1);
|
|
53
|
+
});
|
|
54
|
+
(0, node_test_1.it)('should round down on division with a number', () => {
|
|
55
|
+
const token = new token_js_1.mARIOToken(2);
|
|
56
|
+
const result = token.divide(3);
|
|
57
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 0);
|
|
58
|
+
});
|
|
59
|
+
(0, node_test_1.it)('should round down on division with another mARIOToken', () => {
|
|
60
|
+
const token = new token_js_1.mARIOToken(2);
|
|
61
|
+
const result = token.divide(new token_js_1.mARIOToken(3));
|
|
62
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 0);
|
|
63
|
+
});
|
|
64
|
+
(0, node_test_1.it)('should add', () => {
|
|
65
|
+
const token = new token_js_1.mARIOToken(1);
|
|
66
|
+
const result = token.plus(new token_js_1.mARIOToken(1));
|
|
67
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 2);
|
|
68
|
+
});
|
|
69
|
+
(0, node_test_1.it)('should subtract', () => {
|
|
70
|
+
const token = new token_js_1.mARIOToken(2);
|
|
71
|
+
const result = token.minus(new token_js_1.mARIOToken(1));
|
|
72
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 1);
|
|
73
|
+
});
|
|
74
|
+
(0, node_test_1.it)('should convert to ARIO', () => {
|
|
75
|
+
const token = new token_js_1.mARIOToken(1000000);
|
|
76
|
+
const result = token.toARIO();
|
|
77
|
+
node_assert_1.strict.strictEqual(result.valueOf(), 1);
|
|
78
|
+
});
|
|
79
|
+
(0, node_test_1.it)('should print as a string', () => {
|
|
80
|
+
const token = new token_js_1.mARIOToken(1);
|
|
81
|
+
node_assert_1.strict.strictEqual(`${token}`, '1');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sortANTRecords = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Sorts ANT records by priority and then lexicographically.
|
|
6
|
+
*
|
|
7
|
+
* Note: javascript guarantees that the order of objects in an object is persistent. Still, adding index to each record is useful for enforcing against undername limits.
|
|
8
|
+
*
|
|
9
|
+
* Reference: https://github.com/ar-io/ar-io-node/blob/e0a9ec56559cad1b3e35d668563871afb8649913/docs/madr/003-arns-undername-limits.md
|
|
10
|
+
*
|
|
11
|
+
* @param antRecords - The ANT records to sort.
|
|
12
|
+
*/
|
|
13
|
+
const sortANTRecords = (antRecords) => {
|
|
14
|
+
const sortedEntries = Object.entries(antRecords).sort(([a, aRecord], [b, bRecord]) => {
|
|
15
|
+
// '@' is the root name and should be resolved first
|
|
16
|
+
if (a === '@') {
|
|
17
|
+
return -1;
|
|
18
|
+
}
|
|
19
|
+
if (b === '@') {
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
// if a record has a priority, it should be resolved before any other record without a priority
|
|
23
|
+
if ('priority' in aRecord && !('priority' in bRecord)) {
|
|
24
|
+
return -1;
|
|
25
|
+
}
|
|
26
|
+
if (!('priority' in aRecord) && 'priority' in bRecord) {
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
// if both records have a priority, sort by priority and fallback to lexicographic sorting
|
|
30
|
+
if (aRecord.priority !== undefined && bRecord.priority !== undefined) {
|
|
31
|
+
if (aRecord.priority === bRecord.priority) {
|
|
32
|
+
return a.localeCompare(b);
|
|
33
|
+
}
|
|
34
|
+
return aRecord.priority - bRecord.priority;
|
|
35
|
+
}
|
|
36
|
+
// all other records are sorted lexicographically
|
|
37
|
+
return a.localeCompare(b);
|
|
38
|
+
});
|
|
39
|
+
// now that they are sorted, add the index to each record - this is their position in the sorted list and is used to enforce undername limits
|
|
40
|
+
return Object.fromEntries(sortedEntries.map(([a, aRecord], index) => [a, { ...aRecord, index }]));
|
|
41
|
+
};
|
|
42
|
+
exports.sortANTRecords = sortANTRecords;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_assert_1 = require("node:assert");
|
|
4
|
+
const node_test_1 = require("node:test");
|
|
5
|
+
const ant_js_1 = require("./ant.js");
|
|
6
|
+
(0, node_test_1.describe)('sortANTRecordsByPriority', () => {
|
|
7
|
+
(0, node_test_1.it)('should sort records by priority and then lexicographically', () => {
|
|
8
|
+
const records = {
|
|
9
|
+
undername1: { priority: 1, transactionId: 'test', ttlSeconds: 1 },
|
|
10
|
+
undername2: { priority: 2, transactionId: 'test', ttlSeconds: 1 },
|
|
11
|
+
undername3: { priority: 3, transactionId: 'test', ttlSeconds: 1 }, // colliding priorities default to lexicographic sorting
|
|
12
|
+
undername4: { priority: 3, transactionId: 'test', ttlSeconds: 1 },
|
|
13
|
+
undername5: { priority: 100, transactionId: 'test', ttlSeconds: 1 }, // priority does not represent the index or position of the record, just the order of resolution relative to other records
|
|
14
|
+
noPriority: { transactionId: 'test', ttlSeconds: 1 },
|
|
15
|
+
'@': { transactionId: 'test', ttlSeconds: 1 }, // always first, even if no priority
|
|
16
|
+
};
|
|
17
|
+
const sorted = (0, ant_js_1.sortANTRecords)(records);
|
|
18
|
+
node_assert_1.strict.deepStrictEqual(sorted, {
|
|
19
|
+
'@': { transactionId: 'test', ttlSeconds: 1, index: 0 }, // always first, even if no priority
|
|
20
|
+
undername1: {
|
|
21
|
+
priority: 1,
|
|
22
|
+
transactionId: 'test',
|
|
23
|
+
ttlSeconds: 1,
|
|
24
|
+
index: 1,
|
|
25
|
+
},
|
|
26
|
+
undername2: {
|
|
27
|
+
priority: 2,
|
|
28
|
+
transactionId: 'test',
|
|
29
|
+
ttlSeconds: 1,
|
|
30
|
+
index: 2,
|
|
31
|
+
},
|
|
32
|
+
undername3: {
|
|
33
|
+
priority: 3,
|
|
34
|
+
transactionId: 'test',
|
|
35
|
+
ttlSeconds: 1,
|
|
36
|
+
index: 3,
|
|
37
|
+
},
|
|
38
|
+
undername4: {
|
|
39
|
+
priority: 3,
|
|
40
|
+
transactionId: 'test',
|
|
41
|
+
ttlSeconds: 1,
|
|
42
|
+
index: 4,
|
|
43
|
+
},
|
|
44
|
+
undername5: {
|
|
45
|
+
priority: 100,
|
|
46
|
+
transactionId: 'test',
|
|
47
|
+
ttlSeconds: 1,
|
|
48
|
+
index: 5,
|
|
49
|
+
},
|
|
50
|
+
noPriority: { transactionId: 'test', ttlSeconds: 1, index: 6 },
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
(0, node_test_1.it)('should always return @ as the first record, regardless of priority', () => {
|
|
54
|
+
const records = {
|
|
55
|
+
'@': { priority: 5, transactionId: 'test', ttlSeconds: 1 }, // priorities set on '@' are ignored, they are always first
|
|
56
|
+
undername1: { priority: 2, transactionId: 'test', ttlSeconds: 1 },
|
|
57
|
+
};
|
|
58
|
+
const sorted = (0, ant_js_1.sortANTRecords)(records);
|
|
59
|
+
node_assert_1.strict.deepStrictEqual(sorted, {
|
|
60
|
+
'@': { priority: 5, transactionId: 'test', ttlSeconds: 1, index: 0 },
|
|
61
|
+
undername1: {
|
|
62
|
+
priority: 2,
|
|
63
|
+
transactionId: 'test',
|
|
64
|
+
ttlSeconds: 1,
|
|
65
|
+
index: 1,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_assert_1 = require("node:assert");
|
|
4
|
+
const node_test_1 = require("node:test");
|
|
5
|
+
const base64_js_1 = require("./base64.js");
|
|
6
|
+
(0, node_test_1.describe)('b64utils', () => {
|
|
7
|
+
(0, node_test_1.it)('should convert various strings to base64url and back', () => {
|
|
8
|
+
const testStrings = [
|
|
9
|
+
'Hello, World!',
|
|
10
|
+
'Test123!@#',
|
|
11
|
+
'Base64URLEncoding',
|
|
12
|
+
'Special_Chars+/',
|
|
13
|
+
'',
|
|
14
|
+
'A',
|
|
15
|
+
'1234567890',
|
|
16
|
+
];
|
|
17
|
+
for (const str of testStrings) {
|
|
18
|
+
const encoded = (0, base64_js_1.toB64Url)(Buffer.from(str));
|
|
19
|
+
const decoded = (0, base64_js_1.fromB64Url)(encoded);
|
|
20
|
+
node_assert_1.strict.deepStrictEqual(decoded, Buffer.from(str), `Failed for string: ${str}`);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
(0, node_test_1.it)('should convert various buffers to base64url and back', () => {
|
|
24
|
+
const testBuffers = [
|
|
25
|
+
Buffer.from('Hello, World!'),
|
|
26
|
+
Buffer.from([0, 1, 2, 3, 4, 5]),
|
|
27
|
+
Buffer.from('Test123!@#'),
|
|
28
|
+
Buffer.from('Base64URLEncoding'),
|
|
29
|
+
Buffer.from('Special_Chars+/'),
|
|
30
|
+
Buffer.alloc(0),
|
|
31
|
+
Buffer.from('A'),
|
|
32
|
+
Buffer.from('1234567890'),
|
|
33
|
+
];
|
|
34
|
+
for (const buf of testBuffers) {
|
|
35
|
+
const encoded = (0, base64_js_1.toB64Url)(buf);
|
|
36
|
+
const decoded = (0, base64_js_1.fromB64Url)(encoded);
|
|
37
|
+
node_assert_1.strict.deepStrictEqual(decoded, buf, `Failed for buffer: ${buf.toString()}`);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
(0, node_test_1.it)('should handle edge cases for base64url conversion', () => {
|
|
41
|
+
const edgeCases = [
|
|
42
|
+
'',
|
|
43
|
+
'A',
|
|
44
|
+
'AA',
|
|
45
|
+
'AAA',
|
|
46
|
+
'====',
|
|
47
|
+
'===',
|
|
48
|
+
'==',
|
|
49
|
+
'=',
|
|
50
|
+
'A===',
|
|
51
|
+
'AA==',
|
|
52
|
+
'AAA=',
|
|
53
|
+
];
|
|
54
|
+
for (const testCase of edgeCases) {
|
|
55
|
+
const encoded = (0, base64_js_1.toB64Url)(Buffer.from(testCase));
|
|
56
|
+
const decoded = Buffer.from((0, base64_js_1.fromB64Url)(encoded)).toString();
|
|
57
|
+
node_assert_1.strict.strictEqual(decoded, testCase, `Failed for edge case: ${testCase}`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
(0, node_test_1.it)('should generate random text', () => {
|
|
61
|
+
const randomText = (0, base64_js_1.getRandomText)();
|
|
62
|
+
const randomText2 = (0, base64_js_1.getRandomText)();
|
|
63
|
+
node_assert_1.strict.strictEqual(randomText.length, 32);
|
|
64
|
+
node_assert_1.strict.strictEqual(randomText2.length, 32);
|
|
65
|
+
node_assert_1.strict.notStrictEqual(randomText, randomText2);
|
|
66
|
+
const smallRandomText = (0, base64_js_1.getRandomText)(16);
|
|
67
|
+
const smallRandomText2 = (0, base64_js_1.getRandomText)(16);
|
|
68
|
+
node_assert_1.strict.strictEqual(smallRandomText.length, 16);
|
|
69
|
+
node_assert_1.strict.strictEqual(smallRandomText2.length, 16);
|
|
70
|
+
node_assert_1.strict.notStrictEqual(smallRandomText, smallRandomText2);
|
|
71
|
+
});
|
|
72
|
+
});
|
package/lib/cjs/utils/index.js
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_assert_1 = require("node:assert");
|
|
4
|
+
const node_test_1 = require("node:test");
|
|
5
|
+
const arweave_js_1 = require("./arweave.js");
|
|
6
|
+
const index_js_1 = require("./index.js");
|
|
7
|
+
(0, node_test_1.describe)('pruneTags', () => {
|
|
8
|
+
(0, node_test_1.it)('should remove tags with undefined values', () => {
|
|
9
|
+
const tags = [
|
|
10
|
+
{ name: 'Tag1', value: 'value1' },
|
|
11
|
+
{ name: 'Tag2', value: undefined },
|
|
12
|
+
{ name: 'Tag3', value: 'value3' },
|
|
13
|
+
{ name: 'Tag4', value: undefined },
|
|
14
|
+
];
|
|
15
|
+
const prunedTags = (0, arweave_js_1.pruneTags)(tags);
|
|
16
|
+
node_assert_1.strict.deepEqual(prunedTags, [
|
|
17
|
+
{ name: 'Tag1', value: 'value1' },
|
|
18
|
+
{ name: 'Tag3', value: 'value3' },
|
|
19
|
+
]);
|
|
20
|
+
});
|
|
21
|
+
(0, node_test_1.it)('should return empty array when all tags have undefined values', () => {
|
|
22
|
+
const tags = [
|
|
23
|
+
{ name: 'Tag1', value: undefined },
|
|
24
|
+
{ name: 'Tag2', value: undefined },
|
|
25
|
+
];
|
|
26
|
+
const prunedTags = (0, arweave_js_1.pruneTags)(tags);
|
|
27
|
+
node_assert_1.strict.deepEqual(prunedTags, []);
|
|
28
|
+
});
|
|
29
|
+
(0, node_test_1.it)('should return same array when no tags have undefined values', () => {
|
|
30
|
+
const tags = [
|
|
31
|
+
{ name: 'Tag1', value: 'value1' },
|
|
32
|
+
{ name: 'Tag2', value: 'value2' },
|
|
33
|
+
];
|
|
34
|
+
const prunedTags = (0, arweave_js_1.pruneTags)(tags);
|
|
35
|
+
node_assert_1.strict.deepEqual(prunedTags, tags);
|
|
36
|
+
});
|
|
37
|
+
(0, node_test_1.it)('should return empty array with no tags', () => {
|
|
38
|
+
const tags = [];
|
|
39
|
+
const prunedTags = (0, arweave_js_1.pruneTags)(tags);
|
|
40
|
+
node_assert_1.strict.deepEqual(prunedTags, []);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
(0, node_test_1.describe)('errorMessageFromOutput', () => {
|
|
44
|
+
(0, node_test_1.it)('should return error message from Error field', () => {
|
|
45
|
+
const output = {
|
|
46
|
+
Error: 'Error message',
|
|
47
|
+
};
|
|
48
|
+
const errorMessage = (0, index_js_1.errorMessageFromOutput)(output);
|
|
49
|
+
node_assert_1.strict.equal(errorMessage, 'Error message');
|
|
50
|
+
});
|
|
51
|
+
(0, node_test_1.it)('should return error message from Error tag', () => {
|
|
52
|
+
const output = {
|
|
53
|
+
Messages: [
|
|
54
|
+
{
|
|
55
|
+
Tags: [{ name: 'Error', value: 'Error message' }],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
const errorMessage = (0, index_js_1.errorMessageFromOutput)(output);
|
|
60
|
+
node_assert_1.strict.equal(errorMessage, 'Error message');
|
|
61
|
+
});
|
|
62
|
+
(0, node_test_1.it)('should return error message from Error tag if Error field is undefined', () => {
|
|
63
|
+
const output = {
|
|
64
|
+
Messages: [
|
|
65
|
+
{
|
|
66
|
+
Tags: [{ name: 'Error', value: 'Error message' }],
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
const errorMessage = (0, index_js_1.errorMessageFromOutput)(output);
|
|
71
|
+
node_assert_1.strict.equal(errorMessage, 'Error message');
|
|
72
|
+
});
|
|
73
|
+
(0, node_test_1.it)('should return undefined if no error message is present', () => {
|
|
74
|
+
const output = {
|
|
75
|
+
Messages: [
|
|
76
|
+
{
|
|
77
|
+
Tags: [{ name: 'Tag1', value: 'value1' }],
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
const errorMessage = (0, index_js_1.errorMessageFromOutput)(output);
|
|
82
|
+
node_assert_1.strict.equal(errorMessage, undefined);
|
|
83
|
+
});
|
|
84
|
+
(0, node_test_1.it)('should return error message with line number', () => {
|
|
85
|
+
const output = {
|
|
86
|
+
Error: '[string "aos"]:123: Error message',
|
|
87
|
+
};
|
|
88
|
+
const errorMessage = (0, index_js_1.errorMessageFromOutput)(output);
|
|
89
|
+
node_assert_1.strict.equal(errorMessage, 'Error message (line 123)');
|
|
90
|
+
});
|
|
91
|
+
(0, node_test_1.it)('should return error message with line number and remove unicode', () => {
|
|
92
|
+
const output = {
|
|
93
|
+
Error: '[string "aos"]:123: Error message\u001b[0m',
|
|
94
|
+
};
|
|
95
|
+
const errorMessage = (0, index_js_1.errorMessageFromOutput)(output);
|
|
96
|
+
node_assert_1.strict.equal(errorMessage, 'Error message (line 123)');
|
|
97
|
+
});
|
|
98
|
+
const knownErrorMessages = '\u001b[31mError\u001b[90m handling message with Action = Register\u001b[0m\n\u001b[32m[string ".handlers"]:723: [string "aos"]:128: Already registered\u001b[0m\n\n\u001b[90mstack traceback:\n\t[string ".process"]:871: in function \'.process.handle\'\u001b[0m\n\n\u001b[31merror:\n\u001b[0m[string ".handlers"]:723: [string "aos"]:128: Already registered';
|
|
99
|
+
(0, node_test_1.it)('should display a clean error for a known error message', () => {
|
|
100
|
+
const output = {
|
|
101
|
+
Error: knownErrorMessages,
|
|
102
|
+
};
|
|
103
|
+
const errorMessage = (0, index_js_1.errorMessageFromOutput)(output);
|
|
104
|
+
node_assert_1.strict.equal(errorMessage, 'Already registered (line 128)');
|
|
105
|
+
});
|
|
106
|
+
});
|
package/lib/cjs/version.js
CHANGED
package/lib/esm/types/ant.js
CHANGED
|
@@ -47,6 +47,7 @@ export const AntKeywordsSchema = z.array(z.string()); // TODO: add specific limi
|
|
|
47
47
|
export const AntRecordSchema = z.object({
|
|
48
48
|
transactionId: ArweaveTxIdSchema.describe('The Target ID of the undername'),
|
|
49
49
|
ttlSeconds: z.number(),
|
|
50
|
+
priority: z.number().optional(),
|
|
50
51
|
});
|
|
51
52
|
export const AntRecordsSchema = z.record(z.string(), AntRecordSchema);
|
|
52
53
|
export const AntControllersSchema = z.array(ArweaveTxIdSchema.describe('Controller address'));
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { strict as assert } from 'node:assert';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { AntHandlerNames, AntInfoSchema, AntStateSchema, isAoANTState, } from './ant.js';
|
|
5
|
+
const stub_address = 'valid-address'.padEnd(43, '1');
|
|
6
|
+
describe('ANT Schemas', () => {
|
|
7
|
+
it('should validate AntStateSchema', () => {
|
|
8
|
+
const validState = {
|
|
9
|
+
Name: 'TestToken',
|
|
10
|
+
Ticker: 'TST',
|
|
11
|
+
Description: 'Test description',
|
|
12
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
13
|
+
Denomination: 0,
|
|
14
|
+
Owner: stub_address,
|
|
15
|
+
Controllers: [stub_address],
|
|
16
|
+
Records: {
|
|
17
|
+
record1: {
|
|
18
|
+
transactionId: stub_address,
|
|
19
|
+
ttlSeconds: 3600,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
Balances: {
|
|
23
|
+
[stub_address]: 1,
|
|
24
|
+
},
|
|
25
|
+
Logo: stub_address,
|
|
26
|
+
TotalSupply: 1,
|
|
27
|
+
Initialized: true,
|
|
28
|
+
};
|
|
29
|
+
const invalidState = {
|
|
30
|
+
Name: 'TestToken',
|
|
31
|
+
Ticker: 'TST',
|
|
32
|
+
Description: 'Test description',
|
|
33
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
34
|
+
Denomination: 0,
|
|
35
|
+
Owner: stub_address,
|
|
36
|
+
Controllers: [stub_address],
|
|
37
|
+
Records: {
|
|
38
|
+
record1: {
|
|
39
|
+
transactionId: 'invalid-id',
|
|
40
|
+
ttlSeconds: '3600',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
Balances: {
|
|
44
|
+
[stub_address]: 1,
|
|
45
|
+
},
|
|
46
|
+
Logo: stub_address,
|
|
47
|
+
TotalSupply: -1,
|
|
48
|
+
Initialized: true,
|
|
49
|
+
};
|
|
50
|
+
assert.doesNotThrow(() => AntStateSchema.parse(validState));
|
|
51
|
+
assert.throws(() => AntStateSchema.parse(invalidState), z.ZodError);
|
|
52
|
+
});
|
|
53
|
+
it('should validate AntInfoSchema', () => {
|
|
54
|
+
const validInfo = {
|
|
55
|
+
Name: 'TestToken',
|
|
56
|
+
Owner: stub_address,
|
|
57
|
+
Ticker: 'TST',
|
|
58
|
+
Description: 'Test description',
|
|
59
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
60
|
+
['Total-Supply']: '1',
|
|
61
|
+
Logo: stub_address,
|
|
62
|
+
Denomination: '0',
|
|
63
|
+
Handlers: AntHandlerNames,
|
|
64
|
+
};
|
|
65
|
+
const invalidInfo = {
|
|
66
|
+
Name: 'TestToken',
|
|
67
|
+
Owner: stub_address,
|
|
68
|
+
Ticker: 'TST',
|
|
69
|
+
['Total-Supply']: 1000,
|
|
70
|
+
Logo: stub_address,
|
|
71
|
+
Denomination: '1',
|
|
72
|
+
Handlers: AntHandlerNames,
|
|
73
|
+
};
|
|
74
|
+
assert.doesNotThrow(() => AntInfoSchema.parse(validInfo));
|
|
75
|
+
assert.throws(() => AntInfoSchema.parse(invalidInfo), z.ZodError);
|
|
76
|
+
});
|
|
77
|
+
it('should validate isAoANTState', () => {
|
|
78
|
+
const validState = {
|
|
79
|
+
Name: 'TestToken',
|
|
80
|
+
Ticker: 'TST',
|
|
81
|
+
Description: 'Test description',
|
|
82
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
83
|
+
Denomination: 0,
|
|
84
|
+
Owner: stub_address,
|
|
85
|
+
Controllers: [stub_address],
|
|
86
|
+
Records: {
|
|
87
|
+
record1: {
|
|
88
|
+
transactionId: stub_address,
|
|
89
|
+
ttlSeconds: 3600,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
Balances: {
|
|
93
|
+
[stub_address]: 1,
|
|
94
|
+
},
|
|
95
|
+
Logo: stub_address,
|
|
96
|
+
TotalSupply: 0,
|
|
97
|
+
Initialized: true,
|
|
98
|
+
};
|
|
99
|
+
const invalidState = {
|
|
100
|
+
Name: 'TestToken',
|
|
101
|
+
Ticker: 'TST',
|
|
102
|
+
Description: 'Test description',
|
|
103
|
+
Keywords: ['keyword1', 'keyword2', 'keyword3'],
|
|
104
|
+
Denomination: 0,
|
|
105
|
+
Owner: stub_address,
|
|
106
|
+
Controllers: [stub_address],
|
|
107
|
+
Records: {
|
|
108
|
+
record1: {
|
|
109
|
+
transactionId: 'invalid-id',
|
|
110
|
+
ttlSeconds: '3600',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
Balances: {
|
|
114
|
+
[stub_address]: 1,
|
|
115
|
+
},
|
|
116
|
+
Logo: stub_address,
|
|
117
|
+
TotalSupply: -1,
|
|
118
|
+
Initialized: true,
|
|
119
|
+
};
|
|
120
|
+
assert.strictEqual(isAoANTState(validState), true);
|
|
121
|
+
assert.strictEqual(isAoANTState(invalidState), false);
|
|
122
|
+
});
|
|
123
|
+
});
|