enigma-memory 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.
Files changed (105) hide show
  1. package/LICENSE +55 -0
  2. package/README.md +379 -0
  3. package/apps/cli/bin/enigma.mjs +1117 -0
  4. package/apps/desktop/src/app.js +1327 -0
  5. package/apps/desktop/src/index.html +1373 -0
  6. package/apps/desktop/src/styles.css +386 -0
  7. package/apps/gateway/bin/enigma-gateway.mjs +52 -0
  8. package/apps/gateway/src/server.mjs +1403 -0
  9. package/apps/native-host/README.md +265 -0
  10. package/apps/native-host/bin/enigma-native-host.mjs +499 -0
  11. package/apps/native-host/manifests/com.enigma.native_host.chrome.json +9 -0
  12. package/apps/native-host/manifests/com.enigma.native_host.edge.json +9 -0
  13. package/apps/native-host/manifests/com.enigma.native_host.firefox.json +9 -0
  14. package/apps/relay/bin/enigma-relay.mjs +52 -0
  15. package/apps/relay/src/server.mjs +1571 -0
  16. package/apps/verifier/bin/enigma-verify.mjs +240 -0
  17. package/deploy/docker-compose.production.example.yml +150 -0
  18. package/deploy/kubernetes/enigma-backend.example.yaml +580 -0
  19. package/package.json +196 -0
  20. package/packages/adapters/PACKAGE_CONTRACT.md +47 -0
  21. package/packages/adapters/src/index.js +183 -0
  22. package/packages/boundary/src/index.js +468 -0
  23. package/packages/connectors/src/index.js +533 -0
  24. package/packages/core/src/index.js +766 -0
  25. package/packages/enterprise/src/index.js +505 -0
  26. package/packages/importers/src/index.js +1083 -0
  27. package/packages/mcp-server/bin/enigma-mcp.mjs +19 -0
  28. package/packages/mcp-server/src/index.js +1185 -0
  29. package/packages/mesh/src/index.js +531 -0
  30. package/packages/metering/PACKAGE_CONTRACT.md +20 -0
  31. package/packages/metering/src/index.js +246 -0
  32. package/packages/optimizer/src/index.js +707 -0
  33. package/packages/passport/src/index.js +651 -0
  34. package/packages/settlement/PACKAGE_CONTRACT.md +28 -0
  35. package/packages/settlement/src/index.js +369 -0
  36. package/packages/storage/PACKAGE_CONTRACT.md +23 -0
  37. package/packages/storage/src/index.js +392 -0
  38. package/packages/vault/src/index.js +904 -0
  39. package/scripts/build-ai-orchestration-plan.mjs +248 -0
  40. package/scripts/build-cloudflare-pages-release-packet.mjs +287 -0
  41. package/scripts/build-cloudflare-token-policy.mjs +239 -0
  42. package/scripts/build-cloudflare-token-request.mjs +314 -0
  43. package/scripts/build-demo-assets.mjs +263 -0
  44. package/scripts/build-edge-backend-workers.mjs +353 -0
  45. package/scripts/build-goal-completion-audit.mjs +398 -0
  46. package/scripts/build-hosted-probe-worker.mjs +191 -0
  47. package/scripts/build-operator-acceptance-packet.mjs +254 -0
  48. package/scripts/build-operator-evidence-starter.mjs +525 -0
  49. package/scripts/build-production-backend-env-kit.mjs +384 -0
  50. package/scripts/build-production-dependency-report.mjs +369 -0
  51. package/scripts/build-production-handoff-packet.mjs +475 -0
  52. package/scripts/build-production-readiness-manifest.mjs +209 -0
  53. package/scripts/build-production-status-board.mjs +297 -0
  54. package/scripts/build-production-storage-migration.mjs +86 -0
  55. package/scripts/build-production-workplan.mjs +371 -0
  56. package/scripts/build-review-packet.mjs +594 -0
  57. package/scripts/check.mjs +419 -0
  58. package/scripts/cloudflare-ops.mjs +1672 -0
  59. package/scripts/cloudflare-secret-env.mjs +128 -0
  60. package/scripts/collect-hosted-backend-live-evidence.mjs +263 -0
  61. package/scripts/infrastructure-readiness.mjs +944 -0
  62. package/scripts/install-enigma-local.mjs +270 -0
  63. package/scripts/memory-optimization-benchmark.mjs +242 -0
  64. package/scripts/monitor-live-endpoints.mjs +358 -0
  65. package/scripts/release-audit.mjs +5588 -0
  66. package/scripts/release-provenance.mjs +250 -0
  67. package/scripts/run-backend-readiness-smoke.mjs +220 -0
  68. package/scripts/validate-backup-restore-drill.mjs +166 -0
  69. package/scripts/validate-cloudflare-credentials.mjs +112 -0
  70. package/scripts/validate-cloudflare-worker-inspect.mjs +179 -0
  71. package/scripts/validate-domain-tls.mjs +248 -0
  72. package/scripts/validate-hosted-backend-live.mjs +319 -0
  73. package/scripts/validate-incident-drill.mjs +221 -0
  74. package/scripts/validate-kms-custody.mjs +235 -0
  75. package/scripts/validate-legal-compliance-approval.mjs +274 -0
  76. package/scripts/validate-monitoring-alerting.mjs +263 -0
  77. package/scripts/validate-network-access-policy.mjs +285 -0
  78. package/scripts/validate-operator-acceptance.mjs +298 -0
  79. package/scripts/validate-production-manifests.mjs +325 -0
  80. package/scripts/validate-public-site-security.mjs +252 -0
  81. package/scripts/validate-security-threat-model.mjs +285 -0
  82. package/scripts/validate-service-settlement.mjs +256 -0
  83. package/scripts/validate-support-sla.mjs +190 -0
  84. package/scripts/validate-tenant-policy-approval.mjs +228 -0
  85. package/scripts/validate-usage-metering.mjs +224 -0
  86. package/scripts/validate-whitepaper-claims.mjs +166 -0
  87. package/specs/boundary-manifest-v1.schema.json +35 -0
  88. package/specs/capsule-v1.schema.json +55 -0
  89. package/specs/claim-boundary-manifest-v1.schema.json +22 -0
  90. package/specs/connector-profile-v1.schema.json +62 -0
  91. package/specs/deletion-tombstone-v1.schema.json +26 -0
  92. package/specs/enterprise-policy-v1.schema.json +59 -0
  93. package/specs/gateway-request-v1.schema.json +32 -0
  94. package/specs/goal-completion-audit-v1.schema.json +70 -0
  95. package/specs/hosted-backend-live-evidence-v1.schema.json +147 -0
  96. package/specs/import-report-v1.schema.json +214 -0
  97. package/specs/infrastructure-readiness-manifest-v1.schema.json +130 -0
  98. package/specs/memory-event-v1.schema.json +42 -0
  99. package/specs/mesh-node-v1.schema.json +126 -0
  100. package/specs/passport-v1.schema.json +50 -0
  101. package/specs/production-handoff-packet-v1.schema.json +149 -0
  102. package/specs/receipt-v1.schema.json +61 -0
  103. package/specs/relay-record-v1.schema.json +43 -0
  104. package/specs/state-checkpoint-v1.schema.json +37 -0
  105. package/specs/trust-bundle-v1.schema.json +56 -0
