mumpix 1.0.19 → 1.1.3

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 (38) hide show
  1. package/CHANGELOG.md +82 -11
  2. package/README.md +278 -8
  3. package/bin/mumpix.js +1 -405
  4. package/examples/agent-memory.js +1 -1
  5. package/examples/basic.js +1 -1
  6. package/examples/behavioral-primitives.js +50 -0
  7. package/examples/recall-quality-suite.js +156 -0
  8. package/examples/verified-mode.js +1 -1
  9. package/package.json +24 -13
  10. package/scripts/bench-semantic.cjs +76 -0
  11. package/scripts/test-license-modes.cjs +87 -0
  12. package/scripts/test-phase0.cjs +137 -0
  13. package/scripts/test-semantic.cjs +411 -0
  14. package/src/brp/index.js +1 -0
  15. package/src/collapse/index.js +1 -0
  16. package/src/core/MumpixDB.js +264 -323
  17. package/src/core/audit.js +1 -173
  18. package/src/core/auth.js +1 -232
  19. package/src/core/inverted-index.js +249 -0
  20. package/src/core/license.js +1 -267
  21. package/src/core/ml-dsa.mjs +1 -25
  22. package/src/core/ml-kem.mjs +1 -32
  23. package/src/core/recall.js +226 -112
  24. package/src/core/semantic-sidecar.js +312 -0
  25. package/src/core/store.js +365 -288
  26. package/src/core/wal-writer.js +83 -0
  27. package/src/index.js +20 -34
  28. package/src/integrations/developer-sdk.js +1 -165
  29. package/src/integrations/langchain-official.js +1 -0
  30. package/src/integrations/langchain.js +1 -131
  31. package/src/integrations/llamaindex-official.js +1 -0
  32. package/src/integrations/llamaindex.js +1 -86
  33. package/src/integrations/vector-sidecar.js +325 -0
  34. package/src/rlp/index.js +1 -0
  35. package/src/temporal/engine.js +1 -1894
  36. package/src/temporal/indexes.js +1 -178
  37. package/src/temporal/operators.js +1 -186
  38. package/scripts/postinstall-auth.js +0 -101
package/package.json CHANGED
@@ -1,18 +1,17 @@
1
1
  {
2
2
  "name": "mumpix",
3
- "version": "1.0.19",
3
+ "version": "1.1.3",
4
4
  "description": "MumpixDB reasoning ledger and structured memory engine for AI systems",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "mumpix": "bin/mumpix.js"
8
8
  },
9
9
  "scripts": {
10
- "build": "node ./scripts/build-package.cjs",
11
- "postinstall": "node ./scripts/postinstall-auth.js",
12
- "verify:claims": "node ./scripts/verify-claims.cjs",
13
- "release:publish-and-deprecate": "node ./scripts/publish-and-deprecate.cjs",
14
- "release:clean": "bash ./scripts/release-clean.sh",
15
- "release:pack": "npm run build && npm run release:clean && node ./scripts/obfuscate.cjs && npm pack --cache /tmp/mumpix-npm-cache ; node ./scripts/restore.cjs"
10
+ "bench:semantic": "node ./scripts/bench-semantic.cjs",
11
+ "bench:recall": "node ./examples/recall-quality-suite.js",
12
+ "test:phase0": "node ./scripts/test-phase0.cjs",
13
+ "test:semantic": "node ./scripts/test-semantic.cjs",
14
+ "test:license-modes": "node ./scripts/test-license-modes.cjs"
16
15
  },
