mumpix 1.0.6 → 1.0.13
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 +61 -1
- package/README.md +124 -15
- package/bin/mumpix.js +103 -2
- package/examples/developer-sdk.js +28 -0
- package/examples/license-expiry-downgrade-check.js +69 -0
- package/package.json +10 -3
- package/scripts/postinstall-auth.js +100 -0
- package/src/core/MumpixDB.js +64 -18
- package/src/core/auth.js +199 -0
- package/src/core/license.js +143 -6
- package/src/core/store.js +150 -14
- package/src/index.js +5 -0
- package/src/integrations/developer-sdk.js +158 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.11 - 2026-03-03
|
|
4
|
+
|
|
5
|
+
## 1.0.12 - 2026-03-03
|
|
6
|
+
|
|
7
|
+
### Fixes
|
|
8
|
+
- Fixed CLI database opening bug: `mumpix` commands now correctly `await Mumpix.open(...)` before operations, resolving `db.close is not a function`.
|
|
9
|
+
|
|
10
|
+
### Verification
|
|
11
|
+
- Added executable truth-audit script: `npm run verify:claims`.
|
|
12
|
+
- Script validates core API, WAL replay, verified audit methods, integrations, CLI basic commands, SDK error surface, and license policy defaults.
|
|
13
|
+
|
|
14
|
+
### Documentation
|
|
15
|
+
- Updated README examples to use `await Mumpix.open(...)`.
|
|
16
|
+
- Clarified that `strict`/`verified` are tier-gated capabilities (SDK and CLI).
|
|
17
|
+
- Added `verify:claims` usage to the examples section.
|
|
18
|
+
|
|
19
|
+
## Unreleased
|
|
20
|
+
|
|
21
|
+
### Licensing (offline/air-gapped)
|
|
22
|
+
- Added monthly tier capability mapping for paid durability modes (`eventual`, `strict`) while active.
|
|
23
|
+
- Set monthly offline lease default to 45 days (`MUMPIX_LICENSE_MAX_DAYS_MONTHLY=45` by default).
|
|
24
|
+
- Set enterprise/government/compliance lease defaults to long-window values (100 years default, env configurable).
|
|
25
|
+
- Enforced expiry downgrade policy: expired paid licenses continue in `eventual` mode; paid modes require renewal.
|
|
26
|
+
- Added `examples/license-expiry-downgrade-check.js` to verify downgrade behavior locally.
|
|
27
|
+
|
|
28
|
+
### Authentication
|
|
29
|
+
- Added local account auth state support in `src/core/auth.js`.
|
|
30
|
+
- Added CLI auth commands: `mumpix auth login|status|logout`.
|
|
31
|
+
- Added automatic local-license loading in `MumpixDB.open()` when `licenseKey` is not passed explicitly.
|
|
32
|
+
- Added install-time auth script (`postinstall`) that prompts for account sign-in in interactive terminals.
|
|
33
|
+
- Added browser-open device flow on install; skip path remains `eventual` only.
|
|
34
|
+
|
|
35
|
+
## 1.0.9 - 2026-03-02
|
|
36
|
+
|
|
37
|
+
### Developer experience
|
|
38
|
+
- Added `MumpixDevClient` HTTP SDK for developers building on Mumpix services.
|
|
39
|
+
- Added `MumpixApiError` with structured `.status` and `.data` for reliable client-side error handling.
|
|
40
|
+
- Added API helpers for memory ops, explorer file ops, settings, ROM/manual endpoints, and export URL generation.
|
|
41
|
+
- Added `examples/developer-sdk.js` quick-start integration script.
|
|
42
|
+
- Updated README with a dedicated Developer SDK usage section and method reference.
|
|
43
|
+
|
|
44
|
+
## 1.0.8 - 2026-02-27
|
|
45
|
+
|
|
46
|
+
### Crash safety + integrity recovery hardening
|
|
47
|
+
- Added durable WAL writes (`fdatasync`) before main-file append to ensure recovery intent survives crashes.
|
|
48
|
+
- Added process lock file (`.lock`) to prevent concurrent writers from corrupting the same database file.
|
|
49
|
+
- Added strict-mode recovery path for tail corruption when WAL exists:
|
|
50
|
+
- truncates corrupted tail to last verified-good record set,
|
|
51
|
+
- replays WAL,
|
|
52
|
+
- continues open instead of hard-failing.
|
|
53
|
+
- Kept strict behavior secure when no WAL evidence exists (tamper/noise still fails fast).
|
|
54
|
+
|
|
55
|
+
## 1.0.7 - 2026-02-27
|
|
56
|
+
|
|
57
|
+
### Documentation
|
|
58
|
+
- Updated licensing and tier model in README to capability-based gating:
|
|
59
|
+
- Community: `eventual`
|
|
60
|
+
- Developer/Teams: `eventual`, `strict`
|
|
61
|
+
- Compliance: `eventual`, `strict`, `verified`
|
|
62
|
+
- Removed outdated mention of a 100-record free-tier cap from package docs.
|
|
63
|
+
|
|
3
64
|
## 1.0.6 - 2026-02-27
|
|
4
65
|
|
|
5
66
|
### Security hardening
|
|
@@ -19,4 +80,3 @@
|
|
|
19
80
|
|
|
20
81
|
### Reliability
|
|
21
82
|
- Hardened strict-mode behavior to fail fast on malformed or tampered WAL/record entries.
|
|
22
|
-
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ If you've ever watched an agent "forget" what it just learned, or had to explain
|
|
|
27
27
|
const { Mumpix } = require('mumpix')
|
|
28
28
|
|
|
29
29
|
// Open (or create) a local database
|
|
30
|
-
const db = Mumpix.open('./agent.mumpix', { consistency: '
|
|
30
|
+
const db = await Mumpix.open('./agent.mumpix', { consistency: 'eventual' })
|
|
31
31
|
|
|
32
32
|
// Store memories
|
|
33
33
|
await db.remember('User prefers TypeScript over JavaScript')
|
|
@@ -45,7 +45,47 @@ await db.close()
|
|
|
45
45
|
|
|
46
46
|
## API
|
|
47
47
|
|
|
48
|
-
###
|
|
48
|
+
### Developer SDK (HTTP Client)
|
|
49
|
+
|
|
50
|
+
For developers integrating Mumpix-backed services (local runner, benchmark APIs, hosted tools):
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
const { MumpixDevClient } = require('mumpix')
|
|
54
|
+
|
|
55
|
+
const client = new MumpixDevClient({
|
|
56
|
+
baseUrl: 'https://mumpixdb.com/benchmark'
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const health = await client.health()
|
|
60
|
+
await client.remember('user likes concise answers')
|
|
61
|
+
const hit = await client.recall('what does the user like?')
|
|
62
|
+
const stats = await client.stats()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `MumpixDevClient` methods
|
|
66
|
+
|
|
67
|
+
- `health()`
|
|
68
|
+
- `remember(content)`
|
|
69
|
+
- `recall(query)`
|
|
70
|
+
- `recallMany(query, k)`
|
|
71
|
+
- `memories()`
|
|
72
|
+
- `clear()`
|
|
73
|
+
- `stats()`
|
|
74
|
+
- `settings()`
|
|
75
|
+
- `updateSettings(patch)`
|
|
76
|
+
- `files()`
|
|
77
|
+
- `readFile(file, { atTs, source })`
|
|
78
|
+
- `timeline(file, { source })`
|
|
79
|
+
- `exportUrl(file, format, { atTs, source })`
|
|
80
|
+
- `roms()`
|
|
81
|
+
- `manualForRom(file)`
|
|
82
|
+
- `manualViewUrl(file, { isolate, v })`
|
|
83
|
+
|
|
84
|
+
Errors are thrown as `MumpixApiError` with `.status` and `.data` fields.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### `Mumpix.open(filePath, [opts])` → `Promise<MumpixDB>`
|
|
49
89
|
|
|
50
90
|
Opens (or creates) a Mumpix database.
|
|
51
91
|
|
|
@@ -54,6 +94,8 @@ Opens (or creates) a Mumpix database.
|
|
|
54
94
|
| `consistency` | `string` | `'eventual'` | `'eventual'` / `'strict'` / `'verified'` |
|
|
55
95
|
| `embedFn` | `async fn(texts[]) → number[][]` | — | Custom embedding function (OpenAI, Cohere, etc.) |
|
|
56
96
|
|
|
97
|
+
Note: `strict` and `verified` are tier-gated capabilities. Without an active paid license, paid mode requests are blocked or downgraded to `eventual` based on license state.
|
|
98
|
+
|
|
57
99
|
### Consistency modes
|
|
58
100
|
|
|
59
101
|
| Mode | Write behaviour | Audit log | Use case |
|
|
@@ -105,7 +147,7 @@ await db.close()
|
|
|
105
147
|
### Verified-mode methods
|
|
106
148
|
|
|
107
149
|
```js
|
|
108
|
-
const db = Mumpix.open('./compliance.mumpix', { consistency: 'verified' })
|
|
150
|
+
const db = await Mumpix.open('./compliance.mumpix', { consistency: 'verified' })
|
|
109
151
|
|
|
110
152
|
// Full audit log
|
|
111
153
|
await db.audit()
|
|
@@ -145,7 +187,7 @@ async function embedFn(texts) {
|
|
|
145
187
|
return res.data.map(d => d.embedding)
|
|
146
188
|
}
|
|
147
189
|
|
|
148
|
-
const db = Mumpix.open('./agent.mumpix', { consistency: 'strict', embedFn })
|
|
190
|
+
const db = await Mumpix.open('./agent.mumpix', { consistency: 'strict', embedFn })
|
|
149
191
|
// db.recall() and db.recallMany() now use OpenAI embeddings automatically
|
|
150
192
|
```
|
|
151
193
|
|
|
@@ -157,7 +199,7 @@ const db = Mumpix.open('./agent.mumpix', { consistency: 'strict', embedFn })
|
|
|
157
199
|
const { Mumpix } = require('mumpix')
|
|
158
200
|
const { MumpixVectorStore, MumpixChatMemory, MumpixRetriever } = require('mumpix/src/integrations/langchain')
|
|
159
201
|
|
|
160
|
-
const db = Mumpix.open('./agent.mumpix', { consistency: 'strict' })
|
|
202
|
+
const db = await Mumpix.open('./agent.mumpix', { consistency: 'strict' })
|
|
161
203
|
|
|
162
204
|
// As a VectorStore
|
|
163
205
|
const store = new MumpixVectorStore(db)
|
|
@@ -178,7 +220,7 @@ const results = await retriever.getRelevantDocuments('query')
|
|
|
178
220
|
const { Mumpix } = require('mumpix')
|
|
179
221
|
const { MumpixIndex, MumpixReader } = require('mumpix/src/integrations/llamaindex')
|
|
180
222
|
|
|
181
|
-
const db = Mumpix.open('./agent.mumpix', { consistency: 'strict' })
|
|
223
|
+
const db = await Mumpix.open('./agent.mumpix', { consistency: 'strict' })
|
|
182
224
|
|
|
183
225
|
const index = new MumpixIndex(db)
|
|
184
226
|
const retriever = index.asRetriever({ topK: 5 })
|
|
@@ -213,6 +255,8 @@ mumpix recall ./agent.mumpix "query" --consistency=strict
|
|
|
213
255
|
mumpix shell ./compliance.mumpix --consistency=verified
|
|
214
256
|
```
|
|
215
257
|
|
|
258
|
+
Note: CLI strict/verified modes are tier-gated the same as SDK/API mode selection.
|
|
259
|
+
|
|
216
260
|
---
|
|
217
261
|
|
|
218
262
|
## File format
|
|
@@ -221,8 +265,8 @@ The `.mumpix` file is plain NDJSON — human-readable, portable, no binary parse
|
|
|
221
265
|
|
|
222
266
|
```
|
|
223
267
|
{"v":1,"consistency":"strict","created":1740000000000,"path":"agent.mumpix"}
|
|
224
|
-
{"id":1,"content":"User prefers TypeScript","ts":1740000001000,"h":"
|
|
225
|
-
{"id":2,"content":"Use pnpm workspaces","ts":1740000002000,"h":"
|
|
268
|
+
{"id":1,"content":"User prefers TypeScript","ts":1740000001000,"h":"hmac256:..."}
|
|
269
|
+
{"id":2,"content":"Use pnpm workspaces","ts":1740000002000,"h":"hmac256:..."}
|
|
226
270
|
```
|
|
227
271
|
|
|
228
272
|
**Crash safety**: Mumpix uses a WAL (`.mumpix.wal`). On write:
|
|
@@ -242,6 +286,20 @@ On open, any leftover WAL is replayed before accepting new writes. A record is e
|
|
|
242
286
|
node examples/basic.js # Zero-config 5-line demo
|
|
243
287
|
node examples/agent-memory.js # Persistent agent preferences (run twice)
|
|
244
288
|
node examples/verified-mode.js # Compliance audit log export
|
|
289
|
+
npm run verify:claims # executable truth-audit for package claims
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Release maintenance
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Publish current version and deprecate all older npm versions
|
|
296
|
+
npm run release:publish-and-deprecate -- --otp=123456
|
|
297
|
+
|
|
298
|
+
# Optional flags:
|
|
299
|
+
# --skip-verify skip verify:claims
|
|
300
|
+
# --skip-publish only deprecate older versions
|
|
301
|
+
# --dry-run no writes to npm
|
|
302
|
+
# --remove-old try to unpublish old versions; deprecate on failure
|
|
245
303
|
```
|
|
246
304
|
|
|
247
305
|
---
|
|
@@ -262,14 +320,35 @@ Copyright © 2026 Mumpix (vdsx.cloud). All Rights Reserved.
|
|
|
262
320
|
|
|
263
321
|
## Licensing & Tiers
|
|
264
322
|
|
|
265
|
-
Mumpix
|
|
323
|
+
Mumpix uses capability-based tiering: community is for building, paid tiers are for production operation and compliance.
|
|
266
324
|
|
|
267
|
-
|
|
|
268
|
-
|
|
269
|
-
|
|
|
270
|
-
| `strict` mode | ✅ | ✅ | ✅ |
|
|
271
|
-
| `verified` mode | ❌ |
|
|
272
|
-
|
|
|
325
|
+
| Capability | Community (Free) | Developer ($19/mo) | Teams ($79/mo) | Compliance ($5K/mo) |
|
|
326
|
+
|---|---|---|---|---|
|
|
327
|
+
| `eventual` mode | ✅ | ✅ | ✅ | ✅ |
|
|
328
|
+
| `strict` mode | ❌ | ✅ | ✅ | ✅ |
|
|
329
|
+
| `verified` mode | ❌ | ❌ | ❌ | ✅ |
|
|
330
|
+
| Record writes | Unlimited | Unlimited | Unlimited | Unlimited |
|
|
331
|
+
| Offline use | ✅ | ✅ | ✅ | ✅ |
|
|
332
|
+
|
|
333
|
+
### Tier intent
|
|
334
|
+
|
|
335
|
+
- **Community**: build and prototype with full local development flow.
|
|
336
|
+
- **Developer**: unlock production durability via `strict`.
|
|
337
|
+
- **Teams**: same core durability plus team/commercial operations.
|
|
338
|
+
- **Compliance**: regulated workflows with `verified` audit capabilities.
|
|
339
|
+
|
|
340
|
+
### Offline/Air-gapped expiry policy
|
|
341
|
+
|
|
342
|
+
- Monthly licenses use a **45-day offline lease window** by default.
|
|
343
|
+
- Enterprise/government/compliance licenses support long/custom lease windows (for example 5-year, 10-year, or custom).
|
|
344
|
+
- When a paid license is expired, requested paid modes are automatically downgraded to `eventual` until renewal.
|
|
345
|
+
|
|
346
|
+
You can tune lease windows with environment variables:
|
|
347
|
+
|
|
348
|
+
- `MUMPIX_LICENSE_MAX_DAYS_MONTHLY` (default `45`)
|
|
349
|
+
- `MUMPIX_LICENSE_MAX_DAYS_ENTERPRISE` (default `36500`)
|
|
350
|
+
- `MUMPIX_LICENSE_MAX_DAYS_GOVERNMENT` (default `36500`)
|
|
351
|
+
- `MUMPIX_LICENSE_MAX_DAYS_COMPLIANCE` (default `36500`)
|
|
273
352
|
|
|
274
353
|
### Using a License Key
|
|
275
354
|
|
|
@@ -280,3 +359,33 @@ const db = await Mumpix.open('./agent.mumpix', {
|
|
|
280
359
|
```
|
|
281
360
|
|
|
282
361
|
Get your key at [mumpixdb.com](https://mumpixdb.com).
|
|
362
|
+
|
|
363
|
+
### No-Key account login (recommended)
|
|
364
|
+
|
|
365
|
+
You can link your paid account once and let Mumpix load the local signed license automatically:
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
mumpix auth login # device flow (browser-based)
|
|
369
|
+
mumpix auth status
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Advanced login options:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
mumpix auth login --token=<account-token> # backend token exchange
|
|
376
|
+
mumpix auth login --license=<signed-license> # direct import
|
|
377
|
+
mumpix auth logout
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
For `--token` exchange, your backend should expose `/api/mumpix/auth/token/exchange` and map account tokens server-side (for example via `MUMPIX_AUTH_TOKEN_MAP`), not raw user IDs.
|
|
381
|
+
|
|
382
|
+
By default, auth state is stored at `~/.config/mumpix/auth.json` (or `%APPDATA%/mumpix/auth.json` on Windows).
|
|
383
|
+
|
|
384
|
+
### Install-time auth flow
|
|
385
|
+
|
|
386
|
+
On `npm install mumpix`, the package runs an install-time auth prompt in interactive terminals:
|
|
387
|
+
|
|
388
|
+
- Press **Enter**: browser opens for account auth and local signed license is stored.
|
|
389
|
+
- Press any other key: install continues in `eventual` mode only.
|
|
390
|
+
|
|
391
|
+
Non-interactive installs (CI/containers) skip this prompt automatically and default to `eventual`.
|
package/bin/mumpix.js
CHANGED
|
@@ -17,6 +17,15 @@
|
|
|
17
17
|
const path = require('path');
|
|
18
18
|
const readline = require('readline');
|
|
19
19
|
const { Mumpix } = require('../src/index');
|
|
20
|
+
const {
|
|
21
|
+
loadAuthState,
|
|
22
|
+
clearAuthState,
|
|
23
|
+
upsertStoredLicense,
|
|
24
|
+
exchangeTokenForLicense,
|
|
25
|
+
loginWithDeviceFlow,
|
|
26
|
+
authStatePath,
|
|
27
|
+
configDir,
|
|
28
|
+
} = require('../src/core/auth');
|
|
20
29
|
|
|
21
30
|
const USAGE = `
|
|
22
31
|
mumpix — SQLite for AI
|
|
@@ -33,6 +42,7 @@ Commands:
|
|
|
33
42
|
stats <file> Show database stats
|
|
34
43
|
audit <file> Show audit log (verified mode)
|
|
35
44
|
shell <file> Start interactive REPL
|
|
45
|
+
auth <subcommand> Account login/logout/status
|
|
36
46
|
help Show this message
|
|
37
47
|
|
|
38
48
|
Options (append to any command):
|
|
@@ -43,6 +53,9 @@ Examples:
|
|
|
43
53
|
mumpix recall ./agent.mumpix "what language?" --consistency=strict
|
|
44
54
|
mumpix search ./agent.mumpix "TypeScript" 3
|
|
45
55
|
mumpix shell ./agent.mumpix --consistency=verified
|
|
56
|
+
mumpix auth status
|
|
57
|
+
mumpix auth login --token=<account-token>
|
|
58
|
+
mumpix auth login --license=<signed-license-key>
|
|
46
59
|
`.trim();
|
|
47
60
|
|
|
48
61
|
function parseArgs(argv) {
|
|
@@ -77,15 +90,103 @@ const yellow = t => colorize(t, '33');
|
|
|
77
90
|
const red = t => colorize(t, '31');
|
|
78
91
|
const bold = t => colorize(t, '1');
|
|
79
92
|
|
|
93
|
+
function fmtExpiry(ts) {
|
|
94
|
+
if (!ts) return '-';
|
|
95
|
+
const d = new Date(Number(ts));
|
|
96
|
+
if (Number.isNaN(d.getTime())) return '-';
|
|
97
|
+
return d.toISOString();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function mask(value, keep = 6) {
|
|
101
|
+
const s = String(value || '');
|
|
102
|
+
if (s.length <= keep) return s;
|
|
103
|
+
return `${s.slice(0, keep)}…`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function runAuth(parts, flags) {
|
|
107
|
+
const sub = String(parts[0] || 'status').toLowerCase();
|
|
108
|
+
|
|
109
|
+
if (sub === 'status') {
|
|
110
|
+
const s = loadAuthState();
|
|
111
|
+
if (!s || !s.license || !s.license.key) {
|
|
112
|
+
console.log(dim('Not logged in.'));
|
|
113
|
+
console.log(dim(`Config dir: ${configDir()}`));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
console.log(bold('Mumpix auth status'));
|
|
117
|
+
console.log(` account_id: ${s.account && s.account.id ? s.account.id : '-'}`);
|
|
118
|
+
console.log(` tier: ${s.license.tier || (s.account && s.account.tier) || '-'}`);
|
|
119
|
+
console.log(` issued_at: ${fmtExpiry(s.license.iat)}`);
|
|
120
|
+
console.log(` expires_at: ${fmtExpiry(s.license.exp)}`);
|
|
121
|
+
console.log(` license: ${green(mask(s.license.key, 18))}`);
|
|
122
|
+
console.log(` state: ${authStatePath()}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (sub === 'logout') {
|
|
127
|
+
clearAuthState();
|
|
128
|
+
console.log(green('✓') + ' Logged out. Local license removed.');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (sub === 'login') {
|
|
133
|
+
const directLicense = flags.license || flags['license-key'] || null;
|
|
134
|
+
if (directLicense) {
|
|
135
|
+
const state = upsertStoredLicense(String(directLicense));
|
|
136
|
+
console.log(green('✓') + ' License saved.');
|
|
137
|
+
console.log(` tier: ${state.license.tier || '-'}`);
|
|
138
|
+
console.log(` expires_at: ${fmtExpiry(state.license.exp)}`);
|
|
139
|
+
console.log(` state: ${authStatePath()}`);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const token = flags.token || process.env.MUMPIX_AUTH_TOKEN || '';
|
|
144
|
+
if (token) {
|
|
145
|
+
const state = await exchangeTokenForLicense(String(token).trim(), {});
|
|
146
|
+
console.log(green('✓') + ' Account linked and license saved.');
|
|
147
|
+
console.log(` account_id: ${state.account.id || '-'}`);
|
|
148
|
+
console.log(` tier: ${state.license.tier || state.account.tier || '-'}`);
|
|
149
|
+
console.log(` expires_at: ${fmtExpiry(state.license.exp)}`);
|
|
150
|
+
console.log(` state: ${authStatePath()}`);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const state = await loginWithDeviceFlow({
|
|
155
|
+
onPrompt: ({ userCode, verifyUrl, expiresInSec, intervalSec }) => {
|
|
156
|
+
console.log(bold('Mumpix device login'));
|
|
157
|
+
console.log(` 1) Open: ${verifyUrl}`);
|
|
158
|
+
console.log(` 2) Enter code: ${cyan(userCode)}`);
|
|
159
|
+
console.log(` 3) Waiting for approval... (expires in ${expiresInSec}s, polling ${intervalSec}s)`);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
console.log(green('✓') + ' Account linked and license saved.');
|
|
163
|
+
console.log(` account_id: ${state.account.id || '-'}`);
|
|
164
|
+
console.log(` tier: ${state.license.tier || state.account.tier || '-'}`);
|
|
165
|
+
console.log(` expires_at: ${fmtExpiry(state.license.exp)}`);
|
|
166
|
+
console.log(` state: ${authStatePath()}`);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.error(red(`Unknown auth subcommand: ${sub}`));
|
|
171
|
+
console.log('Usage: mumpix auth <status|login|logout> [--token=...] [--license=...]');
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
|
|
80
175
|
async function main() {
|
|
81
176
|
const { args, flags } = parseArgs(process.argv.slice(2));
|
|
82
|
-
const [command,
|
|
177
|
+
const [command, arg1, ...rest] = args;
|
|
83
178
|
|
|
84
179
|
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
85
180
|
console.log(USAGE);
|
|
86
181
|
process.exit(0);
|
|
87
182
|
}
|
|
88
183
|
|
|
184
|
+
if (command === 'auth') {
|
|
185
|
+
await runAuth([arg1, ...rest], flags);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const filePath = arg1;
|
|
89
190
|
if (!filePath && command !== 'help') {
|
|
90
191
|
console.error(red('Error: file path required'));
|
|
91
192
|
console.log(USAGE);
|
|
@@ -96,7 +197,7 @@ async function main() {
|
|
|
96
197
|
let db;
|
|
97
198
|
|
|
98
199
|
try {
|
|
99
|
-
db = Mumpix.open(filePath, { consistency });
|
|
200
|
+
db = await Mumpix.open(filePath, { consistency });
|
|
100
201
|
} catch (err) {
|
|
101
202
|
console.error(red(`Error opening ${filePath}: ${err.message}`));
|
|
102
203
|
process.exit(1);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { MumpixDevClient } = require('../src');
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
const client = new MumpixDevClient({
|
|
7
|
+
baseUrl: process.env.MUMPIX_BASE_URL || 'http://127.0.0.1:3012',
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const health = await client.health();
|
|
11
|
+
console.log('health:', health);
|
|
12
|
+
|
|
13
|
+
await client.remember('Developer SDK smoke test memory');
|
|
14
|
+
const recalled = await client.recall('smoke test memory');
|
|
15
|
+
console.log('recalled:', recalled);
|
|
16
|
+
|
|
17
|
+
const stats = await client.stats();
|
|
18
|
+
console.log('stats.records:', stats.records);
|
|
19
|
+
|
|
20
|
+
const files = await client.files();
|
|
21
|
+
console.log('files:', (files.files || []).slice(0, 5));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
main().catch((err) => {
|
|
25
|
+
console.error(err);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
});
|
|
28
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* examples/license-expiry-downgrade-check.js
|
|
5
|
+
*
|
|
6
|
+
* Verifies offline expiry behavior:
|
|
7
|
+
* - expired monthly license can still use eventual mode
|
|
8
|
+
* - strict mode is blocked for expired license
|
|
9
|
+
* - requested strict mode auto-downgrades to eventual at open()
|
|
10
|
+
*
|
|
11
|
+
* Run:
|
|
12
|
+
* node examples/license-expiry-downgrade-check.js
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const os = require('os');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { MumpixDB } = require('../src/core/MumpixDB');
|
|
18
|
+
const { LicenseManager } = require('../src/core/license');
|
|
19
|
+
|
|
20
|
+
async function main() {
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
const lic = new LicenseManager();
|
|
23
|
+
lic.tier = 'monthly';
|
|
24
|
+
lic.verified = true;
|
|
25
|
+
lic.issuedAt = now - (50 * 24 * 60 * 60 * 1000);
|
|
26
|
+
lic.expiry = now - (60 * 1000);
|
|
27
|
+
|
|
28
|
+
// Expired monthly license: eventual should still be allowed.
|
|
29
|
+
lic.assertActive('eventual');
|
|
30
|
+
|
|
31
|
+
let strictBlocked = false;
|
|
32
|
+
try {
|
|
33
|
+
lic.assertActive('strict');
|
|
34
|
+
} catch (_) {
|
|
35
|
+
strictBlocked = true;
|
|
36
|
+
}
|
|
37
|
+
if (!strictBlocked) {
|
|
38
|
+
throw new Error('Expected strict mode to be blocked for expired monthly license');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Requested strict should be downgraded to eventual at DB open.
|
|
42
|
+
const dbPath = path.join(
|
|
43
|
+
os.tmpdir(),
|
|
44
|
+
`mumpix-expiry-downgrade-check-${process.pid}-${Date.now()}.mpx`
|
|
45
|
+
);
|
|
46
|
+
const db = await MumpixDB.open(dbPath, {
|
|
47
|
+
consistency: 'strict',
|
|
48
|
+
licenseManager: lic
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const okMode = db.consistency === 'eventual';
|
|
52
|
+
const okMeta = db._opts &&
|
|
53
|
+
db._opts.requestedConsistency === 'strict' &&
|
|
54
|
+
db._opts.downgradedConsistency &&
|
|
55
|
+
db._opts.downgradedConsistency.to === 'eventual';
|
|
56
|
+
|
|
57
|
+
await db.close();
|
|
58
|
+
|
|
59
|
+
if (!okMode || !okMeta) {
|
|
60
|
+
throw new Error(`Unexpected downgrade result: consistency=${db.consistency}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log('PASS license-expiry-downgrade-check');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
main().catch((err) => {
|
|
67
|
+
console.error('FAIL license-expiry-downgrade-check:', err && err.message ? err.message : err);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
package/package.json
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mumpix",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "SQLite for AI — embedded, zero-config memory database for AI agents and LLM applications",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"mumpix": "
|
|
7
|
+
"mumpix": "bin/mumpix.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"postinstall": "node ./scripts/postinstall-auth.js",
|
|
11
|
+
"verify:claims": "node ./scripts/verify-claims.cjs",
|
|
12
|
+
"release:publish-and-deprecate": "node ./scripts/publish-and-deprecate.cjs",
|
|
13
|
+
"release:clean": "bash ./scripts/release-clean.sh",
|
|
14
|
+
"release:pack": "npm run release:clean && npm pack --cache /tmp/mumpix-npm-cache"
|
|
8
15
|
},
|
|
9
|
-
"scripts": {},
|
|
10
16
|
"keywords": [
|
|
11
17
|
"ai",
|
|
12
18
|
"memory",
|
|
@@ -33,6 +39,7 @@
|
|
|
33
39
|
"files": [
|
|
34
40
|
"src/",
|
|
35
41
|
"bin/",
|
|
42
|
+
"scripts/postinstall-auth.js",
|
|
36
43
|
"examples/",
|
|
37
44
|
"CHANGELOG.md",
|
|
38
45
|
"README.md",
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const readline = require('readline');
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
const {
|
|
7
|
+
loginWithDeviceFlow,
|
|
8
|
+
exchangeTokenForLicense,
|
|
9
|
+
authStatePath,
|
|
10
|
+
} = require('../src/core/auth');
|
|
11
|
+
|
|
12
|
+
function isInteractive() {
|
|
13
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY && process.env.CI !== 'true');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function fmtExpiry(ts) {
|
|
17
|
+
if (!ts) return '-';
|
|
18
|
+
const d = new Date(Number(ts));
|
|
19
|
+
if (Number.isNaN(d.getTime())) return '-';
|
|
20
|
+
return d.toISOString();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function openBrowser(url) {
|
|
24
|
+
if (!url) return false;
|
|
25
|
+
try {
|
|
26
|
+
if (process.platform === 'darwin') {
|
|
27
|
+
spawn('open', [url], { stdio: 'ignore', detached: true }).unref();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (process.platform === 'win32') {
|
|
31
|
+
spawn('cmd', ['/c', 'start', '', url], { stdio: 'ignore', detached: true }).unref();
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
spawn('xdg-open', [url], { stdio: 'ignore', detached: true }).unref();
|
|
35
|
+
return true;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ask(question) {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
44
|
+
rl.question(question, (answer) => {
|
|
45
|
+
rl.close();
|
|
46
|
+
resolve(String(answer || '').trim());
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function run() {
|
|
52
|
+
try {
|
|
53
|
+
if (String(process.env.MUMPIX_POSTINSTALL_AUTH || '1') === '0') return;
|
|
54
|
+
|
|
55
|
+
const token = String(process.env.MUMPIX_AUTH_TOKEN || '').trim();
|
|
56
|
+
if (token) {
|
|
57
|
+
const state = await exchangeTokenForLicense(token, {});
|
|
58
|
+
console.log(`[mumpix] account linked via token. tier=${state.license.tier || '-'} exp=${fmtExpiry(state.license.exp)}`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!isInteractive()) {
|
|
63
|
+
console.log('[mumpix] install complete. auth skipped (non-interactive).');
|
|
64
|
+
console.log('[mumpix] run "mumpix auth login" later to unlock strict/verified. default mode remains eventual.');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log('\n[mumpix] authenticate to unlock your paid durability modes (strict/verified).');
|
|
69
|
+
const answer = await ask('[mumpix] press Enter to continue, or press any other key to install free (eventual mode): ');
|
|
70
|
+
if (answer.length > 0) {
|
|
71
|
+
console.log('[mumpix] auth skipped. default mode is eventual.');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const state = await loginWithDeviceFlow({
|
|
76
|
+
onPrompt: ({ userCode, verifyUrl, expiresInSec, intervalSec }) => {
|
|
77
|
+
const opened = openBrowser(verifyUrl);
|
|
78
|
+
if (opened) {
|
|
79
|
+
console.log(`[mumpix] opened browser: ${verifyUrl}`);
|
|
80
|
+
} else {
|
|
81
|
+
console.log(`[mumpix] open this URL in your browser: ${verifyUrl}`);
|
|
82
|
+
}
|
|
83
|
+
console.log(`[mumpix] enter code: ${userCode}`);
|
|
84
|
+
console.log(`[mumpix] waiting for approval (expires in ${expiresInSec}s, polling ${intervalSec}s)...`);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
console.log(`[mumpix] auth success. tier=${state.license.tier || state.account.tier || '-'} exp=${fmtExpiry(state.license.exp)}`);
|
|
89
|
+
console.log(`[mumpix] saved auth: ${authStatePath()}`);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
const msg = err && err.message ? err.message : 'unknown error';
|
|
92
|
+
console.log(`[mumpix] auth step failed (${msg}).`);
|
|
93
|
+
if (String(msg).includes('404')) {
|
|
94
|
+
console.log('[mumpix] auth endpoints not found on this host. check MUMPIX_AUTH_BASE_URL or server auth routes.');
|
|
95
|
+
}
|
|
96
|
+
console.log('[mumpix] continuing install in eventual mode. run "mumpix auth login" later.');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
run();
|