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.
Files changed (232) hide show
  1. package/CHANGELOG.md +637 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/Caddyfile +77 -0
  4. package/README.md +119 -29
  5. package/adapters/adapter-mlv-bible/README.md +124 -0
  6. package/adapters/adapter-mlv-bible/index.js +400 -0
  7. package/adapters/chat-mod-adapter.js +532 -0
  8. package/adapters/content-adapter.js +273 -0
  9. package/content/api.js +50 -41
  10. package/content/index.js +2 -2
  11. package/content/store.js +355 -173
  12. package/dashboard/index.html +19 -3
  13. package/database/replication.js +117 -37
  14. package/docs/CRYPTO-AGILITY.md +204 -0
  15. package/docs/MTLS-RESEARCH.md +367 -0
  16. package/docs/NAMCHE-SPEC.md +681 -0
  17. package/docs/PEERQUANTA-YAKMESH-INTEGRATION.md +407 -0
  18. package/docs/PRECISION-DISCLOSURE.md +96 -0
  19. package/docs/README.md +76 -0
  20. package/docs/ROADMAP-2.4.0.md +447 -0
  21. package/docs/ROADMAP-2.5.0.md +244 -0
  22. package/docs/SECURITY-AUDIT-REPORT.md +306 -0
  23. package/docs/SST-INTEGRATION.md +712 -0
  24. package/docs/STEADYWATCH-IMPLEMENTATION.md +303 -0
  25. package/docs/TERNARY-AUDIT-REPORT.md +247 -0
  26. package/docs/TME-FAQ.md +221 -0
  27. package/docs/WHITEPAPER.md +623 -0
  28. package/docs/adapters.html +1001 -0
  29. package/docs/advanced-systems.html +1045 -0
  30. package/docs/annex.html +1046 -0
  31. package/docs/api.html +970 -0
  32. package/docs/business/response-templates.md +160 -0
  33. package/docs/c2c.html +1225 -0
  34. package/docs/cli.html +1332 -0
  35. package/docs/configuration.html +1248 -0
  36. package/docs/darshan.html +1085 -0
  37. package/docs/dharma.html +966 -0
  38. package/docs/docs-bundle.html +1075 -0
  39. package/docs/docs.css +3120 -0
  40. package/docs/docs.js +556 -0
  41. package/docs/doko.html +969 -0
  42. package/docs/geo-proof.html +858 -0
  43. package/docs/getting-started.html +840 -0
  44. package/docs/gumba-tutorial.html +1144 -0
  45. package/docs/gumba.html +1098 -0
  46. package/docs/index.html +914 -0
  47. package/docs/jhilke.html +1312 -0
  48. package/docs/karma.html +1100 -0
  49. package/docs/katha.html +1037 -0
  50. package/docs/lama.html +978 -0
  51. package/docs/mandala.html +1067 -0
  52. package/docs/mani.html +964 -0
  53. package/docs/mantra.html +967 -0
  54. package/docs/mesh.html +1409 -0
  55. package/docs/nakpak.html +869 -0
  56. package/docs/namche.html +928 -0
  57. package/docs/nav-order.json +53 -0
  58. package/docs/prahari.html +1043 -0
  59. package/docs/prism-bash.min.js +1 -0
  60. package/docs/prism-javascript.min.js +1 -0
  61. package/docs/prism-json.min.js +1 -0
  62. package/docs/prism-tomorrow.min.css +1 -0
  63. package/docs/prism.min.js +1 -0
  64. package/docs/privacy.html +699 -0
  65. package/docs/quick-reference.html +1181 -0
  66. package/docs/sakshi.html +1402 -0
  67. package/docs/sandboxing.md +386 -0
  68. package/docs/seva.html +911 -0
  69. package/docs/sherpa.html +871 -0
  70. package/docs/studio.html +860 -0
  71. package/docs/stupa.html +995 -0
  72. package/docs/tailwind.min.css +2 -0
  73. package/docs/tattva.html +1332 -0
  74. package/docs/terms.html +686 -0
  75. package/docs/time-server-deployment.md +166 -0
  76. package/docs/time-sources.html +1392 -0
  77. package/docs/tivra.html +1127 -0
  78. package/docs/trademark-policy.html +686 -0
  79. package/docs/tribhuj.html +1183 -0
  80. package/docs/trust-security.html +1029 -0
  81. package/docs/tutorials/backup-recovery.html +654 -0
  82. package/docs/tutorials/dashboard.html +604 -0
  83. package/docs/tutorials/domain-setup.html +605 -0
  84. package/docs/tutorials/host-website.html +456 -0
  85. package/docs/tutorials/mesh-network.html +505 -0
  86. package/docs/tutorials/mobile-access.html +445 -0
  87. package/docs/tutorials/privacy.html +467 -0
  88. package/docs/tutorials/raspberry-pi.html +600 -0
  89. package/docs/tutorials/security-basics.html +539 -0
  90. package/docs/tutorials/share-files.html +431 -0
  91. package/docs/tutorials/troubleshooting.html +637 -0
  92. package/docs/tutorials/trust-karma.html +419 -0
  93. package/docs/tutorials/yak-protocol.html +456 -0
  94. package/docs/tutorials.html +1034 -0
  95. package/docs/vani.html +1270 -0
  96. package/docs/webserver.html +809 -0
  97. package/docs/yak-protocol.html +940 -0
  98. package/docs/yak-timeserver-design.md +475 -0
  99. package/docs/yakapp.html +1015 -0
  100. package/docs/ypc27.html +1069 -0
  101. package/docs/yurt.html +1344 -0
  102. package/embedded-docs/bundle.js +334 -74
  103. package/gossip/protocol.js +247 -27
  104. package/identity/key-resolver.js +262 -0
  105. package/identity/machine-seed.js +632 -0
  106. package/identity/node-key.js +669 -368
  107. package/identity/tribhuj-ratchet.js +506 -0
  108. package/knowledge-base.js +37 -8
  109. package/launcher/yakmesh.bat +62 -0
  110. package/launcher/yakmesh.sh +70 -0
  111. package/mesh/annex.js +462 -108
  112. package/mesh/beacon-broadcast.js +113 -1
  113. package/mesh/darshan.js +1718 -0
  114. package/mesh/gumba.js +1567 -0
  115. package/mesh/jhilke.js +651 -0
  116. package/mesh/katha.js +1012 -0
  117. package/mesh/nakpak-routing.js +8 -5
  118. package/mesh/network.js +724 -34
  119. package/mesh/pulse-sync.js +4 -1
  120. package/mesh/rate-limiter.js +127 -15
  121. package/mesh/seva.js +526 -0
  122. package/mesh/sherpa-discovery.js +89 -8
  123. package/mesh/sybil-defense.js +19 -5
  124. package/mesh/temporal-encoder.js +4 -3
  125. package/mesh/vani.js +1364 -0
  126. package/mesh/yurt.js +1340 -0
  127. package/models/entropy-sentinel.onnx +0 -0
  128. package/models/karma-trust.onnx +0 -0
  129. package/models/manifest.json +43 -0
  130. package/models/sakshi-anomaly.onnx +0 -0
  131. package/oracle/code-proof-protocol.js +7 -6
  132. package/oracle/codebase-lock.js +257 -28
  133. package/oracle/index.js +74 -15
  134. package/oracle/ma902-snmp.js +678 -0
  135. package/oracle/module-sealer.js +5 -3
  136. package/oracle/network-identity.js +16 -0
  137. package/oracle/packet-checksum.js +201 -0
  138. package/oracle/sst.js +579 -0
  139. package/oracle/ternary-144t.js +714 -0
  140. package/oracle/ternary-ml.js +481 -0
  141. package/oracle/time-api.js +239 -0
  142. package/oracle/time-source.js +137 -47
  143. package/oracle/validation-oracle-hardened.js +1111 -1071
  144. package/oracle/validation-oracle.js +4 -2
  145. package/oracle/ypc27.js +211 -0
  146. package/package.json +20 -3
  147. package/protocol/yak-handler.js +35 -9
  148. package/protocol/yak-protocol.js +28 -13
  149. package/reference/cpp/yakmesh_mceliece_shard.cpp +168 -0
  150. package/reference/cpp/yakmesh_ypc27.cpp +179 -0
  151. package/sbom.json +87 -0
  152. package/scripts/security-audit.mjs +264 -0
  153. package/scripts/update-docs-nav.js +194 -0
  154. package/scripts/update-docs-sidebar.cjs +164 -0
  155. package/security/crypto-config.js +4 -3
  156. package/security/dharma-moderation.js +517 -0
  157. package/security/doko-identity.js +193 -143
  158. package/security/domain-consensus.js +86 -85
  159. package/security/fs-hardening.js +620 -0
  160. package/security/hardware-attestation.js +5 -3
  161. package/security/hybrid-trust.js +227 -87
  162. package/security/karma-rate-limiter.js +692 -0
  163. package/security/khata-protocol.js +22 -21
  164. package/security/khata-trust-integration.js +277 -150
  165. package/security/memory-safety.js +635 -0
  166. package/security/mesh-auth.js +11 -10
  167. package/security/mesh-revocation.js +373 -5
  168. package/security/namche-gateway.js +298 -69
  169. package/security/sakshi.js +460 -3
  170. package/security/sangha.js +770 -0
  171. package/security/secure-config.js +473 -0
  172. package/security/silicon-parity.js +13 -10
  173. package/security/steadywatch.js +1142 -0
  174. package/security/strike-system.js +32 -3
  175. package/security/temporal-signing.js +488 -0
  176. package/security/trit-commitment.js +464 -0
  177. package/server/crypto/annex.js +247 -0
  178. package/server/darshan-api.js +343 -0
  179. package/server/index.js +3259 -362
  180. package/server/komm-api.js +668 -0
  181. package/utils/accel.js +2273 -0
  182. package/utils/ternary-id.js +79 -0
  183. package/utils/verify-worker.js +57 -0
  184. package/webserver/index.js +95 -5
  185. package/assets/yakmesh-logo.png +0 -0
  186. package/assets/yakmesh-logo.svg +0 -80
  187. package/assets/yakmesh-logo2.png +0 -0
  188. package/assets/yakmesh-logo2sm.png +0 -0
  189. package/assets/ymsm.png +0 -0
  190. package/website/assets/silhouettes/adapters.svg +0 -107
  191. package/website/assets/silhouettes/api-endpoints.svg +0 -115
  192. package/website/assets/silhouettes/atomic-clock.svg +0 -83
  193. package/website/assets/silhouettes/base-camp.svg +0 -81
  194. package/website/assets/silhouettes/bridge.svg +0 -69
  195. package/website/assets/silhouettes/docs-bundle.svg +0 -113
  196. package/website/assets/silhouettes/doko-basket.svg +0 -70
  197. package/website/assets/silhouettes/fortress.svg +0 -93
  198. package/website/assets/silhouettes/gateway.svg +0 -54
  199. package/website/assets/silhouettes/gears.svg +0 -93
  200. package/website/assets/silhouettes/globe-satellite.svg +0 -67
  201. package/website/assets/silhouettes/karma-wheel.svg +0 -137
  202. package/website/assets/silhouettes/lama-council.svg +0 -141
  203. package/website/assets/silhouettes/mandala-network.svg +0 -169
  204. package/website/assets/silhouettes/mani-stones.svg +0 -149
  205. package/website/assets/silhouettes/mantra-wheel.svg +0 -116
  206. package/website/assets/silhouettes/mesh-nodes.svg +0 -113
  207. package/website/assets/silhouettes/nakpak.svg +0 -56
  208. package/website/assets/silhouettes/peak-lightning.svg +0 -73
  209. package/website/assets/silhouettes/sherpa.svg +0 -69
  210. package/website/assets/silhouettes/stupa-tower.svg +0 -119
  211. package/website/assets/silhouettes/tattva-eye.svg +0 -78
  212. package/website/assets/silhouettes/terminal.svg +0 -74
  213. package/website/assets/silhouettes/webserver.svg +0 -145
  214. package/website/assets/silhouettes/yak.svg +0 -78
  215. package/website/assets/yakmesh-logo.png +0 -0
  216. package/website/assets/yakmesh-logo.webp +0 -0
  217. package/website/assets/yakmesh-logo128x140.webp +0 -0
  218. package/website/assets/yakmesh-logo2.png +0 -0
  219. package/website/assets/yakmesh-logo2.svg +0 -51
  220. package/website/assets/yakmesh-logo40x44.webp +0 -0
  221. package/website/assets/yakmesh.gif +0 -0
  222. package/website/assets/yakmesh.ico +0 -0
  223. package/website/assets/yakmesh.jpg +0 -0
  224. package/website/assets/yakmesh.pdf +0 -0
  225. package/website/assets/yakmesh.png +0 -0
  226. package/website/assets/yakmesh.svg +0 -70
  227. package/website/assets/yakmesh128.webp +0 -0
  228. package/website/assets/yakmesh32.png +0 -0
  229. package/website/assets/yakmesh32.svg +0 -65
  230. package/website/assets/yakmesh32o.ico +0 -2
  231. package/website/assets/yakmesh32o.svg +0 -65
  232. package/website/assets/yakmesh32o.svgz +0 -0