17
16
  "keywords": [
18
17
  "ai",
@@ -48,16 +47,28 @@
48
47
  "engines": {
49
48
  "node": ">=18.0.0"
50
49
  },
50
+ "peerDependencies": {
51
+ "@langchain/core": ">=1.1.49",
52
+ "llamaindex": ">=0.12.1"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "@langchain/core": {
56
+ "optional": true
57
+ },
58
+ "llamaindex": {
59
+ "optional": true
60
+ }
61
+ },
51
62
  "files": [
52
63
  "src/",
53
64
  "bin/",
54
- "scripts/postinstall-auth.js",
55
- "examples/",
65
+ "scripts/bench-semantic.cjs",
66
+ "scripts/test-phase0.cjs",
67
+ "scripts/test-semantic.cjs",
68
+ "scripts/test-license-modes.cjs",
69
+ "examples/*.js",
56
70
  "CHANGELOG.md",
57
71
  "README.md",
58
72
  "LICENSE"
59
- ],
60
- "devDependencies": {
61
- "javascript-obfuscator": "^5.4.1"
62
- }
73
+ ]
63
74
  }
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const os = require("os");
5
+ const path = require("path");
6
+ const { Mumpix } = require("../src/index");
7
+
8
+ class BenchEmbedder {
9
+ constructor() {
10
+ this.id = "bench-fnv-32-v1";
11
+ this.dim = 32;
12
+ }
13
+
14
+ async embed(texts) {
15
+ return texts.map((text) => {
16
+ const vector = new Float32Array(this.dim);
17
+ for (const token of String(text).toLowerCase().split(/[^a-z0-9]+/).filter(Boolean)) {
18
+ let hash = 0x811c9dc5;
19
+ for (let i = 0; i < token.length; i += 1) {
20
+ hash ^= token.charCodeAt(i);
21
+ hash = Math.imul(hash, 0x01000193);
22
+ }
23
+ vector[(hash >>> 0) % this.dim] += (hash >>> 16) & 1 ? 1 : -1;
24
+ }
25
+ const norm = Math.hypot(...vector) || 1;
26
+ for (let i = 0; i < this.dim; i += 1) vector[i] /= norm;
27
+ return vector;
28
+ });
29
+ }
30
+ }
31
+
32
+ (async () => {
33
+ const count = Number(process.argv[2]) || 5000;
34
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mumpix-semantic-bench-"));
35
+ const filePath = path.join(dir, "bench.mumpix");
36
+ const db = await Mumpix.open(filePath, {
37
+ recall: "semantic",
38
+ embedder: new BenchEmbedder(),
39
+ semanticFloor: 0.35,
40
+ });
41
+
42
+ const startedAt = process.hrtime.bigint();
43
+ for (let i = 0; i < count; i += 1) {
44
+ await db.remember(`semantic bench record ${i} websocket auth middleware route ${i % 97}`);
45
+ }
46
+ const writeSeconds = Number(process.hrtime.bigint() - startedAt) / 1e9;
47
+
48
+ const jsonlPath = `${filePath}.vectors.jsonl`;
49
+ const journalBytes = fs.existsSync(jsonlPath) ? fs.statSync(jsonlPath).size : 0;
50
+ const closeStartedAt = process.hrtime.bigint();
51
+ await db.close();
52
+ const closeSeconds = Number(process.hrtime.bigint() - closeStartedAt) / 1e9;
53
+ const snapshotBytes = fs.existsSync(`${filePath}.vectors.json`)
54
+ ? fs.statSync(`${filePath}.vectors.json`).size
55
+ : 0;
56
+
57
+ console.log(
58
+ JSON.stringify(
59
+ {
60
+ records: count,
61
+ writeSeconds: Number(writeSeconds.toFixed(3)),
62
+ recordsPerSecond: Number((count / writeSeconds).toFixed(1)),
63
+ closeSeconds: Number(closeSeconds.toFixed(3)),
64
+ snapshotBytes,
65
+ journalBytesBeforeClose: journalBytes,
66
+ },
67
+ null,
68
+ 2
69
+ )
70
+ );
71
+
72
+ fs.rmSync(dir, { recursive: true, force: true });
73
+ })().catch((err) => {
74
+ console.error(err && err.stack ? err.stack : err);
75
+ process.exit(1);
76
+ });
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const os = require('os');
7
+ const path = require('path');
8
+
9
+ const { Mumpix } = require('../src');
10
+ const { LicenseManager } = require('../src/core/license');
11
+
12
+ async function main() {
13
+ const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mumpix-license-modes-'));
14
+ if (!process.env.MUMPIX_CONFIG_DIR) {
15
+ process.env.MUMPIX_CONFIG_DIR = path.join(tempRoot, 'config');
16
+ }
17
+
18
+ if (typeof globalThis.crypto === 'undefined') {
19
+ globalThis.crypto = require('node:crypto').webcrypto;
20
+ }
21
+ const { ml_dsa44 } = await import('file://' + path.resolve(__dirname, '..', 'src/core/ml-dsa.mjs'));
22
+
23
+ const issuer = ml_dsa44.keygen();
24
+ process.env.MUMPIX_LICENSE_PUBLIC_KEY_B64 = Buffer.from(issuer.publicKey).toString('base64');
25
+
26
+ const lm = new LicenseManager();
27
+ const device = await lm.deviceIdentityInfo();
28
+ const now = Date.now();
29
+ const payload = {
30
+ id: 'local-test-user',
31
+ tier: 'pro',
32
+ iat: now,
33
+ exp: now + 30 * 24 * 60 * 60 * 1000,
34
+ dpk: device.publicKeyFingerprint,
35
+ issuer: 'local-ml-dsa-test',
36
+ };
37
+
38
+ const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64');
39
+ const signature = ml_dsa44.sign(Buffer.from(payloadB64, 'utf8'), issuer.secretKey);
40
+ const licenseKey = `${payloadB64}.${Buffer.from(signature).toString('base64')}`;
41
+ const licenseSha256 = crypto.createHash('sha256').update(licenseKey).digest('hex');
42
+
43
+ console.log('generated_license');
44
+ console.log(` tier=${payload.tier}`);
45
+ console.log(` exp=${new Date(payload.exp).toISOString()}`);
46
+ console.log(` device=${payload.dpk}`);
47
+ console.log(` license_sha256=${licenseSha256}`);
48
+ console.log(` license_key=${licenseKey}`);
49
+
50
+ const modes = ['eventual', 'strict', 'verified'];
51
+ const results = [];
52
+ for (const mode of modes) {
53
+ const dbPath = path.join(os.tmpdir(), `mumpix-${mode}-${Date.now()}-${crypto.randomBytes(4).toString('hex')}.mumpix`);
54
+ for (const suffix of ['', '.wal', '.lock', '.audit']) {
55
+ try { fs.unlinkSync(dbPath + suffix); } catch (_) {}
56
+ }
57
+
58
+ const db = await Mumpix.open(dbPath, { consistency: mode, licenseKey });
59
+ await db.remember(`Mode ${mode} remembers signed license verification`);
60
+ const recalled = await db.recall('signed license verification');
61
+ const stats = await db.stats();
62
+ let auditCount = null;
63
+ if (mode === 'verified') {
64
+ auditCount = (await db.audit()).length;
65
+ }
66
+ await db.close();
67
+
68
+ results.push({
69
+ mode,
70
+ effective: db.consistency,
71
+ records: stats.records,
72
+ recall: recalled ? 'ok' : 'missing',
73
+ auditCount,
74
+ });
75
+ }
76
+
77
+ console.log('mode_results');
78
+ for (const result of results) {
79
+ const audit = result.auditCount == null ? '' : ` audit=${result.auditCount}`;
80
+ console.log(` ${result.mode}: effective=${result.effective} records=${result.records} recall=${result.recall}${audit}`);
81
+ }
82
+ }
83
+
84
+ main().catch((error) => {
85
+ console.error(error && error.stack ? error.stack : error);
86
+ process.exit(1);
87
+ });
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+
3
+ const assert = require("assert");
4
+ const fs = require("fs");
5
+ const os = require("os");
6
+ const path = require("path");
7
+ const { spawn } = require("child_process");
8
+ const { Mumpix } = require("../src/index");
9
+
10
+ function rmDb(filePath) {
11
+ for (const suffix of ["", ".wal", ".lock", ".idx"]) {
12
+ try {
13
+ fs.rmSync(`${filePath}${suffix}`, { force: true, recursive: true });
14
+ } catch (_) {}
15
+ }
16
+ }
17
+
18
+ async function testNoMatchThreshold() {
19
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mumpix-phase0-recall-"));
20
+ const filePath = path.join(dir, "memory.mumpix");
21
+ rmDb(filePath);
22
+
23
+ const db = await Mumpix.open(filePath, { consistency: "eventual" });
24
+ try {
25
+ await db.remember("The sky is blue");
26
+
27
+ const miss = await db.recall("quarterly financial projections for the merger");
28
+ assert.strictEqual(miss, null, "unrelated recall() query should return null");
29
+
30
+ const manyMiss = await db.recallMany("quarterly financial projections for the merger", 3);
31
+ assert.deepStrictEqual(manyMiss, [], "unrelated recallMany() query should return []");
32
+
33
+ const hit = await db.recall("sky blue");
34
+ assert.strictEqual(hit, "The sky is blue", "related query should still recall the matching record");
35
+
36
+ const permissive = await db.recall("quarterly financial projections for the merger", {
37
+ minScore: false,
38
+ });
39
+ assert.strictEqual(
40
+ permissive,
41
+ "The sky is blue",
42
+ "minScore:false should preserve explicit opt-out behavior"
43
+ );
44
+ } finally {
45
+ await db.close();
46
+ rmDb(filePath);
47
+ fs.rmSync(dir, { force: true, recursive: true });
48
+ }
49
+ }
50
+
51
+ async function testSigkillLeavesRecoverableLock() {
52
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mumpix-phase0-lock-"));
53
+ const filePath = path.join(dir, "memory.mumpix");
54
+ rmDb(filePath);
55
+
56
+ const childCode = `
57
+ const { Mumpix } = require(${JSON.stringify(path.resolve(__dirname, "../src/index"))});
58
+ (async () => {
59
+ const db = await Mumpix.open(${JSON.stringify(filePath)}, { consistency: "eventual" });
60
+ await db.remember("pre-crash record");
61
+ if (process.send) process.send({ ready: true });
62
+ setInterval(() => {}, 1000);
63
+ })().catch((err) => {
64
+ if (process.send) process.send({ error: err.message });
65
+ process.exit(1);
66
+ });
67
+ `;
68
+
69
+ const child = spawn(process.execPath, ["-e", childCode], {
70
+ stdio: ["ignore", "ignore", "ignore", "ipc"],
71
+ });
72
+
73
+ try {
74
+ await new Promise((resolve, reject) => {
75
+ const timeout = setTimeout(() => reject(new Error("child did not open database")), 5000);
76
+ child.once("message", (message) => {
77
+ clearTimeout(timeout);
78
+ if (message && message.error) reject(new Error(message.error));
79
+ else resolve();
80
+ });
81
+ child.once("exit", (code, signal) => {
82
+ clearTimeout(timeout);
83
+ reject(new Error(`child exited before ready: code=${code} signal=${signal}`));
84
+ });
85
+ });
86
+
87
+ assert(fs.existsSync(`${filePath}.lock`), "child should leave a live lock while open");
88
+ child.kill("SIGKILL");
89
+
90
+ await new Promise((resolve) => child.once("exit", resolve));
91
+
92
+ const reopened = await Mumpix.open(filePath, { consistency: "eventual" });
93
+ try {
94
+ const records = await reopened.list();
95
+ assert.strictEqual(records.length, 1, "pre-crash record should survive SIGKILL");
96
+ assert.strictEqual(records[0].content, "pre-crash record");
97
+ } finally {
98
+ await reopened.close();
99
+ }
100
+ } finally {
101
+ if (!child.killed) child.kill("SIGKILL");
102
+ rmDb(filePath);
103
+ fs.rmSync(dir, { force: true, recursive: true });
104
+ }
105
+ }
106
+
107
+ async function testDeadPidLockPayload() {
108
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mumpix-phase0-deadpid-"));
109
+ const filePath = path.join(dir, "memory.mumpix");
110
+ rmDb(filePath);
111
+
112
+ fs.writeFileSync(
113
+ `${filePath}.lock`,
114
+ JSON.stringify({ pid: 99999999, ts: Date.now() }),
115
+ "utf8"
116
+ );
117
+
118
+ const db = await Mumpix.open(filePath, { consistency: "eventual" });
119
+ try {
120
+ await db.remember("dead pid lock was removed");
121
+ assert.strictEqual(await db.recall("dead pid"), "dead pid lock was removed");
122
+ } finally {
123
+ await db.close();
124
+ rmDb(filePath);
125
+ fs.rmSync(dir, { force: true, recursive: true });
126
+ }
127
+ }
128
+
129
+ (async () => {
130
+ await testNoMatchThreshold();
131
+ await testSigkillLeavesRecoverableLock();
132
+ await testDeadPidLockPayload();
133
+ console.log("phase0 regression tests passed");
134
+ })().catch((err) => {
135
+ console.error(err && err.stack ? err.stack : err);
136
+ process.exit(1);
137
+ });