@totemsdk/manifest 0.1.0 → 0.1.1
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/LICENSE +21 -0
- package/README.md +4 -4
- package/dist/constants.js +6 -3
- package/dist/encoding.js +11 -7
- package/dist/guards.js +10 -4
- package/dist/id.js +6 -3
- package/dist/index.js +19 -6
- package/dist/sign.js +14 -10
- package/dist/types.js +2 -1
- package/dist/verify.js +10 -7
- package/package.json +26 -5
- package/src/__tests__/encoding.test.ts +0 -185
- package/src/__tests__/guards.test.ts +0 -140
- package/src/__tests__/id.test.ts +0 -143
- package/src/__tests__/sign-verify.test.ts +0 -157
- package/src/constants.ts +0 -15
- package/src/encoding.ts +0 -100
- package/src/guards.ts +0 -48
- package/src/id.ts +0 -46
- package/src/index.ts +0 -26
- package/src/sign.ts +0 -63
- package/src/types.ts +0 -140
- package/src/verify.ts +0 -67
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Totem SDK Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -217,7 +217,7 @@ interface EdgeServiceManifest {
|
|
|
217
217
|
|
|
218
218
|
## See also
|
|
219
219
|
|
|
220
|
-
- [`@totemsdk/core`](
|
|
221
|
-
- [`@totemsdk/lookup-protocol`](
|
|
222
|
-
- [`@totemsdk/wots-lease`](
|
|
223
|
-
- [`@totemsdk/root-identity`](
|
|
220
|
+
- [`@totemsdk/core`](https://www.npmjs.com/package/@totemsdk/core) — WOTS signing primitives used internally
|
|
221
|
+
- [`@totemsdk/lookup-protocol`](https://www.npmjs.com/package/@totemsdk/lookup-protocol) — embeds `encodeManifest()` output in `APP_ANNOUNCE` / `AGENT_ANNOUNCE` messages
|
|
222
|
+
- [`@totemsdk/wots-lease`](https://www.npmjs.com/package/@totemsdk/wots-lease) — manage WOTS key index reservation before calling `signManifest`
|
|
223
|
+
- [`@totemsdk/root-identity`](https://www.npmjs.com/package/@totemsdk/root-identity) — optional `rootIdentityProof` field for chain-of-custody linking
|
package/dist/constants.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MANIFEST_BYTE_TO_TYPE = exports.MANIFEST_TYPE_BYTE = exports.MANIFEST_VERSION = void 0;
|
|
4
|
+
exports.MANIFEST_VERSION = 1;
|
|
5
|
+
exports.MANIFEST_TYPE_BYTE = {
|
|
3
6
|
app: 0x01,
|
|
4
7
|
capability: 0x02,
|
|
5
8
|
dapp: 0x03,
|
|
6
9
|
'edge-service': 0x04,
|
|
7
10
|
};
|
|
8
|
-
|
|
11
|
+
exports.MANIFEST_BYTE_TO_TYPE = {
|
|
9
12
|
0x01: 'app',
|
|
10
13
|
0x02: 'capability',
|
|
11
14
|
0x03: 'dapp',
|
package/dist/encoding.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Wire encoding/decoding for SignedManifest.
|
|
3
4
|
*
|
|
@@ -12,15 +13,18 @@
|
|
|
12
13
|
* The trailing WOTS signature bytes are stored separately for easy extraction by
|
|
13
14
|
* the DHT / lookup-protocol layer without needing to parse the JSON.
|
|
14
15
|
*/
|
|
15
|
-
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.encodeManifest = encodeManifest;
|
|
18
|
+
exports.decodeManifest = decodeManifest;
|
|
19
|
+
const constants_js_1 = require("./constants.js");
|
|
16
20
|
function manifestTypeByte(type) {
|
|
17
|
-
const byte = MANIFEST_TYPE_BYTE[type];
|
|
21
|
+
const byte = constants_js_1.MANIFEST_TYPE_BYTE[type];
|
|
18
22
|
if (byte === undefined) {
|
|
19
23
|
throw new Error(`encodeManifest: unknown manifest type: ${type}`);
|
|
20
24
|
}
|
|
21
25
|
return byte;
|
|
22
26
|
}
|
|
23
|
-
|
|
27
|
+
function encodeManifest(signed) {
|
|
24
28
|
const enc = new TextEncoder();
|
|
25
29
|
const json = JSON.stringify(signed);
|
|
26
30
|
const jsonBytes = enc.encode(json);
|
|
@@ -28,7 +32,7 @@ export function encodeManifest(signed) {
|
|
|
28
32
|
const len = jsonBytes.length;
|
|
29
33
|
const out = new Uint8Array(1 + 1 + 4 + len + sigBytes.length);
|
|
30
34
|
let offset = 0;
|
|
31
|
-
out[offset++] = MANIFEST_VERSION;
|
|
35
|
+
out[offset++] = constants_js_1.MANIFEST_VERSION;
|
|
32
36
|
out[offset++] = manifestTypeByte(signed.manifest.type);
|
|
33
37
|
out[offset++] = (len >>> 24) & 0xff;
|
|
34
38
|
out[offset++] = (len >>> 16) & 0xff;
|
|
@@ -39,16 +43,16 @@ export function encodeManifest(signed) {
|
|
|
39
43
|
out.set(sigBytes, offset);
|
|
40
44
|
return out;
|
|
41
45
|
}
|
|
42
|
-
|
|
46
|
+
function decodeManifest(bytes) {
|
|
43
47
|
if (bytes.length < 6) {
|
|
44
48
|
throw new Error('decodeManifest: buffer too short (< 6 bytes)');
|
|
45
49
|
}
|
|
46
50
|
const version = bytes[0];
|
|
47
|
-
if (version !== MANIFEST_VERSION) {
|
|
51
|
+
if (version !== constants_js_1.MANIFEST_VERSION) {
|
|
48
52
|
throw new Error(`decodeManifest: unsupported MANIFEST_VERSION ${version}`);
|
|
49
53
|
}
|
|
50
54
|
const typeByte = bytes[1];
|
|
51
|
-
const expectedType = MANIFEST_BYTE_TO_TYPE[typeByte];
|
|
55
|
+
const expectedType = constants_js_1.MANIFEST_BYTE_TO_TYPE[typeByte];
|
|
52
56
|
if (!expectedType) {
|
|
53
57
|
throw new Error(`decodeManifest: unknown type discriminant 0x${typeByte.toString(16).padStart(2, '0')}`);
|
|
54
58
|
}
|
package/dist/guards.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Type guards for manifest kinds.
|
|
3
4
|
* Each guard accepts a raw Manifest or a SignedManifest.
|
|
4
5
|
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.isAppManifest = isAppManifest;
|
|
8
|
+
exports.isCapabilityManifest = isCapabilityManifest;
|
|
9
|
+
exports.isDAppManifest = isDAppManifest;
|
|
10
|
+
exports.isEdgeServiceManifest = isEdgeServiceManifest;
|
|
5
11
|
function getRawManifest(input) {
|
|
6
12
|
if (!input || typeof input !== 'object')
|
|
7
13
|
return null;
|
|
@@ -12,15 +18,15 @@ function getRawManifest(input) {
|
|
|
12
18
|
return input;
|
|
13
19
|
return null;
|
|
14
20
|
}
|
|
15
|
-
|
|
21
|
+
function isAppManifest(input) {
|
|
16
22
|
return getRawManifest(input)?.type === 'app';
|
|
17
23
|
}
|
|
18
|
-
|
|
24
|
+
function isCapabilityManifest(input) {
|
|
19
25
|
return getRawManifest(input)?.type === 'capability';
|
|
20
26
|
}
|
|
21
|
-
|
|
27
|
+
function isDAppManifest(input) {
|
|
22
28
|
return getRawManifest(input)?.type === 'dapp';
|
|
23
29
|
}
|
|
24
|
-
|
|
30
|
+
function isEdgeServiceManifest(input) {
|
|
25
31
|
return getRawManifest(input)?.type === 'edge-service';
|
|
26
32
|
}
|
package/dist/id.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* computeManifestId — deterministic stable ID for any manifest.
|
|
3
4
|
*
|
|
@@ -10,13 +11,15 @@
|
|
|
10
11
|
* DAppManifest → "dapp" + authorAddress + contractHash
|
|
11
12
|
* EdgeServiceManifest → "edge-service" + operatorAddress + serviceType + name
|
|
12
13
|
*/
|
|
13
|
-
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.computeManifestId = computeManifestId;
|
|
16
|
+
const sha3_js_1 = require("@noble/hashes/sha3.js");
|
|
14
17
|
function bytesToHex(b) {
|
|
15
18
|
return Array.from(b)
|
|
16
19
|
.map((x) => x.toString(16).padStart(2, '0'))
|
|
17
20
|
.join('');
|
|
18
21
|
}
|
|
19
|
-
|
|
22
|
+
function computeManifestId(manifest) {
|
|
20
23
|
let stableKey;
|
|
21
24
|
switch (manifest.type) {
|
|
22
25
|
case 'app':
|
|
@@ -36,5 +39,5 @@ export function computeManifestId(manifest) {
|
|
|
36
39
|
throw new Error(`computeManifestId: unknown manifest type: ${JSON.stringify(_exhaustive)}`);
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
|
-
return bytesToHex(sha3_256(new TextEncoder().encode(stableKey)));
|
|
42
|
+
return bytesToHex((0, sha3_js_1.sha3_256)(new TextEncoder().encode(stableKey)));
|
|
40
43
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isEdgeServiceManifest = exports.isDAppManifest = exports.isCapabilityManifest = exports.isAppManifest = exports.decodeManifest = exports.encodeManifest = exports.verifyManifest = exports.signManifest = exports.computeManifestId = exports.MANIFEST_VERSION = void 0;
|
|
4
|
+
var constants_js_1 = require("./constants.js");
|
|
5
|
+
Object.defineProperty(exports, "MANIFEST_VERSION", { enumerable: true, get: function () { return constants_js_1.MANIFEST_VERSION; } });
|
|
6
|
+
var id_js_1 = require("./id.js");
|
|
7
|
+
Object.defineProperty(exports, "computeManifestId", { enumerable: true, get: function () { return id_js_1.computeManifestId; } });
|
|
8
|
+
var sign_js_1 = require("./sign.js");
|
|
9
|
+
Object.defineProperty(exports, "signManifest", { enumerable: true, get: function () { return sign_js_1.signManifest; } });
|
|
10
|
+
var verify_js_1 = require("./verify.js");
|
|
11
|
+
Object.defineProperty(exports, "verifyManifest", { enumerable: true, get: function () { return verify_js_1.verifyManifest; } });
|
|
12
|
+
var encoding_js_1 = require("./encoding.js");
|
|
13
|
+
Object.defineProperty(exports, "encodeManifest", { enumerable: true, get: function () { return encoding_js_1.encodeManifest; } });
|
|
14
|
+
Object.defineProperty(exports, "decodeManifest", { enumerable: true, get: function () { return encoding_js_1.decodeManifest; } });
|
|
15
|
+
var guards_js_1 = require("./guards.js");
|
|
16
|
+
Object.defineProperty(exports, "isAppManifest", { enumerable: true, get: function () { return guards_js_1.isAppManifest; } });
|
|
17
|
+
Object.defineProperty(exports, "isCapabilityManifest", { enumerable: true, get: function () { return guards_js_1.isCapabilityManifest; } });
|
|
18
|
+
Object.defineProperty(exports, "isDAppManifest", { enumerable: true, get: function () { return guards_js_1.isDAppManifest; } });
|
|
19
|
+
Object.defineProperty(exports, "isEdgeServiceManifest", { enumerable: true, get: function () { return guards_js_1.isEdgeServiceManifest; } });
|
package/dist/sign.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* signManifest — signs a manifest with a WOTS key.
|
|
3
4
|
*
|
|
@@ -14,8 +15,11 @@
|
|
|
14
15
|
* The caller is responsible for reserving the WOTS key index before calling
|
|
15
16
|
* this function. This package does NOT depend on @totemsdk/wots-lease.
|
|
16
17
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.manifestDigest = manifestDigest;
|
|
20
|
+
exports.signManifest = signManifest;
|
|
21
|
+
const sha3_js_1 = require("@noble/hashes/sha3.js");
|
|
22
|
+
const core_1 = require("@totemsdk/core");
|
|
19
23
|
/** Produce a deterministic canonical JSON string with sorted keys (recursive). */
|
|
20
24
|
function canonicalJson(value) {
|
|
21
25
|
if (value === null || typeof value !== 'object') {
|
|
@@ -29,20 +33,20 @@ function canonicalJson(value) {
|
|
|
29
33
|
const pairs = keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`);
|
|
30
34
|
return '{' + pairs.join(',') + '}';
|
|
31
35
|
}
|
|
32
|
-
|
|
36
|
+
function manifestDigest(manifest) {
|
|
33
37
|
const canonical = canonicalJson(manifest);
|
|
34
|
-
return sha3_256(new TextEncoder().encode(canonical));
|
|
38
|
+
return (0, sha3_js_1.sha3_256)(new TextEncoder().encode(canonical));
|
|
35
39
|
}
|
|
36
|
-
|
|
40
|
+
async function signManifest(manifest, seed, keyIndex) {
|
|
37
41
|
const digest = manifestDigest(manifest);
|
|
38
|
-
const sigBytes = wotsSign(seed, keyIndex, digest);
|
|
39
|
-
const kp = wotsKeypairFromSeed(seed, keyIndex);
|
|
40
|
-
const address = wotsAddressFromKeypair(kp);
|
|
42
|
+
const sigBytes = (0, core_1.wotsSign)(seed, keyIndex, digest);
|
|
43
|
+
const kp = (0, core_1.wotsKeypairFromSeed)(seed, keyIndex);
|
|
44
|
+
const address = (0, core_1.wotsAddressFromKeypair)(kp);
|
|
41
45
|
return {
|
|
42
46
|
manifest,
|
|
43
47
|
authorAddress: address,
|
|
44
|
-
signerPublicKey: bytesToHex(kp.pk),
|
|
48
|
+
signerPublicKey: (0, core_1.bytesToHex)(kp.pk),
|
|
45
49
|
signedAt: Date.now(),
|
|
46
|
-
signature: bytesToHex(sigBytes),
|
|
50
|
+
signature: (0, core_1.bytesToHex)(sigBytes),
|
|
47
51
|
};
|
|
48
52
|
}
|
package/dist/types.js
CHANGED
package/dist/verify.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* verifyManifest — verifies a SignedManifest without external state.
|
|
3
4
|
*
|
|
@@ -11,8 +12,10 @@
|
|
|
11
12
|
* stores the 32-byte WOTS PKdigest as returned by wotsKeypairFromSeed.kp.pk.
|
|
12
13
|
* The full 1088-byte key is not stored in SignedManifest to keep it compact.
|
|
13
14
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.verifyManifest = verifyManifest;
|
|
17
|
+
const core_1 = require("@totemsdk/core");
|
|
18
|
+
const sign_js_1 = require("./sign.js");
|
|
16
19
|
function manifestAddressField(manifest) {
|
|
17
20
|
switch (manifest.type) {
|
|
18
21
|
case 'app': return manifest.authorAddress;
|
|
@@ -25,21 +28,21 @@ function manifestAddressField(manifest) {
|
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
|
-
|
|
31
|
+
function verifyManifest(signed) {
|
|
29
32
|
const { manifest, signature, signerPublicKey, authorAddress } = signed;
|
|
30
33
|
let sigBytes;
|
|
31
34
|
let pkDigest;
|
|
32
35
|
try {
|
|
33
|
-
sigBytes = hexToBytes(signature);
|
|
34
|
-
pkDigest = hexToBytes(signerPublicKey);
|
|
36
|
+
sigBytes = (0, core_1.hexToBytes)(signature);
|
|
37
|
+
pkDigest = (0, core_1.hexToBytes)(signerPublicKey);
|
|
35
38
|
}
|
|
36
39
|
catch (e) {
|
|
37
40
|
return { valid: false, reason: `hex decode failed: ${String(e)}`, signerAddress: authorAddress };
|
|
38
41
|
}
|
|
39
|
-
const digest = manifestDigest(manifest);
|
|
42
|
+
const digest = (0, sign_js_1.manifestDigest)(manifest);
|
|
40
43
|
let sigValid;
|
|
41
44
|
try {
|
|
42
|
-
sigValid = wotsVerifyDigest(sigBytes, digest, pkDigest);
|
|
45
|
+
sigValid = (0, core_1.wotsVerifyDigest)(sigBytes, digest, pkDigest);
|
|
43
46
|
}
|
|
44
47
|
catch (e) {
|
|
45
48
|
return { valid: false, reason: `WOTS verify threw: ${String(e)}`, signerAddress: authorAddress };
|
package/package.json
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@totemsdk/manifest",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Canonical signed declaration format for Totem Edge entities — apps, agent capabilities, dApps, and edge services",
|
|
5
|
-
"type": "module",
|
|
6
5
|
"main": "dist/index.js",
|
|
7
6
|
"types": "dist/index.d.ts",
|
|
8
7
|
"exports": {
|
|
9
8
|
".": {
|
|
10
9
|
"types": "./dist/index.d.ts",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"files": [
|
|
15
15
|
"dist",
|
|
16
|
-
"
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
17
18
|
],
|
|
18
19
|
"dependencies": {
|
|
19
20
|
"@totemsdk/core": "1.0.9"
|
|
20
21
|
},
|
|
21
22
|
"peerDependencies": {
|
|
22
|
-
"@noble/hashes": ">=1.3.0
|
|
23
|
+
"@noble/hashes": ">=1.3.0"
|
|
23
24
|
},
|
|
24
25
|
"peerDependenciesMeta": {
|
|
25
26
|
"@noble/hashes": {
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
}
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"@noble/hashes": "^
|
|
31
|
+
"@noble/hashes": "^2.2.0",
|
|
31
32
|
"@types/jest": "^29.0.0",
|
|
32
33
|
"@types/node": "^20.0.0",
|
|
33
34
|
"jest": "^29.0.0",
|
|
@@ -41,6 +42,26 @@
|
|
|
41
42
|
"access": "public"
|
|
42
43
|
},
|
|
43
44
|
"license": "MIT",
|
|
45
|
+
"author": "Totem SDK",
|
|
46
|
+
"homepage": "https://totemsdk.com",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/MrGheek/axia-totem/issues"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/MrGheek/axia-totem.git",
|
|
53
|
+
"directory": "packages/totem-sdk/packages/manifest"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"totem",
|
|
57
|
+
"totemsdk",
|
|
58
|
+
"minima",
|
|
59
|
+
"blockchain",
|
|
60
|
+
"quantum-resistant",
|
|
61
|
+
"wots",
|
|
62
|
+
"kissvm",
|
|
63
|
+
"utxo"
|
|
64
|
+
],
|
|
44
65
|
"scripts": {
|
|
45
66
|
"build": "tsc",
|
|
46
67
|
"clean": "rm -rf dist",
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* encoding.test.ts
|
|
3
|
-
* encode → decode round-trips for all four manifest types.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { signManifest } from '../sign.js';
|
|
7
|
-
import { encodeManifest, decodeManifest } from '../encoding.js';
|
|
8
|
-
import { MANIFEST_VERSION, MANIFEST_TYPE_BYTE } from '../constants.js';
|
|
9
|
-
import type {
|
|
10
|
-
AppManifest,
|
|
11
|
-
CapabilityManifest,
|
|
12
|
-
DAppManifest,
|
|
13
|
-
EdgeServiceManifest,
|
|
14
|
-
} from '../types.js';
|
|
15
|
-
|
|
16
|
-
jest.setTimeout(60_000);
|
|
17
|
-
|
|
18
|
-
const TEST_SEED = new Uint8Array(32).fill(0x11);
|
|
19
|
-
const KEY_INDEX = 0;
|
|
20
|
-
|
|
21
|
-
let resolvedAddress: string;
|
|
22
|
-
|
|
23
|
-
beforeAll(async () => {
|
|
24
|
-
const tmp = await signManifest(
|
|
25
|
-
{
|
|
26
|
-
type: 'app',
|
|
27
|
-
appId: '',
|
|
28
|
-
name: 'init',
|
|
29
|
-
version: '1.0.0',
|
|
30
|
-
authorAddress: 'MxINIT',
|
|
31
|
-
pearTopicKey: 'a'.repeat(64),
|
|
32
|
-
price: '0',
|
|
33
|
-
category: [],
|
|
34
|
-
permissions: [],
|
|
35
|
-
description: '',
|
|
36
|
-
minTotemVersion: '0.1.0',
|
|
37
|
-
} satisfies AppManifest,
|
|
38
|
-
TEST_SEED,
|
|
39
|
-
KEY_INDEX,
|
|
40
|
-
);
|
|
41
|
-
resolvedAddress = tmp.authorAddress;
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('encodeManifest / decodeManifest', () => {
|
|
45
|
-
it('round-trips AppManifest and preserves manifest type', async () => {
|
|
46
|
-
const manifest: AppManifest = {
|
|
47
|
-
type: 'app',
|
|
48
|
-
appId: 'abc123',
|
|
49
|
-
name: 'My App',
|
|
50
|
-
version: '1.0.0',
|
|
51
|
-
authorAddress: resolvedAddress,
|
|
52
|
-
pearTopicKey: 'f'.repeat(64),
|
|
53
|
-
price: '0',
|
|
54
|
-
category: ['finance'],
|
|
55
|
-
permissions: ['wallet:read-balance'],
|
|
56
|
-
description: 'Test',
|
|
57
|
-
minTotemVersion: '0.1.0',
|
|
58
|
-
};
|
|
59
|
-
const signed = await signManifest(manifest, TEST_SEED, KEY_INDEX);
|
|
60
|
-
const encoded = encodeManifest(signed);
|
|
61
|
-
const decoded = decodeManifest(encoded);
|
|
62
|
-
|
|
63
|
-
expect(decoded.manifest.type).toBe('app');
|
|
64
|
-
expect(decoded.manifest.type).toBe(signed.manifest.type);
|
|
65
|
-
expect((decoded.manifest as AppManifest).name).toBe('My App');
|
|
66
|
-
expect(decoded.signature).toBe(signed.signature);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('round-trips CapabilityManifest', async () => {
|
|
70
|
-
const manifest: CapabilityManifest = {
|
|
71
|
-
type: 'capability',
|
|
72
|
-
capabilityId: 'cap1',
|
|
73
|
-
capabilityName: 'price-oracle',
|
|
74
|
-
agentAddress: resolvedAddress,
|
|
75
|
-
agentIdentityKey: 'e'.repeat(64),
|
|
76
|
-
description: 'Price oracle',
|
|
77
|
-
inputSchema: { type: 'object' },
|
|
78
|
-
outputSchema: { type: 'object' },
|
|
79
|
-
pricePerCall: '2',
|
|
80
|
-
expiresAt: Date.now() + 3600_000,
|
|
81
|
-
tags: ['oracle'],
|
|
82
|
-
};
|
|
83
|
-
const signed = await signManifest(manifest, TEST_SEED, KEY_INDEX);
|
|
84
|
-
const encoded = encodeManifest(signed);
|
|
85
|
-
const decoded = decodeManifest(encoded);
|
|
86
|
-
|
|
87
|
-
expect(decoded.manifest.type).toBe('capability');
|
|
88
|
-
expect((decoded.manifest as CapabilityManifest).capabilityName).toBe('price-oracle');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('round-trips DAppManifest', async () => {
|
|
92
|
-
const manifest: DAppManifest = {
|
|
93
|
-
type: 'dapp',
|
|
94
|
-
dappId: 'dapp1',
|
|
95
|
-
name: 'Swap dApp',
|
|
96
|
-
version: '2.0.0',
|
|
97
|
-
authorAddress: resolvedAddress,
|
|
98
|
-
contractHash: 'd'.repeat(64),
|
|
99
|
-
abi: [],
|
|
100
|
-
price: '5',
|
|
101
|
-
category: ['defi'],
|
|
102
|
-
description: 'A swap contract',
|
|
103
|
-
};
|
|
104
|
-
const signed = await signManifest(manifest, TEST_SEED, KEY_INDEX);
|
|
105
|
-
const encoded = encodeManifest(signed);
|
|
106
|
-
const decoded = decodeManifest(encoded);
|
|
107
|
-
|
|
108
|
-
expect(decoded.manifest.type).toBe('dapp');
|
|
109
|
-
expect((decoded.manifest as DAppManifest).name).toBe('Swap dApp');
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('round-trips EdgeServiceManifest', async () => {
|
|
113
|
-
const manifest: EdgeServiceManifest = {
|
|
114
|
-
type: 'edge-service',
|
|
115
|
-
serviceId: 'edge1',
|
|
116
|
-
name: 'DHT Relay',
|
|
117
|
-
version: '1.0.0',
|
|
118
|
-
operatorAddress: resolvedAddress,
|
|
119
|
-
serviceType: 'omnia-router',
|
|
120
|
-
description: 'Omnia routing node',
|
|
121
|
-
capabilities: ['relay'],
|
|
122
|
-
tags: ['infrastructure'],
|
|
123
|
-
};
|
|
124
|
-
const signed = await signManifest(manifest, TEST_SEED, KEY_INDEX);
|
|
125
|
-
const encoded = encodeManifest(signed);
|
|
126
|
-
const decoded = decodeManifest(encoded);
|
|
127
|
-
|
|
128
|
-
expect(decoded.manifest.type).toBe('edge-service');
|
|
129
|
-
expect((decoded.manifest as EdgeServiceManifest).serviceType).toBe('omnia-router');
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('first byte is MANIFEST_VERSION', async () => {
|
|
133
|
-
const manifest: AppManifest = {
|
|
134
|
-
type: 'app',
|
|
135
|
-
appId: '',
|
|
136
|
-
name: 'v-test',
|
|
137
|
-
version: '1.0.0',
|
|
138
|
-
authorAddress: resolvedAddress,
|
|
139
|
-
pearTopicKey: 'a'.repeat(64),
|
|
140
|
-
price: '0',
|
|
141
|
-
category: [],
|
|
142
|
-
permissions: [],
|
|
143
|
-
description: '',
|
|
144
|
-
minTotemVersion: '0.1.0',
|
|
145
|
-
};
|
|
146
|
-
const signed = await signManifest(manifest, TEST_SEED, KEY_INDEX);
|
|
147
|
-
const encoded = encodeManifest(signed);
|
|
148
|
-
expect(encoded[0]).toBe(MANIFEST_VERSION);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('second byte is correct type discriminant', async () => {
|
|
152
|
-
const appSigned = await signManifest(
|
|
153
|
-
{ type: 'app', appId: '', name: 'x', version: '1.0.0', authorAddress: resolvedAddress, pearTopicKey: 'a'.repeat(64), price: '0', category: [], permissions: [], description: '', minTotemVersion: '0.1.0' } satisfies AppManifest,
|
|
154
|
-
TEST_SEED, KEY_INDEX,
|
|
155
|
-
);
|
|
156
|
-
expect(encodeManifest(appSigned)[1]).toBe(MANIFEST_TYPE_BYTE.app);
|
|
157
|
-
|
|
158
|
-
const capSigned = await signManifest(
|
|
159
|
-
{ type: 'capability', capabilityId: '', capabilityName: 'x', agentAddress: resolvedAddress, agentIdentityKey: 'e'.repeat(64), description: '', inputSchema: {}, outputSchema: {}, pricePerCall: '1', expiresAt: 0, tags: [] } satisfies CapabilityManifest,
|
|
160
|
-
TEST_SEED, KEY_INDEX,
|
|
161
|
-
);
|
|
162
|
-
expect(encodeManifest(capSigned)[1]).toBe(MANIFEST_TYPE_BYTE.capability);
|
|
163
|
-
|
|
164
|
-
const edgeSigned = await signManifest(
|
|
165
|
-
{ type: 'edge-service', serviceId: '', name: 'x', version: '1.0.0', operatorAddress: resolvedAddress, serviceType: 'sensor', description: '', capabilities: [], tags: [] } satisfies EdgeServiceManifest,
|
|
166
|
-
TEST_SEED, KEY_INDEX,
|
|
167
|
-
);
|
|
168
|
-
expect(encodeManifest(edgeSigned)[1]).toBe(MANIFEST_TYPE_BYTE['edge-service']);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('throws on unknown type discriminant byte', () => {
|
|
172
|
-
const bad = new Uint8Array([1, 0xff, 0, 0, 0, 5, 104, 101, 108, 108, 111]);
|
|
173
|
-
expect(() => decodeManifest(bad)).toThrow(/unknown type discriminant/);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('throws on buffer too short', () => {
|
|
177
|
-
expect(() => decodeManifest(new Uint8Array([1, 1, 0, 0]))).toThrow(/too short/);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('throws on MANIFEST_VERSION mismatch', () => {
|
|
181
|
-
const bad = new Uint8Array(10).fill(0);
|
|
182
|
-
bad[0] = 255;
|
|
183
|
-
expect(() => decodeManifest(bad)).toThrow(/unsupported MANIFEST_VERSION/);
|
|
184
|
-
});
|
|
185
|
-
});
|