@@ -0,0 +1,531 @@
1
+ import {
2
+ EMPTY_MERKLE_ROOT,
3
+ MerkleSet,
4
+ canonicalize,
5
+ generateSigningKeyPair,
6
+ sha256Hex,
7
+ signPayload,
8
+ verifySignature
9
+ } from '../../core/src/index.js';
10
+
11
+ const ED25519 = 'Ed25519';
12
+ const NODE_SCHEMA = 'enigma.mesh_node.v1';
13
+ const CAPSULE_SCHEMA = 'enigma.capsule_manifest.v1';
14
+ const WITNESS_SCHEMA = 'enigma.witness_checkpoint.v1';
15
+ const RELAY_RECORD_SCHEMA = 'enigma.relay_record.v1';
16
+ const FEDERATION_GRANT_SCHEMA = 'enigma.federation_grant.v1';
17
+ const DEFAULT_NOW = '1970-01-01T00:00:00.000Z';
18
+ const DEFAULT_EXPIRY = '2100-01-01T00:00:00.000Z';
19
+ const ROOT_RE = /^sha256:[a-f0-9]{64}$/;
20
+ const HASH_RE = /^[a-f0-9]{64}$/;
21
+ const FORBIDDEN_PLAINTEXT_KEYS = new Set([
22
+ 'plaintext',
23
+ 'plaintextmemory',
24
+ 'plainmemory',
25
+ 'cleartext',
26
+ 'rawmemory',
27
+ 'memoryplaintext',
28
+ 'memory',
29
+ 'memories',
30
+ 'text',
31
+ 'content',
32
+ 'body',
33
+ 'prompt',
34
+ 'prompttext',
35
+ 'completion',
36
+ 'message',
37
+ 'messagetext',
38
+ 'conversation',
39
+ 'conversationtext',
40
+ 'transcript',
41
+ 'transcripttext'
42
+ ]);
43
+ const RELAY_INPUT_KEYS = new Set([
44
+ 'record_id',
45
+ 'recordId',
46
+ 'capsule_id',
47
+ 'capsuleId',
48
+ 'encrypted_payload_hash',
49
+ 'encryptedPayloadHash',
50
+ 'payload_hash',
51
+ 'payloadHash',
52
+ 'opaque_encrypted_record',
53
+ 'opaqueEncryptedRecord',
54
+ 'encrypted_payload',
55
+ 'encryptedPayload',
56
+ 'ciphertext',
57
+ 'received_at',
58
+ 'receivedAt',
59
+ 'expires_at',
60
+ 'expiresAt'
61
+ ]);
62
+
63
+ function isPlainRecord(value) {
64
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
65
+ }
66
+
67
+ function requiredString(value, field) {
68
+ if (typeof value !== 'string' || value.length === 0) throw new TypeError(`${field} is required`);
69
+ return value;
70
+ }
71
+
72
+ function normalizeKeyName(key) {
73
+ return String(key).toLowerCase().replace(/[^a-z0-9]/g, '');
74
+ }
75
+
76
+ const ENCRYPTED_PAYLOAD_RE = /^(age1|enc:|encrypted:|ciphertext:|jwe:|xchacha20poly1305:|aes256gcm:|sealed:)[A-Za-z0-9+/_=:.~-]+$/i;
77
+ const COMMITMENT_RE = /^(sha256:[a-f0-9]{64}|hmac-sha256:[a-f0-9]{64}|commitment:sha256:[a-f0-9]{64})$/i;
78
+
79
+ function isForbiddenPlaintextKey(key) {
80
+ return FORBIDDEN_PLAINTEXT_KEYS.has(normalizeKeyName(key));
81
+ }
82
+
83
+ function assertEncryptedEnvelopeOrCommitment(value, field) {
84
+ if (typeof value !== 'string' || value.length === 0) throw new TypeError(`${field} must be an encrypted envelope or commitment`);
85
+ if (!ENCRYPTED_PAYLOAD_RE.test(value) && !COMMITMENT_RE.test(value)) {
86
+ throw new Error(`${field} must be an explicit encrypted envelope or commitment`);
87
+ }
88
+ }
89
+
90
+ function hasPlaintextLeak(value, seen = new WeakSet()) {
91
+ if (value === null || typeof value !== 'object') return false;
92
+ if (seen.has(value)) return false;
93
+ seen.add(value);
94
+ if (Array.isArray(value)) return value.some((item) => hasPlaintextLeak(item, seen));
95
+ for (const [key, nested] of Object.entries(value)) {
96
+ if (isForbiddenPlaintextKey(key) && nested !== undefined && nested !== null && nested !== '') return true;
97
+ if (hasPlaintextLeak(nested, seen)) return true;
98
+ }
99
+ return false;
100
+ }
101
+
102
+ function assertNoPlaintext(value, context) {
103
+ if (hasPlaintextLeak(value)) throw new Error(`${context} contains plaintext memory fields`);
104
+ }
105
+
106
+ function assertOnlyRelayFields(record) {
107
+ for (const key of Object.keys(record)) {
108
+ if (!RELAY_INPUT_KEYS.has(key)) throw new Error(`relay record field ${key} is not opaque encrypted metadata`);
109
+ }
110
+ }
111
+
112
+ function rootFromValue(value) {
113
+ return `sha256:${sha256Hex(typeof value === 'string' ? value : canonicalize(value))}`;
114
+ }
115
+
116
+ function normalizeRoot(value, field, fallback = EMPTY_MERKLE_ROOT) {
117
+ if (value === undefined || value === null) return fallback;
118
+ if (typeof value !== 'string') throw new TypeError(`${field} must be a sha256 root`);
119
+ if (ROOT_RE.test(value)) return value;
120
+ if (HASH_RE.test(value)) return `sha256:${value}`;
121
+ throw new TypeError(`${field} must be a sha256 root`);
122
+ }
123
+
124
+ function compareExpectedRoot(actual, expected, field, errors, message) {
125
+ if (expected === undefined) return;
126
+ try {
127
+ if (actual !== normalizeRoot(expected, field)) errors.push(message);
128
+ } catch {
129
+ errors.push(`${field} must be a sha256 root`);
130
+ }
131
+ }
132
+
133
+ function normalizeHashableRoot(options, names, field) {
134
+ for (const name of names) {
135
+ if (options[name] !== undefined) return normalizeRoot(options[name], field);
136
+ }
137
+ return undefined;
138
+ }
139
+
140
+ function normalizeEncryptedPayloadHash(options) {
141
+ const encrypted = options.encrypted_payload ?? options.encryptedPayload ?? options.opaque_encrypted_record ?? options.opaqueEncryptedRecord ?? options.ciphertext;
142
+ if (encrypted !== undefined) assertEncryptedEnvelopeOrCommitment(encrypted, 'encrypted_payload');
143
+ const explicit = normalizeHashableRoot(options, ['encrypted_payload_hash', 'encryptedPayloadHash', 'payload_hash', 'payloadHash'], 'encrypted_payload_hash');
144
+ if (explicit !== undefined) return explicit;
145
+ if (encrypted === undefined) throw new TypeError('encrypted_payload_hash is required');
146
+ return rootFromValue(encrypted);
147
+ }
148
+
149
+ function arrayOfStrings(value, field, fallback = []) {
150
+ if (value === undefined) return fallback;
151
+ if (!Array.isArray(value) || value.some((item) => typeof item !== 'string' || item.length === 0)) {
152
+ throw new TypeError(`${field} must be an array of strings`);
153
+ }
154
+ return [...value];
155
+ }
156
+
157
+ function dateString(value, field, fallback) {
158
+ const string = requiredString(value ?? fallback, field);
159
+ if (Number.isNaN(Date.parse(string))) throw new TypeError(`${field} must be an ISO date string`);
160
+ return string;
161
+ }
162
+
163
+ function signaturePayload(record) {
164
+ const { signature, descriptor_hash, capsule_hash, witness_hash, grant_hash, ...unsigned } = record;
165
+ return unsigned;
166
+ }
167
+
168
+ function signerFrom(options, fallbackNode) {
169
+ const node = options.node ?? fallbackNode;
170
+ if (node?.privateKey) {
171
+ return {
172
+ key_id: node.signer?.key_id ?? node.trust_descriptor?.key?.key_id,
173
+ privateKey: node.privateKey,
174
+ publicKey: node.publicKey ?? node.trust_descriptor?.key?.public_key,
175
+ node_id: node.node_id
176
+ };
177
+ }
178
+ return {
179
+ key_id: options.key_id ?? options.keyId ?? options.signer?.key_id,
180
+ privateKey: options.privateKey,
181
+ publicKey: options.publicKey,
182
+ node_id: options.node_id ?? options.nodeId
183
+ };
184
+ }
185
+
186
+ function createSignature(unsigned, signer) {
187
+ if (signer.privateKey === undefined) throw new TypeError('privateKey is required');
188
+ const key_id = requiredString(signer.key_id, 'signer.key_id');
189
+ return { alg: ED25519, key_id, value: signPayload({ payload: unsigned, privateKey: signer.privateKey }) };
190
+ }
191
+
192
+ function resolvePublicKey(keyId, options = {}) {
193
+ if (options.publicKey !== undefined) return options.publicKey;
194
+ const node = options.node;
195
+ if (node?.signer?.key_id === keyId && node.publicKey !== undefined) return node.publicKey;
196
+ const descriptor = options.trustDescriptor ?? options.issuerDescriptor ?? options.witnessDescriptor ?? options.descriptor;
197
+ if (descriptor?.key?.key_id === keyId) return descriptor.key.public_key;
198
+ const publicKeys = options.publicKeys ?? options.keyring ?? options.keys;
199
+ if (publicKeys instanceof Map) return publicKeys.get(keyId);
200
+ if (typeof publicKeys === 'function') return publicKeys(keyId);
201
+ if (isPlainRecord(publicKeys)) return publicKeys[keyId];
202
+ return undefined;
203
+ }
204
+
205
+ function verifySignedRecord(record, options, errors) {
206
+ if (!isPlainRecord(record.signature)) {
207
+ errors.push('signature missing');
208
+ return;
209
+ }
210
+ if (record.signature.alg !== ED25519 || typeof record.signature.key_id !== 'string' || typeof record.signature.value !== 'string') {
211
+ errors.push('signature malformed');
212
+ return;
213
+ }
214
+ const expectedKeyId = options.expectedKeyId ?? options.signerKeyId ?? options.key_id ?? options.keyId;
215
+ if (expectedKeyId !== undefined && record.signature.key_id !== expectedKeyId) errors.push('signer mismatch');
216
+ const publicKey = resolvePublicKey(record.signature.key_id, options);
217
+ if (publicKey === undefined) {
218
+ errors.push(`missing public key for ${record.signature.key_id}`);
219
+ return;
220
+ }
221
+ if (!verifySignature({ payload: signaturePayload(record), signature: record.signature, publicKey })) errors.push('signature mismatch');
222
+ }
223
+
224
+ function verificationResult(errors, extra = {}) {
225
+ const ok = errors.length === 0;
226
+ return { ok, valid: ok, errors, ...extra };
227
+ }
228
+
229
+
230
+ function createSignedDescriptor({ keyPair, node_id, role, capabilities, trust_roots, endpoints, created_at }) {
231
+ const unsigned = {
232
+ schema: NODE_SCHEMA,
233
+ node_id,
234
+ role,
235
+ key: { alg: ED25519, key_id: keyPair.key_id, public_key: keyPair.publicKey },
236
+ public_key: keyPair.publicKey,
237
+ capabilities,
238
+ trust_roots,
239
+ endpoints,
240
+ created_at
241
+ };
242
+ const signature = createSignature(unsigned, { key_id: keyPair.key_id, privateKey: keyPair.privateKey });
243
+ const signed = { ...unsigned, signature };
244
+ return { ...signed, descriptor_hash: rootFromValue(signed) };
245
+ }
246
+
247
+ export function createMeshNode(options = {}) {
248
+ const keyPair = options.keyPair ?? options.signingKeyPair ?? generateSigningKeyPair(options.keyOptions ?? {});
249
+ const node_id = options.node_id ?? options.nodeId ?? `node_${sha256Hex(keyPair.publicKey).slice(0, 32)}`;
250
+ const created_at = dateString(options.created_at ?? options.createdAt, 'created_at', DEFAULT_NOW);
251
+ const capabilities = arrayOfStrings(options.capabilities, 'capabilities', ['capsule_manifest', 'witness_checkpoint', 'relay_store', 'federation_grant']);
252
+ const trust_roots = arrayOfStrings(options.trust_roots ?? options.trustRoots, 'trust_roots', []);
253
+ const endpoints = arrayOfStrings(options.endpoints, 'endpoints', []);
254
+ const role = options.role ?? 'mesh_node';
255
+ const trust_descriptor = createSignedDescriptor({ keyPair, node_id, role, capabilities, trust_roots, endpoints, created_at });
256
+ return {
257
+ schema: NODE_SCHEMA,
258
+ node_id,
259
+ signer: { alg: ED25519, key_id: keyPair.key_id },
260
+ publicKey: keyPair.publicKey,
261
+ privateKey: keyPair.privateKey,
262
+ trust_descriptor,
263
+ public_descriptor: trust_descriptor
264
+ };
265
+ }
266
+
267
+ export function createCapsuleManifest(options = {}) {
268
+ assertNoPlaintext(options, 'capsule manifest');
269
+ const signer = signerFrom(options);
270
+ const issuer = requiredString(options.issuer ?? signer.node_id, 'issuer');
271
+ const holder = requiredString(options.holder ?? options.holder_id ?? options.holderId, 'holder');
272
+ const ownerScope = options.owner_scope_hash ?? options.ownerScopeHash ?? rootFromValue(options.owner_scope ?? options.ownerScope ?? holder);
273
+ const encrypted_payload_hash = normalizeEncryptedPayloadHash(options);
274
+ const unsigned = {
275
+ schema: CAPSULE_SCHEMA,
276
+ capsule_id: options.capsule_id ?? options.capsuleId ?? `cap_${sha256Hex(canonicalize({ issuer, holder, ownerScope, encrypted_payload_hash })).slice(0, 32)}`,
277
+ encrypted_payload_hash,
278
+ receipt_log_root: normalizeRoot(options.receipt_log_root ?? options.receiptLogRoot, 'receipt_log_root'),
279
+ active_set_root: normalizeRoot(options.active_set_root ?? options.activeSetRoot ?? options.active_memory_root ?? options.activeMemoryRoot, 'active_set_root'),
280
+ owner_scope_hash: normalizeRoot(ownerScope, 'owner_scope_hash'),
281
+ issuer,
282
+ holder,
283
+ issued_at: dateString(options.issued_at ?? options.issuedAt, 'issued_at', DEFAULT_NOW),
284
+ expires_at: dateString(options.expires_at ?? options.expiresAt, 'expires_at', DEFAULT_EXPIRY)
285
+ };
286
+ const manifest = { ...unsigned, signature: createSignature(unsigned, signer) };
287
+ return { ...manifest, capsule_hash: rootFromValue(manifest) };
288
+ }
289
+
290
+ export function verifyCapsuleManifest(manifest, options = {}) {
291
+ const errors = [];
292
+ if (!isPlainRecord(manifest)) return verificationResult(['capsule manifest must be an object']);
293
+ if (hasPlaintextLeak(manifest)) errors.push('plaintext memory fields present');
294
+ if (manifest.schema !== CAPSULE_SCHEMA) errors.push('schema mismatch');
295
+ for (const field of ['encrypted_payload_hash', 'receipt_log_root', 'active_set_root', 'owner_scope_hash']) {
296
+ if (!ROOT_RE.test(manifest[field] ?? '')) errors.push(`${field} must be a sha256 root`);
297
+ }
298
+ for (const field of ['capsule_id', 'issuer', 'holder', 'issued_at', 'expires_at']) {
299
+ if (typeof manifest[field] !== 'string' || manifest[field].length === 0) errors.push(`${field} is required`);
300
+ }
301
+ compareExpectedRoot(manifest.receipt_log_root, options.expectedReceiptLogRoot, 'expectedReceiptLogRoot', errors, 'receipt log root mismatch');
302
+ compareExpectedRoot(manifest.active_set_root, options.expectedActiveSetRoot, 'expectedActiveSetRoot', errors, 'active set root mismatch');
303
+ compareExpectedRoot(manifest.owner_scope_hash, options.expectedOwnerScopeHash, 'expectedOwnerScopeHash', errors, 'owner scope mismatch');
304
+ if (options.expectedIssuer !== undefined && manifest.issuer !== options.expectedIssuer) errors.push('issuer mismatch');
305
+ if (options.expectedHolder !== undefined && manifest.holder !== options.expectedHolder) errors.push('holder mismatch');
306
+ const now = options.now === undefined ? undefined : Date.parse(options.now);
307
+ if (now !== undefined && Number.isFinite(now) && Date.parse(manifest.expires_at) <= now) errors.push('capsule expired');
308
+ verifySignedRecord(manifest, options, errors);
309
+ return verificationResult(errors, { capsule_hash: rootFromValue(manifest) });
310
+ }
311
+
312
+ export function createWitnessCheckpoint(options = {}) {
313
+ assertNoPlaintext(options, 'witness checkpoint');
314
+ const signer = signerFrom(options);
315
+ const witness_node_id = requiredString(options.witness_node_id ?? options.witnessNodeId ?? signer.node_id, 'witness_node_id');
316
+ const subject_node_id = requiredString(options.subject_node_id ?? options.subjectNodeId ?? options.subject ?? 'subject', 'subject_node_id');
317
+ const receipt_log_root = normalizeRoot(options.receipt_log_root ?? options.receiptLogRoot, 'receipt_log_root');
318
+ const active_set_root = normalizeRoot(options.active_set_root ?? options.activeSetRoot ?? options.active_memory_root ?? options.activeMemoryRoot, 'active_set_root');
319
+ const epoch = options.epoch === undefined ? 0 : options.epoch;
320
+ if (!Number.isInteger(epoch) || epoch < 0) throw new TypeError('epoch must be a non-negative integer');
321
+ const previous_witness_hash = normalizeRoot(options.previous_witness_hash ?? options.previousWitnessHash ?? EMPTY_MERKLE_ROOT, 'previous_witness_hash');
322
+ const computed_checkpoint_root = rootFromValue({ subject_node_id, receipt_log_root, active_set_root, epoch, previous_witness_hash });
323
+ const suppliedCheckpointRoot = options.checkpoint_root ?? options.checkpointRoot;
324
+ const checkpoint_root = suppliedCheckpointRoot === undefined
325
+ ? computed_checkpoint_root
326
+ : normalizeRoot(suppliedCheckpointRoot, 'checkpoint_root');
327
+ if (checkpoint_root !== computed_checkpoint_root) throw new Error('checkpoint_root does not match checkpoint contents');
328
+ const unsigned = {
329
+ schema: WITNESS_SCHEMA,
330
+ witness_checkpoint_id: options.witness_checkpoint_id ?? options.witnessCheckpointId ?? `wit_${sha256Hex(canonicalize({ witness_node_id, subject_node_id, checkpoint_root })).slice(0, 32)}`,
331
+ witness_node_id,
332
+ subject_node_id,
333
+ epoch,
334
+ checkpoint_root,
335
+ receipt_log_root,
336
+ active_set_root,
337
+ previous_witness_hash,
338
+ issued_at: dateString(options.issued_at ?? options.issuedAt, 'issued_at', DEFAULT_NOW)
339
+ };
340
+ const checkpoint = { ...unsigned, signature: createSignature(unsigned, signer) };
341
+ return { ...checkpoint, witness_hash: rootFromValue(checkpoint) };
342
+ }
343
+
344
+ export function verifyWitnessCheckpoint(checkpoint, options = {}) {
345
+ const errors = [];
346
+ if (!isPlainRecord(checkpoint)) return verificationResult(['witness checkpoint must be an object']);
347
+ if (hasPlaintextLeak(checkpoint)) errors.push('plaintext memory fields present');
348
+ if (checkpoint.schema !== WITNESS_SCHEMA) errors.push('schema mismatch');
349
+ for (const field of ['checkpoint_root', 'receipt_log_root', 'active_set_root', 'previous_witness_hash']) {
350
+ if (!ROOT_RE.test(checkpoint[field] ?? '')) errors.push(`${field} must be a sha256 root`);
351
+ }
352
+ if (!Number.isInteger(checkpoint.epoch) || checkpoint.epoch < 0) errors.push('epoch must be a non-negative integer');
353
+ const computedCheckpointRoot = rootFromValue({
354
+ subject_node_id: checkpoint.subject_node_id,
355
+ receipt_log_root: checkpoint.receipt_log_root,
356
+ active_set_root: checkpoint.active_set_root,
357
+ epoch: checkpoint.epoch,
358
+ previous_witness_hash: checkpoint.previous_witness_hash
359
+ });
360
+ if (checkpoint.checkpoint_root !== computedCheckpointRoot) errors.push('checkpoint root mismatch');
361
+ compareExpectedRoot(checkpoint.checkpoint_root, options.expectedCheckpointRoot, 'expectedCheckpointRoot', errors, 'checkpoint root mismatch');
362
+ compareExpectedRoot(checkpoint.receipt_log_root, options.expectedReceiptLogRoot, 'expectedReceiptLogRoot', errors, 'receipt log root mismatch');
363
+ compareExpectedRoot(checkpoint.active_set_root, options.expectedActiveSetRoot, 'expectedActiveSetRoot', errors, 'active set root mismatch');
364
+ compareExpectedRoot(checkpoint.previous_witness_hash, options.expectedPreviousWitnessHash, 'expectedPreviousWitnessHash', errors, 'previous witness hash mismatch');
365
+ if (options.minimumEpoch !== undefined && (!Number.isInteger(options.minimumEpoch) || checkpoint.epoch < options.minimumEpoch)) errors.push('epoch continuity mismatch');
366
+ if (options.expectedWitnessNodeId !== undefined && checkpoint.witness_node_id !== options.expectedWitnessNodeId) errors.push('witness node mismatch');
367
+ verifySignedRecord(checkpoint, options, errors);
368
+ return verificationResult(errors, { witness_hash: rootFromValue(checkpoint) });
369
+ }
370
+
371
+ export function createRelayStore(options = {}) {
372
+ const node = options.node;
373
+ return {
374
+ schema: 'enigma.relay_store.v1',
375
+ store_id: options.store_id ?? options.storeId ?? `relay_${sha256Hex(canonicalize({ node_id: node?.node_id ?? 'local', created_at: options.created_at ?? DEFAULT_NOW })).slice(0, 32)}`,
376
+ node_id: options.node_id ?? options.nodeId ?? node?.node_id ?? 'local',
377
+ created_at: dateString(options.created_at ?? options.createdAt, 'created_at', DEFAULT_NOW),
378
+ records: new Map(),
379
+ node
380
+ };
381
+ }
382
+
383
+ export function pushRelayRecord(store, record = {}) {
384
+ if (!isPlainRecord(store) || !(store.records instanceof Map)) throw new TypeError('relay store is required');
385
+ if (!isPlainRecord(record)) throw new TypeError('relay record must be an object');
386
+ assertNoPlaintext(record, 'relay record');
387
+ assertOnlyRelayFields(record);
388
+ const encrypted_payload_hash = normalizeEncryptedPayloadHash(record);
389
+ const unsigned = {
390
+ schema: RELAY_RECORD_SCHEMA,
391
+ record_id: record.record_id ?? record.recordId ?? `rel_${sha256Hex(canonicalize({ store_id: store.store_id, encrypted_payload_hash })).slice(0, 32)}`,
392
+ store_id: store.store_id,
393
+ capsule_id: record.capsule_id ?? record.capsuleId ?? null,
394
+ encrypted_payload_hash,
395
+ payload_storage: 'hash_only',
396
+ received_at: dateString(record.received_at ?? record.receivedAt, 'received_at', DEFAULT_NOW),
397
+ expires_at: record.expires_at ?? record.expiresAt ? dateString(record.expires_at ?? record.expiresAt, 'expires_at') : null
398
+ };
399
+ const signer = store.node?.privateKey ? signerFrom({}, store.node) : null;
400
+ const relayRecord = signer ? { ...unsigned, signature: createSignature(unsigned, signer) } : unsigned;
401
+ store.records.set(relayRecord.record_id, Object.freeze({ ...relayRecord }));
402
+ return { ...relayRecord, relay_record_id: relayRecord.record_id };
403
+ }
404
+
405
+ export function pullRelayRecord(store, recordRef) {
406
+ if (!isPlainRecord(store) || !(store.records instanceof Map)) throw new TypeError('relay store is required');
407
+ const record_id = typeof recordRef === 'string' ? recordRef : recordRef?.record_id ?? recordRef?.recordId ?? recordRef?.relay_record_id;
408
+ if (typeof record_id !== 'string' || record_id.length === 0) throw new TypeError('record_id is required');
409
+ const record = store.records.get(record_id) ?? null;
410
+ if (record !== null && hasPlaintextLeak(record)) throw new Error('stored relay record contains plaintext memory fields');
411
+ return record === null ? null : { ...record, relay_record_id: record.record_id };
412
+ }
413
+
414
+ export function createFederationGrant(options = {}) {
415
+ assertNoPlaintext(options, 'federation grant');
416
+ const signer = signerFrom(options);
417
+ const subjects = arrayOfStrings(options.subjects ?? options.subject_ids ?? options.subjectIds, 'subjects');
418
+ const operations = arrayOfStrings(options.operations, 'operations');
419
+ const issuer = requiredString(options.issuer ?? signer.node_id, 'issuer');
420
+ const holder = requiredString(options.holder ?? options.holder_id ?? options.holderId, 'holder');
421
+ const unsigned = {
422
+ schema: FEDERATION_GRANT_SCHEMA,
423
+ grant_id: options.grant_id ?? options.grantId ?? `fgr_${sha256Hex(canonicalize({ issuer, holder, subjects, operations, purpose: options.purpose })).slice(0, 32)}`,
424
+ issuer,
425
+ holder,
426
+ subjects: [...subjects].sort(),
427
+ operations: [...operations].sort(),
428
+ purpose: requiredString(options.purpose, 'purpose'),
429
+ issued_at: dateString(options.issued_at ?? options.issuedAt, 'issued_at', DEFAULT_NOW),
430
+ expires_at: dateString(options.expires_at ?? options.expiresAt, 'expires_at', DEFAULT_EXPIRY)
431
+ };
432
+ const grant = { ...unsigned, signature: createSignature(unsigned, signer) };
433
+ return { ...grant, grant_hash: rootFromValue(grant) };
434
+ }
435
+
436
+ export function verifyFederationGrant(grant, options = {}) {
437
+ const errors = [];
438
+ if (!isPlainRecord(grant)) return verificationResult(['federation grant must be an object']);
439
+ if (hasPlaintextLeak(grant)) errors.push('plaintext memory fields present');
440
+ if (grant.schema !== FEDERATION_GRANT_SCHEMA) errors.push('schema mismatch');
441
+ if (!Array.isArray(grant.subjects) || grant.subjects.some((item) => typeof item !== 'string' || item.length === 0)) errors.push('subjects must be strings');
442
+ if (!Array.isArray(grant.operations) || grant.operations.some((item) => typeof item !== 'string' || item.length === 0)) errors.push('operations must be strings');
443
+ for (const field of ['grant_id', 'issuer', 'holder', 'purpose', 'issued_at', 'expires_at']) {
444
+ if (typeof grant[field] !== 'string' || grant[field].length === 0) errors.push(`${field} is required`);
445
+ }
446
+ const expectedSubject = options.expectedSubject ?? options.subject;
447
+ if (expectedSubject !== undefined && !grant.subjects?.includes(expectedSubject)) errors.push('subject not granted');
448
+ const expectedOperation = options.expectedOperation ?? options.operation;
449
+ if (expectedOperation !== undefined && !grant.operations?.includes(expectedOperation)) errors.push('operation not granted');
450
+ if (options.expectedPurpose !== undefined && grant.purpose !== options.expectedPurpose) errors.push('purpose mismatch');
451
+ if (options.expectedIssuer !== undefined && grant.issuer !== options.expectedIssuer) errors.push('issuer mismatch');
452
+ if (options.expectedHolder !== undefined && grant.holder !== options.expectedHolder) errors.push('holder mismatch');
453
+ const now = options.now === undefined ? undefined : Date.parse(options.now);
454
+ if (now !== undefined && Number.isFinite(now) && Date.parse(grant.expires_at) <= now) errors.push('grant expired');
455
+ verifySignedRecord(grant, options, errors);
456
+ return verificationResult(errors, { grant_hash: rootFromValue(grant) });
457
+ }
458
+
459
+ export function runMeshDemo(options = {}) {
460
+ const node = createMeshNode({ created_at: options.now ?? DEFAULT_NOW });
461
+ const holder = options.holder ?? 'holder:demo';
462
+ const activeSet = new MerkleSet(['mem:hmac-sha256:demo-active-address']);
463
+ const receiptLog = new MerkleSet(['sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa']);
464
+ const active_set_root = activeSet.root();
465
+ const receipt_log_root = receiptLog.root();
466
+ const encrypted_payload = 'age1-encrypted-demo-capsule-only';
467
+ const capsule = createCapsuleManifest({ node, issuer: node.node_id, holder, encrypted_payload, receipt_log_root, active_set_root, owner_scope: { holder, scope: 'demo' } });
468
+ const capsuleVerification = verifyCapsuleManifest(capsule, {
469
+ trustDescriptor: node.trust_descriptor,
470
+ expectedIssuer: node.node_id,
471
+ expectedHolder: holder,
472
+ expectedReceiptLogRoot: receipt_log_root,
473
+ expectedActiveSetRoot: active_set_root,
474
+ now: options.now ?? DEFAULT_NOW
475
+ });
476
+ const witness = createWitnessCheckpoint({ node, witness_node_id: node.node_id, subject_node_id: holder, receipt_log_root, active_set_root, epoch: 1 });
477
+ const witnessVerification = verifyWitnessCheckpoint(witness, {
478
+ trustDescriptor: node.trust_descriptor,
479
+ expectedWitnessNodeId: node.node_id,
480
+ expectedReceiptLogRoot: receipt_log_root,
481
+ expectedActiveSetRoot: active_set_root
482
+ });
483
+ const relayStore = createRelayStore({ node, created_at: options.now ?? DEFAULT_NOW });
484
+ const relayRecord = pushRelayRecord(relayStore, { capsule_id: capsule.capsule_id, opaque_encrypted_record: encrypted_payload });
485
+ let rejected_plaintext = false;
486
+ try {
487
+ pushRelayRecord(relayStore, { plaintext: 'demo memory must never cross the mesh', opaque_encrypted_record: encrypted_payload });
488
+ } catch {
489
+ rejected_plaintext = true;
490
+ }
491
+ const grant = createFederationGrant({ node, issuer: node.node_id, holder, subjects: [holder], operations: ['capsule.pull', 'witness.verify'], purpose: 'demo federation', expires_at: DEFAULT_EXPIRY });
492
+ const grantVerification = verifyFederationGrant(grant, {
493
+ trustDescriptor: node.trust_descriptor,
494
+ expectedIssuer: node.node_id,
495
+ expectedHolder: holder,
496
+ expectedSubject: holder,
497
+ expectedOperation: 'capsule.pull',
498
+ expectedPurpose: 'demo federation',
499
+ now: options.now ?? DEFAULT_NOW
500
+ });
501
+ const artifacts = { descriptor: node.trust_descriptor, capsule, witness, relayRecord, grant };
502
+ const no_plaintext_leakage = !hasPlaintextLeak(artifacts);
503
+ const ok = capsuleVerification.ok && witnessVerification.ok && grantVerification.ok && Boolean(relayRecord.record_id) && rejected_plaintext && no_plaintext_leakage;
504
+ return {
505
+ ok,
506
+ node: { node_id: node.node_id, trust_descriptor: node.trust_descriptor },
507
+ capsule: { ok: capsuleVerification.ok, capsule_id: capsule.capsule_id },
508
+ witness: { ok: witnessVerification.ok, witness_checkpoint_id: witness.witness_checkpoint_id },
509
+ relay: { record_id: relayRecord.record_id, rejected_plaintext },
510
+ federation: { ok: grantVerification.ok, grant_id: grant.grant_id },
511
+ capsule_verification_ok: capsuleVerification.ok,
512
+ witness_verification_ok: witnessVerification.ok,
513
+ relay_record_id: relayRecord.record_id,
514
+ federation_grant_verification_ok: grantVerification.ok,
515
+ no_plaintext_leakage
516
+ };
517
+ }
518
+
519
+ export default {
520
+ createMeshNode,
521
+ createCapsuleManifest,
522
+ verifyCapsuleManifest,
523
+ createWitnessCheckpoint,
524
+ verifyWitnessCheckpoint,
525
+ createRelayStore,
526
+ pushRelayRecord,
527
+ pullRelayRecord,
528
+ createFederationGrant,
529
+ verifyFederationGrant,
530
+ runMeshDemo
531
+ };
@@ -0,0 +1,20 @@
1
+ # `@enigma-ai/enigma/metering`
2
+
3
+ Deterministic, content-minimized usage metering for the Enigma memory layer.
4
+
5
+ ## Contract
6
+
7
+ - Produces `enigma.usage_event.v1` events and `enigma.usage_aggregate.v1` aggregates.
8
+ - Accepts token counts, memory baseline/optimized counts, provider/model identifiers, and public pricing inputs.
9
+ - Computes estimated memory credit from supplied counts only.
10
+ - Does not inspect or store prompts, completions, transcripts, provider responses, decrypted memory, credentials, or secrets.
11
+ - Does not claim provider invoice savings, token ROI/profit/equity, decentralized inference, provider-side deletion, model forgetting, or compliance certification.
12
+
13
+ ## Public API
14
+
15
+ - `createUsageEvent(options)`
16
+ - `aggregateUsageEvents(options | events[])`
17
+
18
+ ## Evidence boundary
19
+
20
+ A metering event is billing/settlement evidence for Enigma-side usage math. It is not proof that any cloud/provider invoice changed, any token has value, any inference backend is decentralized, or any provider deleted/forgot content.