@totemsdk/manifest 0.1.0

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 ADDED
@@ -0,0 +1,223 @@
1
+ # @totemsdk/manifest
2
+
3
+ **Canonical signed declarations for every Totem Edge entity.**
4
+
5
+ Defines the schema, deterministic IDs, wire encoding, WOTS signing, and type guards for all manifest types in the Totem ecosystem. Every entity that wants to be discovered, paid, or trusted — an app, an AI agent capability, a smart contract, or a persistent edge service — is represented as a `SignedManifest`.
6
+
7
+ No network. No blockchain. No Hyperswarm. Pure schema + cryptographic binding.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @totemsdk/manifest
13
+ ```
14
+
15
+ ## What's inside
16
+
17
+ | Type | Role |
18
+ |------|------|
19
+ | `AppManifest` | A human-facing Pear app — name, version, permissions, pricing, install topic key |
20
+ | `CapabilityManifest` | An ephemeral AI/agent service — input/output schema, per-call pricing, expiry |
21
+ | `DAppManifest` | A KISSVM smart contract / covenant — contract hash, ABI, audit report |
22
+ | `EdgeServiceManifest` | Any persistent Totem Edge service — sensors, robots, MQTT feeds, Omnia routers, lookup providers, proof indexers, and more |
23
+ | `SignedManifest<T>` | Wraps any manifest with a WOTS signature and signer address |
24
+ | `VerifyResult` | Result of `verifyManifest` — `valid`, optional `reason`, `signerAddress` |
25
+
26
+ ## Usage
27
+
28
+ ### Sign a manifest
29
+
30
+ ```typescript
31
+ import { signManifest } from '@totemsdk/manifest';
32
+ import type { AppManifest } from '@totemsdk/manifest';
33
+
34
+ const app: AppManifest = {
35
+ type: 'app',
36
+ appId: computeManifestId(app), // fill after construction
37
+ name: 'My dApp',
38
+ version: '1.0.0',
39
+ authorAddress: 'MxABC123...',
40
+ pearTopicKey: 'a1b2c3...', // 32-byte hex — Hyperswarm install topic
41
+ price: '0',
42
+ category: ['finance'],
43
+ permissions: ['wallet:read-balance', 'wallet:request-payment'],
44
+ description: 'My first Totem app',
45
+ minTotemVersion: '0.1.0',
46
+ };
47
+
48
+ // seed = your 32-byte WOTS seed; keyIndex = pre-reserved key index
49
+ const signed = await signManifest(app, seed, keyIndex);
50
+ // signed.authorAddress — the Minima address of the signer
51
+ // signed.signature — WOTS signature hex
52
+ ```
53
+
54
+ ### Verify a manifest
55
+
56
+ ```typescript
57
+ import { verifyManifest } from '@totemsdk/manifest';
58
+
59
+ const result = verifyManifest(signed);
60
+ if (!result.valid) {
61
+ console.error('Invalid manifest:', result.reason);
62
+ }
63
+ ```
64
+
65
+ ### Compute a stable manifest ID
66
+
67
+ ```typescript
68
+ import { computeManifestId } from '@totemsdk/manifest';
69
+
70
+ // ID is SHA3-256 over stable key fields — does not change when version changes
71
+ const id = computeManifestId(app);
72
+ ```
73
+
74
+ ### Wire encode / decode
75
+
76
+ ```typescript
77
+ import { encodeManifest, decodeManifest } from '@totemsdk/manifest';
78
+
79
+ // Encode to Uint8Array for DHT / lookup-protocol embedding
80
+ const bytes = encodeManifest(signed);
81
+
82
+ // Decode back from bytes (validates type discriminant and version)
83
+ const decoded = decodeManifest(bytes);
84
+ ```
85
+
86
+ Wire format: `[1 version][1 type][4-byte JSON length][JSON payload][WOTS signature]`
87
+
88
+ ### Type guards
89
+
90
+ ```typescript
91
+ import {
92
+ isAppManifest,
93
+ isCapabilityManifest,
94
+ isDAppManifest,
95
+ isEdgeServiceManifest,
96
+ } from '@totemsdk/manifest';
97
+
98
+ // Accept raw Manifest or SignedManifest<T>
99
+ if (isCapabilityManifest(signed)) {
100
+ console.log(signed.manifest.capabilityName);
101
+ }
102
+ ```
103
+
104
+ ## Manifest types
105
+
106
+ ### `AppManifest`
107
+
108
+ ```typescript
109
+ interface AppManifest {
110
+ type: 'app';
111
+ appId: string; // SHA3-256(authorAddress + pearTopicKey)
112
+ name: string;
113
+ version: string; // semver
114
+ authorAddress: string; // Minima address
115
+ pearTopicKey: string; // 32-byte hex — Hyperswarm install topic
116
+ price: string; // '0' for free; Minima amount for paid
117
+ priceToken?: string;
118
+ subscriptionInterval?: number;
119
+ category: string[];
120
+ permissions: AppPermission[];
121
+ iconCid?: string;
122
+ description: string;
123
+ repoUrl?: string;
124
+ minTotemVersion: string;
125
+ }
126
+ ```
127
+
128
+ ### `CapabilityManifest`
129
+
130
+ ```typescript
131
+ interface CapabilityManifest {
132
+ type: 'capability';
133
+ capabilityId: string; // SHA3-256(agentAddress + capabilityName)
134
+ capabilityName: string;
135
+ agentAddress: string;
136
+ agentIdentityKey: string; // ed25519 pubkey for auth challenge/response
137
+ description: string;
138
+ inputSchema: object; // JSON Schema
139
+ outputSchema: object; // JSON Schema
140
+ pricePerCall: string;
141
+ priceToken?: string;
142
+ paymentChannel?: 'omnia' | 'onchain';
143
+ maxLatencyMs?: number;
144
+ maxCallsPerMinute?: number;
145
+ expiresAt: number; // ms — must be re-announced
146
+ tags: string[];
147
+ }
148
+ ```
149
+
150
+ ### `DAppManifest`
151
+
152
+ ```typescript
153
+ interface DAppManifest {
154
+ type: 'dapp';
155
+ dappId: string; // SHA3-256(authorAddress + contractHash)
156
+ name: string;
157
+ version: string;
158
+ authorAddress: string;
159
+ contractHash: string; // SHA3-256 of the KISSVM script
160
+ contractSource?: string;
161
+ abi: DAppAbiEntry[];
162
+ price: string;
163
+ priceToken?: string;
164
+ category: string[];
165
+ description: string;
166
+ auditReport?: string; // CID of a simulation audit result
167
+ }
168
+ ```
169
+
170
+ ### `EdgeServiceManifest`
171
+
172
+ Covers all persistent Totem Edge services that are not apps, capabilities, or dApps.
173
+
174
+ ```typescript
175
+ type EdgeServiceType =
176
+ | 'sensor'
177
+ | 'robot'
178
+ | 'mqtt-feed'
179
+ | 'proof-index'
180
+ | 'lookup-provider'
181
+ | 'omnia-router'
182
+ | 'calibration-authority'
183
+ | 'verifier'
184
+ | 'machine-service'
185
+ | 'other';
186
+
187
+ interface EdgeServiceManifest {
188
+ type: 'edge-service';
189
+ serviceId: string; // SHA3-256(operatorAddress + serviceType + name)
190
+ name: string;
191
+ version: string;
192
+ operatorAddress: string;
193
+ serviceType: EdgeServiceType;
194
+ description: string;
195
+ endpoints?: Array<{
196
+ type: 'https' | 'mqtt' | 'hyperswarm' | 'websocket' | 'other';
197
+ uri: string;
198
+ }>;
199
+ capabilities: string[];
200
+ price?: string;
201
+ priceToken?: string;
202
+ paymentMethods?: Array<'omnia' | 'onchain' | 'invoice' | 'free'>;
203
+ tags: string[];
204
+ expiresAt?: number;
205
+ minTotemVersion?: string;
206
+ }
207
+ ```
208
+
209
+ ## Wire type discriminants
210
+
211
+ | Type | Byte |
212
+ |------|------|
213
+ | `app` | `0x01` |
214
+ | `capability` | `0x02` |
215
+ | `dapp` | `0x03` |
216
+ | `edge-service` | `0x04` |
217
+
218
+ ## See also
219
+
220
+ - [`@totemsdk/core`](../core) — WOTS signing primitives used internally
221
+ - [`@totemsdk/lookup-protocol`](../lookup-protocol) — embeds `encodeManifest()` output in `APP_ANNOUNCE` / `AGENT_ANNOUNCE` messages
222
+ - [`@totemsdk/wots-lease`](../wots-lease) — manage WOTS key index reservation before calling `signManifest`
223
+ - [`@totemsdk/root-identity`](../root-identity) — optional `rootIdentityProof` field for chain-of-custody linking
@@ -0,0 +1,8 @@
1
+ export declare const MANIFEST_VERSION: 1;
2
+ export declare const MANIFEST_TYPE_BYTE: {
3
+ readonly app: 1;
4
+ readonly capability: 2;
5
+ readonly dapp: 3;
6
+ readonly 'edge-service': 4;
7
+ };
8
+ export declare const MANIFEST_BYTE_TO_TYPE: Record<number, string>;
@@ -0,0 +1,13 @@
1
+ export const MANIFEST_VERSION = 1;
2
+ export const MANIFEST_TYPE_BYTE = {
3
+ app: 0x01,
4
+ capability: 0x02,
5
+ dapp: 0x03,
6
+ 'edge-service': 0x04,
7
+ };
8
+ export const MANIFEST_BYTE_TO_TYPE = {
9
+ 0x01: 'app',
10
+ 0x02: 'capability',
11
+ 0x03: 'dapp',
12
+ 0x04: 'edge-service',
13
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Wire encoding/decoding for SignedManifest.
3
+ *
4
+ * Format:
5
+ * [1 byte MANIFEST_VERSION ]
6
+ * [1 byte type discriminant] 0x01=app 0x02=capability 0x03=dapp 0x04=edge-service
7
+ * [4 bytes big-endian JSON length]
8
+ * [N bytes canonical JSON (UTF-8)]
9
+ * [remaining bytes = WOTS signature]
10
+ *
11
+ * The JSON payload is the full SignedManifest object (manifest + metadata + signature).
12
+ * The trailing WOTS signature bytes are stored separately for easy extraction by
13
+ * the DHT / lookup-protocol layer without needing to parse the JSON.
14
+ */
15
+ import type { SignedManifest } from './types.js';
16
+ export declare function encodeManifest(signed: SignedManifest): Uint8Array;
17
+ export declare function decodeManifest(bytes: Uint8Array): SignedManifest;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Wire encoding/decoding for SignedManifest.
3
+ *
4
+ * Format:
5
+ * [1 byte MANIFEST_VERSION ]
6
+ * [1 byte type discriminant] 0x01=app 0x02=capability 0x03=dapp 0x04=edge-service
7
+ * [4 bytes big-endian JSON length]
8
+ * [N bytes canonical JSON (UTF-8)]
9
+ * [remaining bytes = WOTS signature]
10
+ *
11
+ * The JSON payload is the full SignedManifest object (manifest + metadata + signature).
12
+ * The trailing WOTS signature bytes are stored separately for easy extraction by
13
+ * the DHT / lookup-protocol layer without needing to parse the JSON.
14
+ */
15
+ import { MANIFEST_VERSION, MANIFEST_TYPE_BYTE, MANIFEST_BYTE_TO_TYPE } from './constants.js';
16
+ function manifestTypeByte(type) {
17
+ const byte = MANIFEST_TYPE_BYTE[type];
18
+ if (byte === undefined) {
19
+ throw new Error(`encodeManifest: unknown manifest type: ${type}`);
20
+ }
21
+ return byte;
22
+ }
23
+ export function encodeManifest(signed) {
24
+ const enc = new TextEncoder();
25
+ const json = JSON.stringify(signed);
26
+ const jsonBytes = enc.encode(json);
27
+ const sigBytes = hexToBytes(signed.signature);
28
+ const len = jsonBytes.length;
29
+ const out = new Uint8Array(1 + 1 + 4 + len + sigBytes.length);
30
+ let offset = 0;
31
+ out[offset++] = MANIFEST_VERSION;
32
+ out[offset++] = manifestTypeByte(signed.manifest.type);
33
+ out[offset++] = (len >>> 24) & 0xff;
34
+ out[offset++] = (len >>> 16) & 0xff;
35
+ out[offset++] = (len >>> 8) & 0xff;
36
+ out[offset++] = len & 0xff;
37
+ out.set(jsonBytes, offset);
38
+ offset += len;
39
+ out.set(sigBytes, offset);
40
+ return out;
41
+ }
42
+ export function decodeManifest(bytes) {
43
+ if (bytes.length < 6) {
44
+ throw new Error('decodeManifest: buffer too short (< 6 bytes)');
45
+ }
46
+ const version = bytes[0];
47
+ if (version !== MANIFEST_VERSION) {
48
+ throw new Error(`decodeManifest: unsupported MANIFEST_VERSION ${version}`);
49
+ }
50
+ const typeByte = bytes[1];
51
+ const expectedType = MANIFEST_BYTE_TO_TYPE[typeByte];
52
+ if (!expectedType) {
53
+ throw new Error(`decodeManifest: unknown type discriminant 0x${typeByte.toString(16).padStart(2, '0')}`);
54
+ }
55
+ const jsonLen = (bytes[2] << 24) | (bytes[3] << 16) | (bytes[4] << 8) | bytes[5];
56
+ if (bytes.length < 6 + jsonLen) {
57
+ throw new Error(`decodeManifest: buffer too short for declared JSON length ${jsonLen}`);
58
+ }
59
+ const jsonBytes = bytes.slice(6, 6 + jsonLen);
60
+ const json = new TextDecoder().decode(jsonBytes);
61
+ let signed;
62
+ try {
63
+ signed = JSON.parse(json);
64
+ }
65
+ catch (e) {
66
+ throw new Error(`decodeManifest: invalid JSON payload: ${String(e)}`);
67
+ }
68
+ if (signed.manifest?.type !== expectedType) {
69
+ throw new Error(`decodeManifest: type discriminant mismatch — wire says '${expectedType}' but JSON manifest.type is '${signed.manifest?.type}'`);
70
+ }
71
+ return signed;
72
+ }
73
+ function hexToBytes(hex) {
74
+ if (hex.startsWith('0x'))
75
+ hex = hex.slice(2);
76
+ if (hex.length % 2 !== 0)
77
+ throw new Error('hexToBytes: odd-length hex string');
78
+ const out = new Uint8Array(hex.length / 2);
79
+ for (let i = 0; i < out.length; i++) {
80
+ out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
81
+ }
82
+ return out;
83
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Type guards for manifest kinds.
3
+ * Each guard accepts a raw Manifest or a SignedManifest.
4
+ */
5
+ import type { Manifest, SignedManifest, AppManifest, CapabilityManifest, DAppManifest, EdgeServiceManifest } from './types.js';
6
+ type MaybeSignedOrRaw = Manifest | SignedManifest | null | undefined;
7
+ export declare function isAppManifest(input: MaybeSignedOrRaw): input is AppManifest | SignedManifest<AppManifest>;
8
+ export declare function isCapabilityManifest(input: MaybeSignedOrRaw): input is CapabilityManifest | SignedManifest<CapabilityManifest>;
9
+ export declare function isDAppManifest(input: MaybeSignedOrRaw): input is DAppManifest | SignedManifest<DAppManifest>;
10
+ export declare function isEdgeServiceManifest(input: MaybeSignedOrRaw): input is EdgeServiceManifest | SignedManifest<EdgeServiceManifest>;
11
+ export {};
package/dist/guards.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Type guards for manifest kinds.
3
+ * Each guard accepts a raw Manifest or a SignedManifest.
4
+ */
5
+ function getRawManifest(input) {
6
+ if (!input || typeof input !== 'object')
7
+ return null;
8
+ if ('manifest' in input && input.manifest && typeof input.manifest === 'object') {
9
+ return input.manifest;
10
+ }
11
+ if ('type' in input)
12
+ return input;
13
+ return null;
14
+ }
15
+ export function isAppManifest(input) {
16
+ return getRawManifest(input)?.type === 'app';
17
+ }
18
+ export function isCapabilityManifest(input) {
19
+ return getRawManifest(input)?.type === 'capability';
20
+ }
21
+ export function isDAppManifest(input) {
22
+ return getRawManifest(input)?.type === 'dapp';
23
+ }
24
+ export function isEdgeServiceManifest(input) {
25
+ return getRawManifest(input)?.type === 'edge-service';
26
+ }
package/dist/id.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * computeManifestId — deterministic stable ID for any manifest.
3
+ *
4
+ * The ID is SHA3-256 over a type-specific stable key string.
5
+ * It must be stable across version bumps (version is NOT part of the input).
6
+ *
7
+ * Stable key rules:
8
+ * AppManifest → "app" + authorAddress + pearTopicKey
9
+ * CapabilityManifest → "capability" + agentAddress + capabilityName
10
+ * DAppManifest → "dapp" + authorAddress + contractHash
11
+ * EdgeServiceManifest → "edge-service" + operatorAddress + serviceType + name
12
+ */
13
+ import type { Manifest } from './types.js';
14
+ export declare function computeManifestId(manifest: Manifest): string;
package/dist/id.js ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * computeManifestId — deterministic stable ID for any manifest.
3
+ *
4
+ * The ID is SHA3-256 over a type-specific stable key string.
5
+ * It must be stable across version bumps (version is NOT part of the input).
6
+ *
7
+ * Stable key rules:
8
+ * AppManifest → "app" + authorAddress + pearTopicKey
9
+ * CapabilityManifest → "capability" + agentAddress + capabilityName
10
+ * DAppManifest → "dapp" + authorAddress + contractHash
11
+ * EdgeServiceManifest → "edge-service" + operatorAddress + serviceType + name
12
+ */
13
+ import { sha3_256 } from '@noble/hashes/sha3.js';
14
+ function bytesToHex(b) {
15
+ return Array.from(b)
16
+ .map((x) => x.toString(16).padStart(2, '0'))
17
+ .join('');
18
+ }
19
+ export function computeManifestId(manifest) {
20
+ let stableKey;
21
+ switch (manifest.type) {
22
+ case 'app':
23
+ stableKey = `app\0${manifest.authorAddress}\0${manifest.pearTopicKey}`;
24
+ break;
25
+ case 'capability':
26
+ stableKey = `capability\0${manifest.agentAddress}\0${manifest.capabilityName}`;
27
+ break;
28
+ case 'dapp':
29
+ stableKey = `dapp\0${manifest.authorAddress}\0${manifest.contractHash}`;
30
+ break;
31
+ case 'edge-service':
32
+ stableKey = `edge-service\0${manifest.operatorAddress}\0${manifest.serviceType}\0${manifest.name}`;
33
+ break;
34
+ default: {
35
+ const _exhaustive = manifest;
36
+ throw new Error(`computeManifestId: unknown manifest type: ${JSON.stringify(_exhaustive)}`);
37
+ }
38
+ }
39
+ return bytesToHex(sha3_256(new TextEncoder().encode(stableKey)));
40
+ }
@@ -0,0 +1,7 @@
1
+ export type { AppManifest, CapabilityManifest, DAppManifest, EdgeServiceManifest, EdgeServiceType, Manifest, SignedManifest, AppPermission, DAppAbiEntry, VerifyResult, } from './types.js';
2
+ export { MANIFEST_VERSION } from './constants.js';
3
+ export { computeManifestId } from './id.js';
4
+ export { signManifest } from './sign.js';
5
+ export { verifyManifest } from './verify.js';
6
+ export { encodeManifest, decodeManifest } from './encoding.js';
7
+ export { isAppManifest, isCapabilityManifest, isDAppManifest, isEdgeServiceManifest, } from './guards.js';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { MANIFEST_VERSION } from './constants.js';
2
+ export { computeManifestId } from './id.js';
3
+ export { signManifest } from './sign.js';
4
+ export { verifyManifest } from './verify.js';
5
+ export { encodeManifest, decodeManifest } from './encoding.js';
6
+ export { isAppManifest, isCapabilityManifest, isDAppManifest, isEdgeServiceManifest, } from './guards.js';
package/dist/sign.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * signManifest — signs a manifest with a WOTS key.
3
+ *
4
+ * Steps:
5
+ * 1. Canonicalise the manifest as deterministic JSON (sorted keys).
6
+ * 2. SHA3-256 the UTF-8 bytes → 32-byte digest.
7
+ * 3. Sign with wotsSign(seed, keyIndex, digest).
8
+ * 4. Derive address + PKdigest via wotsKeypairFromSeed + wotsAddressFromKeypair.
9
+ * 5. Return SignedManifest<T>.
10
+ *
11
+ * signerPublicKey in SignedManifest is the 32-byte WOTS PKdigest (hex, 64 chars).
12
+ * This is the exact value expected by verifyManifest (via wotsVerifyDigest).
13
+ *
14
+ * The caller is responsible for reserving the WOTS key index before calling
15
+ * this function. This package does NOT depend on @totemsdk/wots-lease.
16
+ */
17
+ import type { Manifest, SignedManifest } from './types.js';
18
+ export declare function manifestDigest(manifest: Manifest): Uint8Array;
19
+ export declare function signManifest<T extends Manifest>(manifest: T, seed: Uint8Array, keyIndex: number): Promise<SignedManifest<T>>;
package/dist/sign.js ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * signManifest — signs a manifest with a WOTS key.
3
+ *
4
+ * Steps:
5
+ * 1. Canonicalise the manifest as deterministic JSON (sorted keys).
6
+ * 2. SHA3-256 the UTF-8 bytes → 32-byte digest.
7
+ * 3. Sign with wotsSign(seed, keyIndex, digest).
8
+ * 4. Derive address + PKdigest via wotsKeypairFromSeed + wotsAddressFromKeypair.
9
+ * 5. Return SignedManifest<T>.
10
+ *
11
+ * signerPublicKey in SignedManifest is the 32-byte WOTS PKdigest (hex, 64 chars).
12
+ * This is the exact value expected by verifyManifest (via wotsVerifyDigest).
13
+ *
14
+ * The caller is responsible for reserving the WOTS key index before calling
15
+ * this function. This package does NOT depend on @totemsdk/wots-lease.
16
+ */
17
+ import { sha3_256 } from '@noble/hashes/sha3.js';
18
+ import { wotsSign, wotsKeypairFromSeed, wotsAddressFromKeypair, bytesToHex, } from '@totemsdk/core';
19
+ /** Produce a deterministic canonical JSON string with sorted keys (recursive). */
20
+ function canonicalJson(value) {
21
+ if (value === null || typeof value !== 'object') {
22
+ return JSON.stringify(value);
23
+ }
24
+ if (Array.isArray(value)) {
25
+ return '[' + value.map(canonicalJson).join(',') + ']';
26
+ }
27
+ const obj = value;
28
+ const keys = Object.keys(obj).sort();
29
+ const pairs = keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`);
30
+ return '{' + pairs.join(',') + '}';
31
+ }
32
+ export function manifestDigest(manifest) {
33
+ const canonical = canonicalJson(manifest);
34
+ return sha3_256(new TextEncoder().encode(canonical));
35
+ }
36
+ export async function signManifest(manifest, seed, keyIndex) {
37
+ const digest = manifestDigest(manifest);
38
+ const sigBytes = wotsSign(seed, keyIndex, digest);
39
+ const kp = wotsKeypairFromSeed(seed, keyIndex);
40
+ const address = wotsAddressFromKeypair(kp);
41
+ return {
42
+ manifest,
43
+ authorAddress: address,
44
+ signerPublicKey: bytesToHex(kp.pk),
45
+ signedAt: Date.now(),
46
+ signature: bytesToHex(sigBytes),
47
+ };
48
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @totemsdk/manifest — Manifest type definitions
3
+ *
4
+ * Four manifest categories for the MVP:
5
+ * AppManifest — human-facing Pear app
6
+ * CapabilityManifest — ephemeral AI/agent service
7
+ * DAppManifest — KISSVM contract / covenant
8
+ * EdgeServiceManifest — any persistent Totem Edge service
9
+ *
10
+ * No network, no blockchain, no Hyperswarm — pure schema.
11
+ */
12
+ export type AppPermission = 'wallet:read-balance' | 'wallet:request-payment' | 'omnia:open-channel' | 'omnia:update-channel' | 'lookup:watch-address' | 'kissvm:evaluate' | 'qvac:call-agent';
13
+ export interface AppManifest {
14
+ type: 'app';
15
+ appId: string;
16
+ name: string;
17
+ version: string;
18
+ authorAddress: string;
19
+ pearTopicKey: string;
20
+ price: string;
21
+ priceToken?: string;
22
+ subscriptionInterval?: number;
23
+ category: string[];
24
+ permissions: AppPermission[];
25
+ iconCid?: string;
26
+ description: string;
27
+ repoUrl?: string;
28
+ minTotemVersion: string;
29
+ }
30
+ export interface CapabilityManifest {
31
+ type: 'capability';
32
+ capabilityId: string;
33
+ capabilityName: string;
34
+ agentAddress: string;
35
+ agentIdentityKey: string;
36
+ description: string;
37
+ inputSchema: object;
38
+ outputSchema: object;
39
+ pricePerCall: string;
40
+ priceToken?: string;
41
+ paymentChannel?: 'omnia' | 'onchain';
42
+ maxLatencyMs?: number;
43
+ maxCallsPerMinute?: number;
44
+ expiresAt: number;
45
+ tags: string[];
46
+ }
47
+ export interface DAppAbiEntry {
48
+ name: string;
49
+ description: string;
50
+ params: {
51
+ name: string;
52
+ type: string;
53
+ description?: string;
54
+ }[];
55
+ }
56
+ export interface DAppManifest {
57
+ type: 'dapp';
58
+ dappId: string;
59
+ name: string;
60
+ version: string;
61
+ authorAddress: string;
62
+ contractHash: string;
63
+ contractSource?: string;
64
+ abi: DAppAbiEntry[];
65
+ price: string;
66
+ priceToken?: string;
67
+ category: string[];
68
+ description: string;
69
+ auditReport?: string;
70
+ }
71
+ export type EdgeServiceType = 'sensor' | 'robot' | 'mqtt-feed' | 'proof-index' | 'lookup-provider' | 'omnia-router' | 'calibration-authority' | 'verifier' | 'machine-service' | 'other';
72
+ export interface EdgeServiceManifest {
73
+ type: 'edge-service';
74
+ serviceId: string;
75
+ name: string;
76
+ version: string;
77
+ operatorAddress: string;
78
+ serviceType: EdgeServiceType;
79
+ description: string;
80
+ endpoints?: Array<{
81
+ type: 'https' | 'mqtt' | 'hyperswarm' | 'websocket' | 'other';
82
+ uri: string;
83
+ }>;
84
+ capabilities: string[];
85
+ price?: string;
86
+ priceToken?: string;
87
+ paymentMethods?: Array<'omnia' | 'onchain' | 'invoice' | 'free'>;
88
+ tags: string[];
89
+ expiresAt?: number;
90
+ minTotemVersion?: string;
91
+ }
92
+ export type Manifest = AppManifest | CapabilityManifest | DAppManifest | EdgeServiceManifest;
93
+ /**
94
+ * Wraps any manifest with a WOTS signature.
95
+ *
96
+ * `signerPublicKey` — hex of the full WOTS public key (required for
97
+ * self-contained verification via verifyManifest).
98
+ * `authorAddress` — the Minima address of the signer, derived at sign time
99
+ * and stored for quick policy checks without re-deriving from the public key.
100
+ */
101
+ export interface SignedManifest<T extends Manifest = Manifest> {
102
+ manifest: T;
103
+ authorAddress: string;
104
+ signerPublicKey: string;
105
+ signedAt: number;
106
+ signature: string;
107
+ rootIdentityProof?: string;
108
+ }
109
+ export interface VerifyResult {
110
+ valid: boolean;
111
+ reason?: string;
112
+ signerAddress: string;
113
+ }
package/dist/types.js ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @totemsdk/manifest — Manifest type definitions
3
+ *
4
+ * Four manifest categories for the MVP:
5
+ * AppManifest — human-facing Pear app
6
+ * CapabilityManifest — ephemeral AI/agent service
7
+ * DAppManifest — KISSVM contract / covenant
8
+ * EdgeServiceManifest — any persistent Totem Edge service
9
+ *
10
+ * No network, no blockchain, no Hyperswarm — pure schema.
11
+ */
12
+ export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * verifyManifest — verifies a SignedManifest without external state.
3
+ *
4
+ * Steps:
5
+ * 1. Recompute the canonical manifest digest.
6
+ * 2. Verify the WOTS signature against the stored 32-byte PKdigest
7
+ * (signerPublicKey field) using wotsVerifyDigest.
8
+ * 3. Confirm authorAddress matches the manifest's address field.
9
+ *
10
+ * wotsVerifyDigest is used (rather than wotsVerify) because signerPublicKey
11
+ * stores the 32-byte WOTS PKdigest as returned by wotsKeypairFromSeed.kp.pk.
12
+ * The full 1088-byte key is not stored in SignedManifest to keep it compact.
13
+ */
14
+ import type { SignedManifest, VerifyResult } from './types.js';
15
+ export declare function verifyManifest(signed: SignedManifest): VerifyResult;