@@ -0,0 +1,517 @@
1
+ /**
2
+ * DHARMA Content Moderation Module
3
+ *
4
+ * Universal behavior-based content moderation for Yakmesh.
5
+ * Filters ACTIONS, not IDENTITIES.
6
+ *
7
+ * Philosophy:
8
+ * - No religious, ethnic, or identity-based discrimination
9
+ * - Focus on harmful BEHAVIORS: violence, exploitation, terrorism
10
+ * - Transparent criteria published openly
11
+ * - Host sovereignty: operators may extend locally
12
+ *
13
+ * @module security/dharma-moderation.js
14
+ * @version 3.0.0
15
+ * @license MIT
16
+ */
17
+
18
+ import { createHash } from 'crypto';
19
+ import { EventEmitter } from 'events';
20
+
21
+ // ============================================================
22
+ // PROHIBITED CONTENT CATEGORIES
23
+ // ============================================================
24
+
25
+ /**
26
+ * Content categories that are universally prohibited.
27
+ * These target BEHAVIORS and ACTIONS, not identities.
28
+ */
29
+ export const PROHIBITED_CATEGORIES = Object.freeze({
30
+ // Violence & Harm
31
+ VIOLENCE_INCITEMENT: {
32
+ id: 'violence-incitement',
33
+ severity: 'critical',
34
+ description: 'Content that directly incites violence against individuals or groups',
35
+ keywords: [
36
+ 'kill them', 'murder them', 'exterminate', 'genocide', 'ethnic cleansing',
37
+ 'mass shooting', 'bomb them', 'eradicate', 'purge them'
38
+ ],
39
+ patterns: [
40
+ /\b(kill|murder|shoot|stab|bomb)\s+(all|every|the)\s+\w+s?\b/i,
41
+ /\bdeath\s+to\s+\w+\b/i,
42
+ ]
43
+ },
44
+
45
+ TERRORISM_PROMOTION: {
46
+ id: 'terrorism-promotion',
47
+ severity: 'critical',
48
+ description: 'Content that promotes, glorifies or recruits for terrorism',
49
+ keywords: [
50
+ 'join isis', 'join al-qaeda', 'jihad against', 'martyrdom operation',
51
+ 'suicide bombing', 'terrorist attack', 'terror cell'
52
+ ],
53
+ patterns: [
54
+ /\bterror(ist)?\s+(attack|cell|group|organization)\b/i,
55
+ /\brecruit.*for.*terror/i,
56
+ ]
57
+ },
58
+
59
+ WEAPONS_INSTRUCTIONS: {
60
+ id: 'weapons-instructions',
61
+ severity: 'high',
62
+ description: 'Detailed instructions for creating weapons of mass harm',
63
+ keywords: [
64
+ 'how to make bomb', 'pipe bomb instructions', 'ricin recipe',
65
+ 'anthrax creation', 'sarin synthesis', 'nerve agent'
66
+ ],
67
+ patterns: [
68
+ /\bhow\s+to\s+(make|build|create)\s+(a\s+)?(bomb|explosive|poison)/i,
69
+ /\b(detailed|step.by.step)\s+instructions?\s+for\s+(bomb|weapon)/i,
70
+ ]
71
+ },
72
+
73
+ // Exploitation
74
+ CHILD_EXPLOITATION: {
75
+ id: 'child-exploitation',
76
+ severity: 'critical',
77
+ description: 'Any content that sexualizes or exploits minors',
78
+ keywords: [
79
+ 'csam', 'child porn', 'pedo', 'minor explicit',
80
+ 'underage sex', 'child abuse material'
81
+ ],
82
+ patterns: [
83
+ /\b(child|minor|underage)\s+(porn|sex|explicit|nude)/i,
84
+ /\bcp\b.*\b(material|content|images)/i,
85
+ ]
86
+ },
87
+
88
+ HUMAN_TRAFFICKING: {
89
+ id: 'human-trafficking',
90
+ severity: 'critical',
91
+ description: 'Content facilitating human trafficking or slavery',
92
+ keywords: [
93
+ 'buy slaves', 'sell humans', 'traffick women', 'traffick children',
94
+ 'sex slavery', 'forced labor market'
95
+ ],
96
+ patterns: [
97
+ /\b(buy|sell|trade)\s+(slaves?|humans?|people)\b/i,
98
+ /\btraffick(ing)?\s+(women|children|people)\b/i,
99
+ ]
100
+ },
101
+
102
+ // Harmful Instructions
103
+ SELF_HARM_PROMOTION: {
104
+ id: 'self-harm-promotion',
105
+ severity: 'high',
106
+ description: 'Content that promotes or provides methods for self-harm or suicide',
107
+ keywords: [
108
+ 'how to kill yourself', 'suicide methods', 'best way to die',
109
+ 'pro-ana', 'pro-mia', 'cutting tutorial'
110
+ ],
111
+ patterns: [
112
+ /\bhow\s+to\s+(kill|end)\s+(yourself|your\s+life)/i,
113
+ /\b(best|easy|painless)\s+(way|method)\s+to\s+die\b/i,
114
+ ]
115
+ },
116
+
117
+ DOXXING: {
118
+ id: 'doxxing',
119
+ severity: 'high',
120
+ description: 'Publishing private information to enable harassment',
121
+ keywords: [
122
+ 'home address of', 'personal phone', 'doxx this person',
123
+ 'leak their info', 'find where they live'
124
+ ],
125
+ patterns: [
126
+ /\b(doxx|dox)\s+(this|them|him|her)\b/i,
127
+ /\bpost\s+(their|his|her)\s+(address|phone|ssn)\b/i,
128
+ ]
129
+ },
130
+
131
+ // Fraud & Scams
132
+ FINANCIAL_FRAUD: {
133
+ id: 'financial-fraud',
134
+ severity: 'medium',
135
+ description: 'Content promoting financial scams or fraud schemes',
136
+ keywords: [
137
+ 'steal credit cards', 'carding tutorial', 'phishing kit',
138
+ 'identity theft', 'bank fraud', 'money laundering'
139
+ ],
140
+ patterns: [
141
+ /\b(steal|hack)\s+(credit\s+cards?|bank\s+accounts?)\b/i,
142
+ /\b(carding|phishing)\s+(tutorial|guide|kit)\b/i,
143
+ ]
144
+ },
145
+
146
+ // Specific Harmful Rituals
147
+ HUMAN_SACRIFICE: {
148
+ id: 'human-sacrifice',
149
+ severity: 'critical',
150
+ description: 'Content promoting or instructing human sacrifice rituals',
151
+ keywords: [
152
+ 'human sacrifice ritual', 'blood sacrifice human', 'sacrificial killing',
153
+ 'ritual murder', 'sacrifice a person'
154
+ ],
155
+ patterns: [
156
+ /\bhuman\s+sacrifice\b/i,
157
+ /\bsacrifice\s+(a\s+)?(person|child|human|victim)\b/i,
158
+ /\britual\s+(murder|killing|sacrifice)\b/i,
159
+ ]
160
+ },
161
+ });
162
+
163
+ /**
164
+ * Severity levels for moderation actions
165
+ */
166
+ export const SEVERITY_LEVELS = Object.freeze({
167
+ CRITICAL: 'critical', // Immediate block, report to authorities option
168
+ HIGH: 'high', // Block content, flag for review
169
+ MEDIUM: 'medium', // Flag for review, allow with warning
170
+ LOW: 'low', // Log only, allow
171
+ });
172
+
173
+ /**
174
+ * Moderation actions
175
+ */
176
+ export const MODERATION_ACTIONS = Object.freeze({
177
+ BLOCK: 'block', // Prevent content from being distributed
178
+ FLAG: 'flag', // Allow but mark for review
179
+ WARN: 'warn', // Allow with warning to user
180
+ LOG: 'log', // Silent logging only
181
+ ALLOW: 'allow', // No action
182
+ });
183
+
184
+ // ============================================================
185
+ // DHARMA MODERATOR CLASS
186
+ // ============================================================
187
+
188
+ /**
189
+ * DharmaModerator - Universal behavior-based content moderation
190
+ *
191
+ * Named after the concept of righteous conduct across traditions.
192
+ * Enforces ethical behavior standards without religious discrimination.
193
+ */
194
+ export class DharmaModerator extends EventEmitter {
195
+ /**
196
+ * Create a new DharmaModerator instance
197
+ * @param {Object} config - Configuration options
198
+ */
199
+ constructor(config = {}) {
200
+ super();
201
+
202
+ this.config = {
203
+ // Default severity thresholds
204
+ blockThreshold: SEVERITY_LEVELS.HIGH,
205
+ flagThreshold: SEVERITY_LEVELS.MEDIUM,
206
+
207
+ // Enable/disable categories
208
+ enabledCategories: Object.keys(PROHIBITED_CATEGORIES),
209
+
210
+ // Custom patterns (host sovereignty)
211
+ customPatterns: [],
212
+
213
+ // Logging
214
+ logLevel: 'info',
215
+
216
+ // Rate limiting for moderation checks
217
+ maxChecksPerMinute: 1000,
218
+
219
+ ...config,
220
+ };
221
+
222
+ this.checkCount = 0;
223
+ this.lastCheckReset = Date.now();
224
+
225
+ // Build pattern index for performance
226
+ this._buildPatternIndex();
227
+ }
228
+
229
+ /**
230
+ * Build optimized pattern index from categories
231
+ * @private
232
+ */
233
+ _buildPatternIndex() {
234
+ this.patternIndex = new Map();
235
+
236
+ for (const [categoryKey, category] of Object.entries(PROHIBITED_CATEGORIES)) {
237
+ if (!this.config.enabledCategories.includes(categoryKey)) continue;
238
+
239
+ // Add keyword patterns (word boundary wrapped, metacharacters escaped)
240
+ for (const keyword of category.keywords) {
241
+ const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
242
+ const pattern = new RegExp('\\b' + escaped.replace(/\s+/g, '\\s+') + '\\b', 'i');
243
+ this.patternIndex.set(pattern, { category, match: 'keyword', original: keyword });
244
+ }
245
+
246
+ // Add regex patterns
247
+ for (const pattern of category.patterns) {
248
+ this.patternIndex.set(pattern, { category, match: 'pattern' });
249
+ }
250
+ }
251
+
252
+ // Add custom patterns
253
+ for (const custom of this.config.customPatterns) {
254
+ this.patternIndex.set(
255
+ custom.pattern,
256
+ { category: custom, match: 'custom' }
257
+ );
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Check content against moderation rules
263
+ * @param {string} content - Content to check
264
+ * @param {Object} context - Optional context (adapterId, userId, etc.)
265
+ * @returns {Object} Moderation result
266
+ */
267
+ async checkContent(content, context = {}) {
268
+ // Rate limiting
269
+ this._checkRateLimit();
270
+
271
+ if (!content || typeof content !== 'string') {
272
+ return this._createResult(MODERATION_ACTIONS.ALLOW, null, content);
273
+ }
274
+
275
+ const normalizedContent = this._normalizeContent(content);
276
+ const violations = [];
277
+
278
+ // Check against all patterns
279
+ for (const [pattern, info] of this.patternIndex) {
280
+ if (pattern.test(normalizedContent)) {
281
+ violations.push({
282
+ categoryId: info.category.id,
283
+ severity: info.category.severity,
284
+ matchType: info.match,
285
+ pattern: info.original || pattern.source,
286
+ description: info.category.description,
287
+ });
288
+ }
289
+ }
290
+
291
+ // Determine action based on violations
292
+ const result = this._determineAction(violations, content, context);
293
+
294
+ // Emit events for logging/analysis
295
+ if (result.action !== MODERATION_ACTIONS.ALLOW) {
296
+ this.emit('violation', {
297
+ result,
298
+ context,
299
+ timestamp: Date.now(),
300
+ contentHash: this._hashContent(content),
301
+ });
302
+ }
303
+
304
+ return result;
305
+ }
306
+
307
+ /**
308
+ * Batch check multiple content items
309
+ * @param {string[]} contents - Array of content strings
310
+ * @param {Object} context - Shared context
311
+ * @returns {Object[]} Array of moderation results
312
+ */
313
+ async checkBatch(contents, context = {}) {
314
+ return Promise.all(
315
+ contents.map(content => this.checkContent(content, context))
316
+ );
317
+ }
318
+
319
+ /**
320
+ * Normalize content for consistent matching
321
+ * @private
322
+ */
323
+ _normalizeContent(content) {
324
+ return content
325
+ .toLowerCase()
326
+ // Remove excessive whitespace
327
+ .replace(/\s+/g, ' ')
328
+ // Remove common obfuscation
329
+ .replace(/[0-9@$!]/g, match => {
330
+ const map = { '0': 'o', '@': 'a', '$': 's', '!': 'i', '1': 'i', '3': 'e' };
331
+ return map[match] || match;
332
+ })
333
+ .trim();
334
+ }
335
+
336
+ /**
337
+ * Create a moderation result object
338
+ * @private
339
+ */
340
+ _createResult(action, violations, content) {
341
+ return {
342
+ action,
343
+ allowed: action !== MODERATION_ACTIONS.BLOCK,
344
+ violations: violations || [],
345
+ violationCount: violations ? violations.length : 0,
346
+ timestamp: Date.now(),
347
+ checksum: this._hashContent(content || ''),
348
+ };
349
+ }
350
+
351
+ /**
352
+ * Determine appropriate action based on violations
353
+ * @private
354
+ */
355
+ _determineAction(violations, content, context) {
356
+ if (violations.length === 0) {
357
+ return this._createResult(MODERATION_ACTIONS.ALLOW, [], content);
358
+ }
359
+
360
+ // Find highest severity
361
+ const severityOrder = [
362
+ SEVERITY_LEVELS.CRITICAL,
363
+ SEVERITY_LEVELS.HIGH,
364
+ SEVERITY_LEVELS.MEDIUM,
365
+ SEVERITY_LEVELS.LOW,
366
+ ];
367
+
368
+ let highestSeverity = SEVERITY_LEVELS.LOW;
369
+ for (const violation of violations) {
370
+ const currentIndex = severityOrder.indexOf(violation.severity);
371
+ const highestIndex = severityOrder.indexOf(highestSeverity);
372
+ if (currentIndex < highestIndex) {
373
+ highestSeverity = violation.severity;
374
+ }
375
+ }
376
+
377
+ // Determine action based on severity
378
+ let action;
379
+ if (highestSeverity === SEVERITY_LEVELS.CRITICAL ||
380
+ highestSeverity === SEVERITY_LEVELS.HIGH) {
381
+ action = MODERATION_ACTIONS.BLOCK;
382
+ } else if (highestSeverity === SEVERITY_LEVELS.MEDIUM) {
383
+ action = MODERATION_ACTIONS.FLAG;
384
+ } else {
385
+ action = MODERATION_ACTIONS.WARN;
386
+ }
387
+
388
+ return {
389
+ action,
390
+ allowed: action !== MODERATION_ACTIONS.BLOCK,
391
+ violations,
392
+ violationCount: violations.length,
393
+ highestSeverity,
394
+ timestamp: Date.now(),
395
+ checksum: this._hashContent(content),
396
+ };
397
+ }
398
+
399
+ /**
400
+ * Hash content for logging without storing actual content
401
+ * @private
402
+ */
403
+ _hashContent(content) {
404
+ return createHash('sha256')
405
+ .update(content.substring(0, 1000))
406
+ .digest('hex')
407
+ .substring(0, 16);
408
+ }
409
+
410
+ /**
411
+ * Check and enforce rate limits
412
+ * @private
413
+ */
414
+ _checkRateLimit() {
415
+ const now = Date.now();
416
+ if (now - this.lastCheckReset > 60000) {
417
+ this.checkCount = 0;
418
+ this.lastCheckReset = now;
419
+ }
420
+
421
+ this.checkCount++;
422
+ if (this.checkCount > this.config.maxChecksPerMinute) {
423
+ throw new Error('Rate limit exceeded for moderation checks');
424
+ }
425
+ }
426
+
427
+ /**
428
+ * Add a custom pattern (host sovereignty feature)
429
+ * @param {Object} pattern - Custom pattern definition
430
+ */
431
+ addCustomPattern(pattern) {
432
+ if (!pattern.pattern || !pattern.severity || !pattern.id) {
433
+ throw new Error('Custom pattern requires pattern, severity, and id');
434
+ }
435
+
436
+ this.config.customPatterns.push(pattern);
437
+ this._buildPatternIndex();
438
+
439
+ this.emit('patternAdded', { pattern });
440
+ }
441
+
442
+ /**
443
+ * Get current moderation configuration
444
+ * @returns {Object} Current configuration (sanitized)
445
+ */
446
+ getConfiguration() {
447
+ return {
448
+ enabledCategories: this.config.enabledCategories,
449
+ blockThreshold: this.config.blockThreshold,
450
+ flagThreshold: this.config.flagThreshold,
451
+ customPatternCount: this.config.customPatterns.length,
452
+ totalPatterns: this.patternIndex.size,
453
+ };
454
+ }
455
+
456
+ /**
457
+ * Get human-readable category descriptions
458
+ * @returns {Object} Category documentation
459
+ */
460
+ static getCategoryDocumentation() {
461
+ const docs = {};
462
+ for (const [key, category] of Object.entries(PROHIBITED_CATEGORIES)) {
463
+ docs[key] = {
464
+ id: category.id,
465
+ severity: category.severity,
466
+ description: category.description,
467
+ // Don't expose actual patterns publicly
468
+ };
469
+ }
470
+ return docs;
471
+ }
472
+ }
473
+
474
+ // ============================================================
475
+ // INTEGRATION HELPERS
476
+ // ============================================================
477
+
478
+ /**
479
+ * Create a moderation middleware for adapters
480
+ * @param {DharmaModerator} moderator - Moderator instance
481
+ * @returns {Function} Middleware function
482
+ */
483
+ export function createModerationMiddleware(moderator) {
484
+ return async (content, context, next) => {
485
+ const result = await moderator.checkContent(content, context);
486
+
487
+ if (!result.allowed) {
488
+ return {
489
+ blocked: true,
490
+ reason: 'Content violates community standards',
491
+ violations: result.violations.map(v => ({
492
+ category: v.categoryId,
493
+ severity: v.severity,
494
+ })),
495
+ };
496
+ }
497
+
498
+ // Attach moderation result to context
499
+ context.moderationResult = result;
500
+
501
+ return next ? next(content, context) : { allowed: true };
502
+ };
503
+ }
504
+
505
+ /**
506
+ * Create a default moderator instance
507
+ * @returns {DharmaModerator} Default moderator
508
+ */
509
+ export function createDefaultModerator() {
510
+ return new DharmaModerator();
511
+ }
512
+
513
+ // ============================================================
514
+ // EXPORTED CONSTANTS
515
+ // ============================================================
516
+
517
+ export default DharmaModerator;