yakmesh 2.8.2 → 3.0.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/CHANGELOG.md +637 -0
- package/CONTRIBUTING.md +42 -0
- package/Caddyfile +77 -0
- package/README.md +119 -29
- package/adapters/adapter-mlv-bible/README.md +124 -0
- package/adapters/adapter-mlv-bible/index.js +400 -0
- package/adapters/chat-mod-adapter.js +532 -0
- package/adapters/content-adapter.js +273 -0
- package/content/api.js +50 -41
- package/content/index.js +2 -2
- package/content/store.js +355 -173
- package/dashboard/index.html +19 -3
- package/database/replication.js +117 -37
- package/docs/CRYPTO-AGILITY.md +204 -0
- package/docs/MTLS-RESEARCH.md +367 -0
- package/docs/NAMCHE-SPEC.md +681 -0
- package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
- package/docs/PRECISION-DISCLOSURE.md +96 -0
- package/docs/README.md +76 -0
- package/docs/ROADMAP-2.4.0.md +447 -0
- package/docs/ROADMAP-2.5.0.md +244 -0
- package/docs/SECURITY-AUDIT-REPORT.md +306 -0
- package/docs/SST-INTEGRATION.md +712 -0
- package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
- package/docs/TERNARY-AUDIT-REPORT.md +247 -0
- package/docs/TME-FAQ.md +221 -0
- package/docs/WHITEPAPER.md +623 -0
- package/docs/adapters.html +1001 -0
- package/docs/advanced-systems.html +1045 -0
- package/docs/annex.html +1046 -0
- package/docs/api.html +970 -0
- package/docs/business/response-templates.md +160 -0
- package/docs/c2c.html +1225 -0
- package/docs/cli.html +1332 -0
- package/docs/configuration.html +1248 -0
- package/docs/darshan.html +1085 -0
- package/docs/dharma.html +966 -0
- package/docs/docs-bundle.html +1075 -0
- package/docs/docs.css +3120 -0
- package/docs/docs.js +556 -0
- package/docs/doko.html +969 -0
- package/docs/geo-proof.html +858 -0
- package/docs/getting-started.html +840 -0
- package/docs/gumba-tutorial.html +1144 -0
- package/docs/gumba.html +1098 -0
- package/docs/index.html +914 -0
- package/docs/jhilke.html +1312 -0
- package/docs/karma.html +1100 -0
- package/docs/katha.html +1037 -0
- package/docs/lama.html +978 -0
- package/docs/mandala.html +1067 -0
- package/docs/mani.html +964 -0
- package/docs/mantra.html +967 -0
- package/docs/mesh.html +1409 -0
- package/docs/nakpak.html +869 -0
- package/docs/namche.html +928 -0
- package/docs/nav-order.json +53 -0
- package/docs/prahari.html +1043 -0
- package/docs/prism-bash.min.js +1 -0
- package/docs/prism-javascript.min.js +1 -0
- package/docs/prism-json.min.js +1 -0
- package/docs/prism-tomorrow.min.css +1 -0
- package/docs/prism.min.js +1 -0
- package/docs/privacy.html +699 -0
- package/docs/quick-reference.html +1181 -0
- package/docs/sakshi.html +1402 -0
- package/docs/sandboxing.md +386 -0
- package/docs/seva.html +911 -0
- package/docs/sherpa.html +871 -0
- package/docs/studio.html +860 -0
- package/docs/stupa.html +995 -0
- package/docs/tailwind.min.css +2 -0
- package/docs/tattva.html +1332 -0
- package/docs/terms.html +686 -0
- package/docs/time-server-deployment.md +166 -0
- package/docs/time-sources.html +1392 -0
- package/docs/tivra.html +1127 -0
- package/docs/trademark-policy.html +686 -0
- package/docs/tribhuj.html +1183 -0
- package/docs/trust-security.html +1029 -0
- package/docs/tutorials/backup-recovery.html +654 -0
- package/docs/tutorials/dashboard.html +604 -0
- package/docs/tutorials/domain-setup.html +605 -0
- package/docs/tutorials/host-website.html +456 -0
- package/docs/tutorials/mesh-network.html +505 -0
- package/docs/tutorials/mobile-access.html +445 -0
- package/docs/tutorials/privacy.html +467 -0
- package/docs/tutorials/raspberry-pi.html +600 -0
- package/docs/tutorials/security-basics.html +539 -0
- package/docs/tutorials/share-files.html +431 -0
- package/docs/tutorials/troubleshooting.html +637 -0
- package/docs/tutorials/trust-karma.html +419 -0
- package/docs/tutorials/yak-protocol.html +456 -0
- package/docs/tutorials.html +1034 -0
- package/docs/vani.html +1270 -0
- package/docs/webserver.html +809 -0
- package/docs/yak-protocol.html +940 -0
- package/docs/yak-timeserver-design.md +475 -0
- package/docs/yakapp.html +1015 -0
- package/docs/ypc27.html +1069 -0
- package/docs/yurt.html +1344 -0
- package/embedded-docs/bundle.js +334 -74
- package/gossip/protocol.js +247 -27
- package/identity/key-resolver.js +262 -0
- package/identity/machine-seed.js +632 -0
- package/identity/node-key.js +669 -368
- package/identity/tribhuj-ratchet.js +506 -0
- package/knowledge-base.js +37 -8
- package/launcher/yakmesh.bat +62 -0
- package/launcher/yakmesh.sh +70 -0
- package/mesh/annex.js +462 -108
- package/mesh/beacon-broadcast.js +113 -1
- package/mesh/darshan.js +1718 -0
- package/mesh/gumba.js +1567 -0
- package/mesh/jhilke.js +651 -0
- package/mesh/katha.js +1012 -0
- package/mesh/nakpak-routing.js +8 -5
- package/mesh/network.js +724 -34
- package/mesh/pulse-sync.js +4 -1
- package/mesh/rate-limiter.js +127 -15
- package/mesh/seva.js +526 -0
- package/mesh/sherpa-discovery.js +89 -8
- package/mesh/sybil-defense.js +19 -5
- package/mesh/temporal-encoder.js +4 -3
- package/mesh/vani.js +1364 -0
- package/mesh/yurt.js +1340 -0
- package/models/entropy-sentinel.onnx +0 -0
- package/models/karma-trust.onnx +0 -0
- package/models/manifest.json +43 -0
- package/models/sakshi-anomaly.onnx +0 -0
- package/oracle/code-proof-protocol.js +7 -6
- package/oracle/codebase-lock.js +257 -28
- package/oracle/index.js +74 -15
- package/oracle/ma902-snmp.js +678 -0
- package/oracle/module-sealer.js +5 -3
- package/oracle/network-identity.js +16 -0
- package/oracle/packet-checksum.js +201 -0
- package/oracle/sst.js +579 -0
- package/oracle/ternary-144t.js +714 -0
- package/oracle/ternary-ml.js +481 -0
- package/oracle/time-api.js +239 -0
- package/oracle/time-source.js +137 -47
- package/oracle/validation-oracle-hardened.js +1111 -1071
- package/oracle/validation-oracle.js +4 -2
- package/oracle/ypc27.js +211 -0
- package/package.json +20 -3
- package/protocol/yak-handler.js +35 -9
- package/protocol/yak-protocol.js +28 -13
- package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
- package/reference/cpp/yakmesh_ypc27.cpp +179 -0
- package/sbom.json +87 -0
- package/scripts/security-audit.mjs +264 -0
- package/scripts/update-docs-nav.js +194 -0
- package/scripts/update-docs-sidebar.cjs +164 -0
- package/security/crypto-config.js +4 -3
- package/security/dharma-moderation.js +517 -0
- package/security/doko-identity.js +193 -143
- package/security/domain-consensus.js +86 -85
- package/security/fs-hardening.js +620 -0
- package/security/hardware-attestation.js +5 -3
- package/security/hybrid-trust.js +227 -87
- package/security/karma-rate-limiter.js +692 -0
- package/security/khata-protocol.js +22 -21
- package/security/khata-trust-integration.js +277 -150
- package/security/memory-safety.js +635 -0
- package/security/mesh-auth.js +11 -10
- package/security/mesh-revocation.js +373 -5
- package/security/namche-gateway.js +298 -69
- package/security/sakshi.js +460 -3
- package/security/sangha.js +770 -0
- package/security/secure-config.js +473 -0
- package/security/silicon-parity.js +13 -10
- package/security/steadywatch.js +1142 -0
- package/security/strike-system.js +32 -3
- package/security/temporal-signing.js +488 -0
- package/security/trit-commitment.js +464 -0
- package/server/crypto/annex.js +247 -0
- package/server/darshan-api.js +343 -0
- package/server/index.js +3259 -362
- package/server/komm-api.js +668 -0
- package/utils/accel.js +2273 -0
- package/utils/ternary-id.js +79 -0
- package/utils/verify-worker.js +57 -0
- package/webserver/index.js +95 -5
- package/assets/yakmesh-logo.png +0 -0
- package/assets/yakmesh-logo.svg +0 -80
- package/assets/yakmesh-logo2.png +0 -0
- package/assets/yakmesh-logo2sm.png +0 -0
- package/assets/ymsm.png +0 -0
- package/website/assets/silhouettes/adapters.svg +0 -107
- package/website/assets/silhouettes/api-endpoints.svg +0 -115
- package/website/assets/silhouettes/atomic-clock.svg +0 -83
- package/website/assets/silhouettes/base-camp.svg +0 -81
- package/website/assets/silhouettes/bridge.svg +0 -69
- package/website/assets/silhouettes/docs-bundle.svg +0 -113
- package/website/assets/silhouettes/doko-basket.svg +0 -70
- package/website/assets/silhouettes/fortress.svg +0 -93
- package/website/assets/silhouettes/gateway.svg +0 -54
- package/website/assets/silhouettes/gears.svg +0 -93
- package/website/assets/silhouettes/globe-satellite.svg +0 -67
- package/website/assets/silhouettes/karma-wheel.svg +0 -137
- package/website/assets/silhouettes/lama-council.svg +0 -141
- package/website/assets/silhouettes/mandala-network.svg +0 -169
- package/website/assets/silhouettes/mani-stones.svg +0 -149
- package/website/assets/silhouettes/mantra-wheel.svg +0 -116
- package/website/assets/silhouettes/mesh-nodes.svg +0 -113
- package/website/assets/silhouettes/nakpak.svg +0 -56
- package/website/assets/silhouettes/peak-lightning.svg +0 -73
- package/website/assets/silhouettes/sherpa.svg +0 -69
- package/website/assets/silhouettes/stupa-tower.svg +0 -119
- package/website/assets/silhouettes/tattva-eye.svg +0 -78
- package/website/assets/silhouettes/terminal.svg +0 -74
- package/website/assets/silhouettes/webserver.svg +0 -145
- package/website/assets/silhouettes/yak.svg +0 -78
- package/website/assets/yakmesh-logo.png +0 -0
- package/website/assets/yakmesh-logo.webp +0 -0
- package/website/assets/yakmesh-logo128x140.webp +0 -0
- package/website/assets/yakmesh-logo2.png +0 -0
- package/website/assets/yakmesh-logo2.svg +0 -51
- package/website/assets/yakmesh-logo40x44.webp +0 -0
- package/website/assets/yakmesh.gif +0 -0
- package/website/assets/yakmesh.ico +0 -0
- package/website/assets/yakmesh.jpg +0 -0
- package/website/assets/yakmesh.pdf +0 -0
- package/website/assets/yakmesh.png +0 -0
- package/website/assets/yakmesh.svg +0 -70
- package/website/assets/yakmesh128.webp +0 -0
- package/website/assets/yakmesh32.png +0 -0
- package/website/assets/yakmesh32.svg +0 -65
- package/website/assets/yakmesh32o.ico +0 -2
- package/website/assets/yakmesh32o.svg +0 -65
- package/website/assets/yakmesh32o.svgz +0 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yakmesh - Content Adapter Base Class
|
|
3
|
+
*
|
|
4
|
+
* Specialized adapter for content distribution via DARSHAN protocol.
|
|
5
|
+
* Designed for scripture, documents, educational materials, and other
|
|
6
|
+
* content that benefits from the view-not-copy paradigm.
|
|
7
|
+
*
|
|
8
|
+
* @module adapters/content-adapter
|
|
9
|
+
* @version 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { EventEmitter } from 'events';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Capability declarations for content adapters
|
|
16
|
+
* Adapters MUST declare their capabilities upfront
|
|
17
|
+
*/
|
|
18
|
+
export const CONTENT_CAPABILITIES = {
|
|
19
|
+
// Content types this adapter can serve
|
|
20
|
+
SERVE_PDF: 'serve:pdf',
|
|
21
|
+
SERVE_TEXT: 'serve:text',
|
|
22
|
+
SERVE_AUDIO: 'serve:audio',
|
|
23
|
+
SERVE_VIDEO: 'serve:video',
|
|
24
|
+
|
|
25
|
+
// Search/lookup capabilities
|
|
26
|
+
SEARCH_FULLTEXT: 'search:fulltext',
|
|
27
|
+
SEARCH_REFERENCE: 'search:reference', // e.g., John 3:16
|
|
28
|
+
|
|
29
|
+
// Chat integration capabilities
|
|
30
|
+
CHAT_QUOTE: 'chat:quote', // Can generate quotes for KATHA
|
|
31
|
+
CHAT_EMBED: 'chat:embed', // Can embed previews in chat
|
|
32
|
+
CHAT_LOOKUP: 'chat:lookup', // Can respond to lookup commands
|
|
33
|
+
|
|
34
|
+
// Network capabilities
|
|
35
|
+
NET_STREAM: 'net:stream', // Can stream via DARSHAN
|
|
36
|
+
NET_DOWNLOAD: 'net:download', // Allows downloads (opt-in)
|
|
37
|
+
NET_CACHE: 'net:cache', // Can be cached by peers
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Content metadata standard
|
|
42
|
+
*/
|
|
43
|
+
export class ContentMetadata {
|
|
44
|
+
constructor({
|
|
45
|
+
id,
|
|
46
|
+
title,
|
|
47
|
+
author = null,
|
|
48
|
+
copyright = null,
|
|
49
|
+
license = null,
|
|
50
|
+
version = '1.0.0',
|
|
51
|
+
language = 'en',
|
|
52
|
+
contentType = 'application/pdf',
|
|
53
|
+
size = 0,
|
|
54
|
+
hash = null,
|
|
55
|
+
created = new Date(),
|
|
56
|
+
modified = new Date(),
|
|
57
|
+
tags = [],
|
|
58
|
+
references = {}, // e.g., { 'John 3:16': { page: 42, position: 0.3 } }
|
|
59
|
+
} = {}) {
|
|
60
|
+
this.id = id;
|
|
61
|
+
this.title = title;
|
|
62
|
+
this.author = author;
|
|
63
|
+
this.copyright = copyright;
|
|
64
|
+
this.license = license;
|
|
65
|
+
this.version = version;
|
|
66
|
+
this.language = language;
|
|
67
|
+
this.contentType = contentType;
|
|
68
|
+
this.size = size;
|
|
69
|
+
this.hash = hash;
|
|
70
|
+
this.created = created;
|
|
71
|
+
this.modified = modified;
|
|
72
|
+
this.tags = tags;
|
|
73
|
+
this.references = references;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
toJSON() {
|
|
77
|
+
return { ...this };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Abstract base class for content distribution adapters
|
|
83
|
+
*/
|
|
84
|
+
export class ContentAdapter extends EventEmitter {
|
|
85
|
+
/**
|
|
86
|
+
* @param {Object} config - Adapter configuration
|
|
87
|
+
* @param {string} config.name - Human-readable adapter name
|
|
88
|
+
* @param {string} config.id - Unique adapter identifier
|
|
89
|
+
* @param {string[]} config.capabilities - Array of CONTENT_CAPABILITIES
|
|
90
|
+
* @param {Object} config.darshan - DARSHAN instance for streaming
|
|
91
|
+
*/
|
|
92
|
+
constructor(config = {}) {
|
|
93
|
+
super();
|
|
94
|
+
|
|
95
|
+
if (new.target === ContentAdapter) {
|
|
96
|
+
throw new Error('ContentAdapter is abstract and cannot be instantiated directly');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.name = config.name || 'UnnamedContentAdapter';
|
|
100
|
+
this.id = config.id || 'content-adapter-' + Date.now();
|
|
101
|
+
this.capabilities = new Set(config.capabilities || []);
|
|
102
|
+
this.darshan = config.darshan || null;
|
|
103
|
+
|
|
104
|
+
// Content catalog
|
|
105
|
+
this.catalog = new Map(); // id -> ContentMetadata
|
|
106
|
+
|
|
107
|
+
// Statistics
|
|
108
|
+
this.stats = {
|
|
109
|
+
contentServed: 0,
|
|
110
|
+
searchQueries: 0,
|
|
111
|
+
chatQuotes: 0,
|
|
112
|
+
errors: [],
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Security: Validate capabilities
|
|
116
|
+
this._validateCapabilities();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Initialize the adapter and build content catalog
|
|
121
|
+
* @abstract
|
|
122
|
+
*/
|
|
123
|
+
async init() {
|
|
124
|
+
throw new Error('init() must be implemented by subclass');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get list of available content
|
|
129
|
+
* @returns {ContentMetadata[]}
|
|
130
|
+
*/
|
|
131
|
+
listContent() {
|
|
132
|
+
return Array.from(this.catalog.values());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get content metadata by ID
|
|
137
|
+
* @param {string} id - Content ID
|
|
138
|
+
* @returns {ContentMetadata|null}
|
|
139
|
+
*/
|
|
140
|
+
getContentMeta(id) {
|
|
141
|
+
return this.catalog.get(id) || null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Search content by query
|
|
146
|
+
* @abstract
|
|
147
|
+
* @param {string} query - Search query
|
|
148
|
+
* @param {Object} options - Search options
|
|
149
|
+
* @returns {Promise<Object[]>} Search results
|
|
150
|
+
*/
|
|
151
|
+
async search(query, options = {}) {
|
|
152
|
+
throw new Error('search() must be implemented by subclass');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Lookup content by reference (e.g., 'John 3:16')
|
|
157
|
+
* @abstract
|
|
158
|
+
* @param {string} reference - Reference string
|
|
159
|
+
* @returns {Promise<Object|null>} Lookup result
|
|
160
|
+
*/
|
|
161
|
+
async lookupReference(reference) {
|
|
162
|
+
throw new Error('lookupReference() must be implemented by subclass');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Get content stream for DARSHAN
|
|
167
|
+
* @abstract
|
|
168
|
+
* @param {string} id - Content ID
|
|
169
|
+
* @param {Object} options - Stream options (range, quality, etc.)
|
|
170
|
+
* @returns {Promise<ReadableStream>}
|
|
171
|
+
*/
|
|
172
|
+
async getContentStream(id, options = {}) {
|
|
173
|
+
throw new Error('getContentStream() must be implemented by subclass');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Generate a quotable snippet for KATHA chat
|
|
178
|
+
* @param {string} reference - Content reference
|
|
179
|
+
* @param {Object} options - Quote options
|
|
180
|
+
* @returns {Promise<Object>} Quote object for KATHA
|
|
181
|
+
*/
|
|
182
|
+
async generateChatQuote(reference, options = {}) {
|
|
183
|
+
if (!this.capabilities.has(CONTENT_CAPABILITIES.CHAT_QUOTE)) {
|
|
184
|
+
throw new Error('Adapter does not support chat quotes');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const result = await this.lookupReference(reference);
|
|
188
|
+
if (!result) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.stats.chatQuotes++;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
type: 'content-quote',
|
|
196
|
+
adapter: this.id,
|
|
197
|
+
reference,
|
|
198
|
+
text: result.text,
|
|
199
|
+
metadata: {
|
|
200
|
+
source: this.name,
|
|
201
|
+
contentId: result.contentId,
|
|
202
|
+
position: result.position,
|
|
203
|
+
},
|
|
204
|
+
// Security: Sign the quote so it can be verified
|
|
205
|
+
verified: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Register content with DARSHAN for streaming
|
|
211
|
+
* @param {string} id - Content ID
|
|
212
|
+
* @param {Object} options - Registration options
|
|
213
|
+
*/
|
|
214
|
+
async registerWithDarshan(id, options = {}) {
|
|
215
|
+
if (!this.darshan) {
|
|
216
|
+
throw new Error('DARSHAN instance not configured');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const meta = this.catalog.get(id);
|
|
220
|
+
if (!meta) {
|
|
221
|
+
throw new Error('Content not found: ' + id);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Register as a DARSHAN content source
|
|
225
|
+
await this.darshan.registerContent(id, {
|
|
226
|
+
title: meta.title,
|
|
227
|
+
type: meta.contentType,
|
|
228
|
+
size: meta.size,
|
|
229
|
+
getStream: () => this.getContentStream(id),
|
|
230
|
+
allowDownload: options.allowDownload || false,
|
|
231
|
+
// DARSHAN handles view-not-copy enforcement
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
this.emit('content-registered', { id, meta });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Validate declared capabilities
|
|
239
|
+
* @private
|
|
240
|
+
*/
|
|
241
|
+
_validateCapabilities() {
|
|
242
|
+
const validCaps = new Set(Object.values(CONTENT_CAPABILITIES));
|
|
243
|
+
for (const cap of this.capabilities) {
|
|
244
|
+
if (!validCaps.has(cap)) {
|
|
245
|
+
console.warn(\Unknown capability declared: \\);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Check if adapter has a capability
|
|
252
|
+
* @param {string} capability - Capability to check
|
|
253
|
+
* @returns {boolean}
|
|
254
|
+
*/
|
|
255
|
+
hasCapability(capability) {
|
|
256
|
+
return this.capabilities.has(capability);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get adapter statistics
|
|
261
|
+
*/
|
|
262
|
+
getStats() {
|
|
263
|
+
return {
|
|
264
|
+
...this.stats,
|
|
265
|
+
name: this.name,
|
|
266
|
+
id: this.id,
|
|
267
|
+
capabilities: Array.from(this.capabilities),
|
|
268
|
+
catalogSize: this.catalog.size,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export default ContentAdapter;
|
package/content/api.js
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
* YAKMESH™ Public Content API
|
|
3
3
|
* HTTP endpoints for public content delivery
|
|
4
4
|
*
|
|
5
|
+
* Content integrity = SHA3-256 hash match.
|
|
6
|
+
* Content authorship = publisher ML-DSA-65 signature.
|
|
7
|
+
* No voting, no quorum, no consensus proofs.
|
|
8
|
+
*
|
|
5
9
|
* Public (no auth required):
|
|
6
10
|
* - GET /content/:hash - Fetch content by hash
|
|
7
11
|
* - GET /content/:hash/meta - Fetch metadata only
|
|
8
|
-
* - GET /content/:hash/
|
|
12
|
+
* - GET /content/:hash/integrity - Fetch integrity info (hash + publisher sig)
|
|
9
13
|
* - GET /content/list - List available content
|
|
10
14
|
*
|
|
11
15
|
* Authenticated (rate limited):
|
|
@@ -18,18 +22,19 @@
|
|
|
18
22
|
*/
|
|
19
23
|
|
|
20
24
|
import { Router } from 'express';
|
|
21
|
-
import { ContentStore, ContentType, ContentStatus, computeContentHash } from './store.js';
|
|
25
|
+
import { ContentStore, ContentType, ContentStatus, computeContentHash, isTritAddress } from './store.js';
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Create content API router
|
|
25
29
|
*/
|
|
26
30
|
export function createContentAPI(contentStore, options = {}) {
|
|
27
31
|
const router = Router();
|
|
28
|
-
|
|
32
|
+
|
|
29
33
|
const {
|
|
30
34
|
writeLimiter,
|
|
31
35
|
readLimiter,
|
|
32
36
|
validateString,
|
|
37
|
+
requirePeerAuth,
|
|
33
38
|
} = options;
|
|
34
39
|
|
|
35
40
|
// =========================================
|
|
@@ -38,22 +43,20 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
45
|
* GET /content/:hash
|
|
41
|
-
* Fetch content by hash
|
|
46
|
+
* Fetch content by hash
|
|
42
47
|
*
|
|
43
48
|
* Query params:
|
|
44
|
-
* - proof=1 : Include consensus proof in response headers
|
|
45
49
|
* - download=1 : Force download (Content-Disposition)
|
|
46
50
|
*/
|
|
47
51
|
router.get('/:hash', readLimiter, (req, res) => {
|
|
48
52
|
const { hash } = req.params;
|
|
49
|
-
const includeProof = req.query.proof === '1';
|
|
50
53
|
const download = req.query.download === '1';
|
|
51
54
|
|
|
52
55
|
// Get content with metadata
|
|
53
56
|
const result = contentStore.getWithProof(hash);
|
|
54
|
-
|
|
57
|
+
|
|
55
58
|
if (!result) {
|
|
56
|
-
return res.status(404).json({
|
|
59
|
+
return res.status(404).json({
|
|
57
60
|
error: 'Content not found',
|
|
58
61
|
hash,
|
|
59
62
|
hint: 'Content may not have synced yet. Try again later.',
|
|
@@ -64,19 +67,22 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
64
67
|
res.setHeader('Content-Type', result.meta?.contentType || 'application/octet-stream');
|
|
65
68
|
res.setHeader('Content-Length', result.meta?.size || result.content.length);
|
|
66
69
|
res.setHeader('X-Content-Hash', result.hash);
|
|
70
|
+
res.setHeader('X-Content-Hash-144T', result.hash144t || result.meta?.hash144t || '');
|
|
67
71
|
res.setHeader('X-Content-Status', result.meta?.status || 'unknown');
|
|
68
|
-
|
|
69
|
-
// Cache headers (
|
|
72
|
+
|
|
73
|
+
// Cache headers (verified content = cache forever)
|
|
70
74
|
if (result.verified) {
|
|
71
75
|
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
76
|
+
res.setHeader('X-Verified', 'true');
|
|
72
77
|
} else {
|
|
73
78
|
res.setHeader('Cache-Control', 'public, max-age=60');
|
|
79
|
+
res.setHeader('X-Verified', 'false');
|
|
74
80
|
}
|
|
75
81
|
|
|
76
|
-
//
|
|
77
|
-
if (
|
|
78
|
-
res.setHeader('X-
|
|
79
|
-
res.setHeader('X-
|
|
82
|
+
// Publisher signature header
|
|
83
|
+
if (result.meta?.publisherSignature) {
|
|
84
|
+
res.setHeader('X-Publisher-Signature', result.meta.publisherSignature);
|
|
85
|
+
res.setHeader('X-Published-By', result.meta.publishedBy || 'unknown');
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
// Download disposition
|
|
@@ -95,7 +101,7 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
95
101
|
router.get('/:hash/meta', readLimiter, (req, res) => {
|
|
96
102
|
const { hash } = req.params;
|
|
97
103
|
const meta = contentStore.getMeta(hash);
|
|
98
|
-
|
|
104
|
+
|
|
99
105
|
if (!meta) {
|
|
100
106
|
return res.status(404).json({ error: 'Content not found', hash });
|
|
101
107
|
}
|
|
@@ -104,30 +110,31 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
104
110
|
});
|
|
105
111
|
|
|
106
112
|
/**
|
|
107
|
-
* GET /content/:hash/
|
|
108
|
-
* Fetch
|
|
113
|
+
* GET /content/:hash/integrity
|
|
114
|
+
* Fetch integrity info for content verification
|
|
115
|
+
* Returns hash, publisher identity, publisher signature, and verification status.
|
|
116
|
+
* Any client can independently verify: hash(content) === hash AND
|
|
117
|
+
* verify(hash, publisherSignature, publisherPubKey) === true.
|
|
109
118
|
*/
|
|
110
|
-
router.get('/:hash/
|
|
119
|
+
router.get('/:hash/integrity', readLimiter, (req, res) => {
|
|
111
120
|
const { hash } = req.params;
|
|
112
121
|
const meta = contentStore.getMeta(hash);
|
|
113
|
-
|
|
122
|
+
|
|
114
123
|
if (!meta) {
|
|
115
124
|
return res.status(404).json({ error: 'Content not found', hash });
|
|
116
125
|
}
|
|
117
126
|
|
|
118
|
-
if (!meta.consensusProof) {
|
|
119
|
-
return res.status(404).json({
|
|
120
|
-
error: 'No consensus proof yet',
|
|
121
|
-
hash,
|
|
122
|
-
status: meta.status,
|
|
123
|
-
hint: 'Content may still be pending consensus.',
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
127
|
res.json({
|
|
128
|
-
hash,
|
|
128
|
+
hash: meta.hash,
|
|
129
|
+
hash144t: meta.hash144t,
|
|
130
|
+
ioName: meta.ioName,
|
|
129
131
|
verified: meta.status === ContentStatus.VERIFIED,
|
|
130
|
-
|
|
132
|
+
status: meta.status,
|
|
133
|
+
publishedBy: meta.publishedBy,
|
|
134
|
+
publisherSignature: meta.publisherSignature || null,
|
|
135
|
+
contentType: meta.contentType,
|
|
136
|
+
size: meta.size,
|
|
137
|
+
createdAt: meta.createdAt,
|
|
131
138
|
});
|
|
132
139
|
});
|
|
133
140
|
|
|
@@ -143,7 +150,7 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
143
150
|
*/
|
|
144
151
|
router.get('/', readLimiter, (req, res) => {
|
|
145
152
|
const { tag, status, limit = 100, offset = 0 } = req.query;
|
|
146
|
-
|
|
153
|
+
|
|
147
154
|
const items = contentStore.list({
|
|
148
155
|
tag,
|
|
149
156
|
status,
|
|
@@ -164,7 +171,7 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
164
171
|
*/
|
|
165
172
|
router.head('/:hash', readLimiter, (req, res) => {
|
|
166
173
|
const { hash } = req.params;
|
|
167
|
-
|
|
174
|
+
|
|
168
175
|
if (contentStore.has(hash)) {
|
|
169
176
|
const meta = contentStore.getMeta(hash);
|
|
170
177
|
res.setHeader('Content-Type', meta?.contentType || 'application/octet-stream');
|
|
@@ -199,7 +206,7 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
199
206
|
* - name: optional name
|
|
200
207
|
* - tags: comma-separated tags
|
|
201
208
|
*/
|
|
202
|
-
router.post('/publish', writeLimiter, async (req, res) => {
|
|
209
|
+
router.post('/publish', writeLimiter, requirePeerAuth, async (req, res) => {
|
|
203
210
|
try {
|
|
204
211
|
let content;
|
|
205
212
|
let options = {};
|
|
@@ -216,7 +223,7 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
216
223
|
tags: req.body.tags || [],
|
|
217
224
|
ttl: req.body.ttl || 0,
|
|
218
225
|
};
|
|
219
|
-
}
|
|
226
|
+
}
|
|
220
227
|
// Handle raw body
|
|
221
228
|
else if (req.body && Buffer.isBuffer(req.body)) {
|
|
222
229
|
content = req.body;
|
|
@@ -245,9 +252,11 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
245
252
|
res.status(201).json({
|
|
246
253
|
success: true,
|
|
247
254
|
hash: result.hash,
|
|
255
|
+
hash144t: result.hash144t,
|
|
256
|
+
ioName: result.ioName,
|
|
248
257
|
status: result.status,
|
|
249
258
|
meta: result.meta?.toJSON ? result.meta.toJSON() : result.meta,
|
|
250
|
-
url: `/content/${result.hash}`,
|
|
259
|
+
url: `/content/${result.hash144t || result.hash}`,
|
|
251
260
|
});
|
|
252
261
|
} catch (error) {
|
|
253
262
|
res.status(500).json({ error: error.message });
|
|
@@ -260,7 +269,7 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
260
269
|
*/
|
|
261
270
|
router.post('/request', writeLimiter, async (req, res) => {
|
|
262
271
|
const { hash } = req.body;
|
|
263
|
-
|
|
272
|
+
|
|
264
273
|
if (!hash) {
|
|
265
274
|
return res.status(400).json({ error: 'Hash required' });
|
|
266
275
|
}
|
|
@@ -277,7 +286,7 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
277
286
|
|
|
278
287
|
// Request from mesh
|
|
279
288
|
const result = await contentStore.request(hash);
|
|
280
|
-
|
|
289
|
+
|
|
281
290
|
res.json({
|
|
282
291
|
found: true,
|
|
283
292
|
local: false,
|
|
@@ -297,9 +306,9 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
297
306
|
* DELETE /content/:hash
|
|
298
307
|
* Remove content (local only - cannot remove from mesh)
|
|
299
308
|
*/
|
|
300
|
-
router.delete('/:hash', writeLimiter, (req, res) => {
|
|
309
|
+
router.delete('/:hash', writeLimiter, requirePeerAuth, (req, res) => {
|
|
301
310
|
const { hash } = req.params;
|
|
302
|
-
|
|
311
|
+
|
|
303
312
|
if (!contentStore.has(hash)) {
|
|
304
313
|
return res.status(404).json({ error: 'Content not found', hash });
|
|
305
314
|
}
|
|
@@ -329,13 +338,13 @@ export function createContentAPI(contentStore, options = {}) {
|
|
|
329
338
|
*/
|
|
330
339
|
router.post('/verify', readLimiter, (req, res) => {
|
|
331
340
|
const content = req.body.content || req.body;
|
|
332
|
-
|
|
341
|
+
|
|
333
342
|
if (!content) {
|
|
334
343
|
return res.status(400).json({ error: 'Content required' });
|
|
335
344
|
}
|
|
336
345
|
|
|
337
346
|
const hash = computeContentHash(content);
|
|
338
|
-
|
|
347
|
+
|
|
339
348
|
res.json({
|
|
340
349
|
hash,
|
|
341
350
|
exists: contentStore.has(hash),
|
package/content/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* YAKMESH™ Content Module
|
|
3
|
-
* Content-addressed storage with
|
|
3
|
+
* Content-addressed storage with integrity verification
|
|
4
4
|
*
|
|
5
5
|
* @module content
|
|
6
6
|
* @license MIT
|
|
@@ -12,8 +12,8 @@ export {
|
|
|
12
12
|
ContentType,
|
|
13
13
|
ContentStatus,
|
|
14
14
|
ContentMetadata,
|
|
15
|
-
ConsensusProof,
|
|
16
15
|
computeContentHash,
|
|
16
|
+
deriveContentName,
|
|
17
17
|
} from './store.js';
|
|
18
18
|
|
|
19
19
|
export { createContentAPI } from './api.js';
|