@raviolelabs/engram-mcp 0.5.3 → 0.5.5
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/dist/cloud/bridge-client.d.ts.map +1 -1
- package/dist/cloud/bridge-client.js +14 -1
- package/dist/cloud/bridge-client.js.map +1 -1
- package/dist/cloud/pairing.d.ts.map +1 -1
- package/dist/cloud/pairing.js +45 -4
- package/dist/cloud/pairing.js.map +1 -1
- package/dist/core/db/index.d.ts.map +1 -1
- package/dist/core/db/index.js +31 -15
- package/dist/core/db/index.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +22 -4
- package/dist/core/logger.js.map +1 -1
- package/dist/core/server/http.d.ts.map +1 -1
- package/dist/core/server/http.js +14 -3
- package/dist/core/server/http.js.map +1 -1
- package/package.json +1 -2
- package/dist/mcp-server/tests/mcp-e2e.test.d.ts +0 -2
- package/dist/mcp-server/tests/mcp-e2e.test.d.ts.map +0 -1
- package/dist/mcp-server/tests/mcp-e2e.test.js +0 -157
- package/dist/mcp-server/tests/mcp-e2e.test.js.map +0 -1
- package/dist/memory/modules/_custom/tests/custom-types.test.d.ts +0 -2
- package/dist/memory/modules/_custom/tests/custom-types.test.d.ts.map +0 -1
- package/dist/memory/modules/_custom/tests/custom-types.test.js +0 -96
- package/dist/memory/modules/_custom/tests/custom-types.test.js.map +0 -1
- package/dist/memory/modules/audio/tests/audio.test.d.ts +0 -2
- package/dist/memory/modules/audio/tests/audio.test.d.ts.map +0 -1
- package/dist/memory/modules/audio/tests/audio.test.js +0 -66
- package/dist/memory/modules/audio/tests/audio.test.js.map +0 -1
- package/dist/memory/modules/audio/tests/transcriber.test.d.ts +0 -2
- package/dist/memory/modules/audio/tests/transcriber.test.d.ts.map +0 -1
- package/dist/memory/modules/audio/tests/transcriber.test.js +0 -27
- package/dist/memory/modules/audio/tests/transcriber.test.js.map +0 -1
- package/dist/memory/modules/conversations/tests/conversations.test.d.ts +0 -2
- package/dist/memory/modules/conversations/tests/conversations.test.d.ts.map +0 -1
- package/dist/memory/modules/conversations/tests/conversations.test.js +0 -75
- package/dist/memory/modules/conversations/tests/conversations.test.js.map +0 -1
- package/dist/memory/modules/drive/tests/drive.test.d.ts +0 -2
- package/dist/memory/modules/drive/tests/drive.test.d.ts.map +0 -1
- package/dist/memory/modules/drive/tests/drive.test.js +0 -66
- package/dist/memory/modules/drive/tests/drive.test.js.map +0 -1
- package/dist/memory/modules/notes/tests/notes.test.d.ts +0 -2
- package/dist/memory/modules/notes/tests/notes.test.d.ts.map +0 -1
- package/dist/memory/modules/notes/tests/notes.test.js +0 -64
- package/dist/memory/modules/notes/tests/notes.test.js.map +0 -1
- package/dist/memory/modules/notion/tests/notion.test.d.ts +0 -2
- package/dist/memory/modules/notion/tests/notion.test.d.ts.map +0 -1
- package/dist/memory/modules/notion/tests/notion.test.js +0 -53
- package/dist/memory/modules/notion/tests/notion.test.js.map +0 -1
- package/dist/memory/modules/obsidian/tests/obsidian.test.d.ts +0 -2
- package/dist/memory/modules/obsidian/tests/obsidian.test.d.ts.map +0 -1
- package/dist/memory/modules/obsidian/tests/obsidian.test.js +0 -72
- package/dist/memory/modules/obsidian/tests/obsidian.test.js.map +0 -1
- package/dist/memory/modules/obsidian/tests/vault-reader.test.d.ts +0 -2
- package/dist/memory/modules/obsidian/tests/vault-reader.test.d.ts.map +0 -1
- package/dist/memory/modules/obsidian/tests/vault-reader.test.js +0 -37
- package/dist/memory/modules/obsidian/tests/vault-reader.test.js.map +0 -1
- package/dist/memory/modules/youtube/tests/channel.test.d.ts +0 -2
- package/dist/memory/modules/youtube/tests/channel.test.d.ts.map +0 -1
- package/dist/memory/modules/youtube/tests/channel.test.js +0 -61
- package/dist/memory/modules/youtube/tests/channel.test.js.map +0 -1
- package/dist/memory/modules/youtube/tests/transcript-fetcher.test.d.ts +0 -2
- package/dist/memory/modules/youtube/tests/transcript-fetcher.test.d.ts.map +0 -1
- package/dist/memory/modules/youtube/tests/transcript-fetcher.test.js +0 -23
- package/dist/memory/modules/youtube/tests/transcript-fetcher.test.js.map +0 -1
- package/dist/memory/modules/youtube/tests/youtube.test.d.ts +0 -2
- package/dist/memory/modules/youtube/tests/youtube.test.d.ts.map +0 -1
- package/dist/memory/modules/youtube/tests/youtube.test.js +0 -61
- package/dist/memory/modules/youtube/tests/youtube.test.js.map +0 -1
- package/dist/sync/tests/apply.test.d.ts +0 -4
- package/dist/sync/tests/apply.test.d.ts.map +0 -1
- package/dist/sync/tests/apply.test.js +0 -117
- package/dist/sync/tests/apply.test.js.map +0 -1
- package/dist/sync/tests/ops-log.test.d.ts +0 -2
- package/dist/sync/tests/ops-log.test.d.ts.map +0 -1
- package/dist/sync/tests/ops-log.test.js +0 -105
- package/dist/sync/tests/ops-log.test.js.map +0 -1
- package/dist/sync/tests/two-device-sync.test.d.ts +0 -2
- package/dist/sync/tests/two-device-sync.test.d.ts.map +0 -1
- package/dist/sync/tests/two-device-sync.test.js +0 -250
- package/dist/sync/tests/two-device-sync.test.js.map +0 -1
- package/dist/tests/chunker.test.d.ts +0 -2
- package/dist/tests/chunker.test.d.ts.map +0 -1
- package/dist/tests/chunker.test.js +0 -24
- package/dist/tests/chunker.test.js.map +0 -1
- package/dist/tests/cloud-auth.test.d.ts +0 -2
- package/dist/tests/cloud-auth.test.d.ts.map +0 -1
- package/dist/tests/cloud-auth.test.js +0 -75
- package/dist/tests/cloud-auth.test.js.map +0 -1
- package/dist/tests/cloud-crypto.test.d.ts +0 -2
- package/dist/tests/cloud-crypto.test.d.ts.map +0 -1
- package/dist/tests/cloud-crypto.test.js +0 -58
- package/dist/tests/cloud-crypto.test.js.map +0 -1
- package/dist/tests/cloud-integration.test.d.ts +0 -2
- package/dist/tests/cloud-integration.test.d.ts.map +0 -1
- package/dist/tests/cloud-integration.test.js +0 -193
- package/dist/tests/cloud-integration.test.js.map +0 -1
- package/dist/tests/cloud-pairing.test.d.ts +0 -2
- package/dist/tests/cloud-pairing.test.d.ts.map +0 -1
- package/dist/tests/cloud-pairing.test.js +0 -86
- package/dist/tests/cloud-pairing.test.js.map +0 -1
- package/dist/tests/cloud-saves-integration.test.d.ts +0 -2
- package/dist/tests/cloud-saves-integration.test.d.ts.map +0 -1
- package/dist/tests/cloud-saves-integration.test.js +0 -92
- package/dist/tests/cloud-saves-integration.test.js.map +0 -1
- package/dist/tests/cloud-transit.test.d.ts +0 -2
- package/dist/tests/cloud-transit.test.d.ts.map +0 -1
- package/dist/tests/cloud-transit.test.js +0 -263
- package/dist/tests/cloud-transit.test.js.map +0 -1
- package/dist/tests/config.test.d.ts +0 -2
- package/dist/tests/config.test.d.ts.map +0 -1
- package/dist/tests/config.test.js +0 -25
- package/dist/tests/config.test.js.map +0 -1
- package/dist/tests/db.test.d.ts +0 -2
- package/dist/tests/db.test.d.ts.map +0 -1
- package/dist/tests/db.test.js +0 -73
- package/dist/tests/db.test.js.map +0 -1
- package/dist/tests/embeddings-providers.test.d.ts +0 -2
- package/dist/tests/embeddings-providers.test.d.ts.map +0 -1
- package/dist/tests/embeddings-providers.test.js +0 -62
- package/dist/tests/embeddings-providers.test.js.map +0 -1
- package/dist/tests/embeddings.test.d.ts +0 -2
- package/dist/tests/embeddings.test.d.ts.map +0 -1
- package/dist/tests/embeddings.test.js +0 -22
- package/dist/tests/embeddings.test.js.map +0 -1
- package/dist/tests/integrations-api.test.d.ts +0 -2
- package/dist/tests/integrations-api.test.d.ts.map +0 -1
- package/dist/tests/integrations-api.test.js +0 -129
- package/dist/tests/integrations-api.test.js.map +0 -1
- package/dist/tests/memory-store.test.d.ts +0 -2
- package/dist/tests/memory-store.test.d.ts.map +0 -1
- package/dist/tests/memory-store.test.js +0 -129
- package/dist/tests/memory-store.test.js.map +0 -1
- package/dist/tests/module-registry.test.d.ts +0 -2
- package/dist/tests/module-registry.test.d.ts.map +0 -1
- package/dist/tests/module-registry.test.js +0 -44
- package/dist/tests/module-registry.test.js.map +0 -1
- package/dist/tests/property-extractor.test.d.ts +0 -2
- package/dist/tests/property-extractor.test.d.ts.map +0 -1
- package/dist/tests/property-extractor.test.js +0 -24
- package/dist/tests/property-extractor.test.js.map +0 -1
- package/dist/tests/public-tools.test.d.ts +0 -2
- package/dist/tests/public-tools.test.d.ts.map +0 -1
- package/dist/tests/public-tools.test.js +0 -286
- package/dist/tests/public-tools.test.js.map +0 -1
- package/dist/tests/reindex.test.d.ts +0 -2
- package/dist/tests/reindex.test.d.ts.map +0 -1
- package/dist/tests/reindex.test.js +0 -58
- package/dist/tests/reindex.test.js.map +0 -1
- package/dist/tests/scope-encryption.test.d.ts +0 -2
- package/dist/tests/scope-encryption.test.d.ts.map +0 -1
- package/dist/tests/scope-encryption.test.js +0 -71
- package/dist/tests/scope-encryption.test.js.map +0 -1
- package/dist/tests/shamir.test.d.ts +0 -2
- package/dist/tests/shamir.test.d.ts.map +0 -1
- package/dist/tests/shamir.test.js +0 -57
- package/dist/tests/shamir.test.js.map +0 -1
- package/dist/tests/source-registry.test.d.ts +0 -2
- package/dist/tests/source-registry.test.d.ts.map +0 -1
- package/dist/tests/source-registry.test.js +0 -58
- package/dist/tests/source-registry.test.js.map +0 -1
- package/dist/tests/types.test.d.ts +0 -2
- package/dist/tests/types.test.d.ts.map +0 -1
- package/dist/tests/types.test.js +0 -26
- package/dist/tests/types.test.js.map +0 -1
- package/dist/tests/vector.test.d.ts +0 -2
- package/dist/tests/vector.test.d.ts.map +0 -1
- package/dist/tests/vector.test.js +0 -61
- package/dist/tests/vector.test.js.map +0 -1
- package/dist/tests/wikilinks.test.d.ts +0 -2
- package/dist/tests/wikilinks.test.d.ts.map +0 -1
- package/dist/tests/wikilinks.test.js +0 -20
- package/dist/tests/wikilinks.test.js.map +0 -1
- package/dist/webapp/tests/api.test.d.ts +0 -2
- package/dist/webapp/tests/api.test.d.ts.map +0 -1
- package/dist/webapp/tests/api.test.js +0 -125
- package/dist/webapp/tests/api.test.js.map +0 -1
- package/dist/webapp/tests/mcp-http.test.d.ts +0 -2
- package/dist/webapp/tests/mcp-http.test.d.ts.map +0 -1
- package/dist/webapp/tests/mcp-http.test.js +0 -47
- package/dist/webapp/tests/mcp-http.test.js.map +0 -1
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
// src/sync/tests/two-device-sync.test.ts
|
|
2
|
-
// Integration test: 2 in-process Device instances simulate bidirectional sync
|
|
3
|
-
// using an in-memory relay bus (no real WebSocket or cloud required).
|
|
4
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
5
|
-
import { mkdtempSync, rmSync } from 'node:fs';
|
|
6
|
-
import { tmpdir } from 'node:os';
|
|
7
|
-
import { join } from 'node:path';
|
|
8
|
-
import { initDb } from '../../db/index.js';
|
|
9
|
-
import { getOrCreateDeviceIdentity } from '../ed25519.js';
|
|
10
|
-
import { OpsLogger } from '../ops-log.js';
|
|
11
|
-
import { ReplayApplier } from '../apply.js';
|
|
12
|
-
const masterKey = Buffer.alloc(32, 0xab); // shared master key (same user)
|
|
13
|
-
class InMemoryRelay {
|
|
14
|
-
handlers = [];
|
|
15
|
-
subscribe(handler) {
|
|
16
|
-
this.handlers.push(handler);
|
|
17
|
-
}
|
|
18
|
-
async broadcast(ops, excludeHandler) {
|
|
19
|
-
for (const handler of this.handlers) {
|
|
20
|
-
if (handler !== excludeHandler) {
|
|
21
|
-
for (const op of ops) {
|
|
22
|
-
await handler(op);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function createDevice(name) {
|
|
29
|
-
const tmpDir = mkdtempSync(join(tmpdir(), `engram-sync-${name}-`));
|
|
30
|
-
const db = initDb(join(tmpDir, 'engram.db'));
|
|
31
|
-
const identity = getOrCreateDeviceIdentity(db);
|
|
32
|
-
const memories = new Map();
|
|
33
|
-
// Stub MemoryStore (tests SQLite writes directly; no LanceDB in unit test)
|
|
34
|
-
const storeStub = {
|
|
35
|
-
async insertWithoutLog(item) {
|
|
36
|
-
const id = item['id'];
|
|
37
|
-
memories.set(id, { ...item });
|
|
38
|
-
db.prepare(`INSERT OR REPLACE INTO memories
|
|
39
|
-
(id, type, source_id, content, content_hash, properties_json,
|
|
40
|
-
wikilinks_json, related_ids_json, embedding_model, created_at)
|
|
41
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, item['type'] ?? 'notes', item['source_id'] ?? '', item['content'] ?? '', item['content_hash'] ?? '', JSON.stringify(item['properties'] ?? {}), '[]', '[]', 'nomic-embed-text', Date.now());
|
|
42
|
-
},
|
|
43
|
-
async deleteVectorIfExists(_id) {
|
|
44
|
-
// no-op in stub
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
const logger = new OpsLogger(db, identity, masterKey);
|
|
48
|
-
const applier = new ReplayApplier(db, storeStub, masterKey);
|
|
49
|
-
return { name, tmpDir, db, identity, logger, applier, memories };
|
|
50
|
-
}
|
|
51
|
-
function teardownDevice(device) {
|
|
52
|
-
device.db.close();
|
|
53
|
-
rmSync(device.tmpDir, { recursive: true });
|
|
54
|
-
}
|
|
55
|
-
// --- Tests ---
|
|
56
|
-
describe('two-device bidirectional sync', () => {
|
|
57
|
-
let alpha;
|
|
58
|
-
let beta;
|
|
59
|
-
let relay;
|
|
60
|
-
beforeEach(() => {
|
|
61
|
-
alpha = createDevice('alpha');
|
|
62
|
-
beta = createDevice('beta');
|
|
63
|
-
relay = new InMemoryRelay();
|
|
64
|
-
// Wire relay: alpha's push → beta's applier, and vice versa
|
|
65
|
-
relay.subscribe(async (op) => {
|
|
66
|
-
await beta.applier.applyOp(op, beta.identity.device_id);
|
|
67
|
-
});
|
|
68
|
-
relay.subscribe(async (op) => {
|
|
69
|
-
await alpha.applier.applyOp(op, alpha.identity.device_id);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
afterEach(() => {
|
|
73
|
-
teardownDevice(alpha);
|
|
74
|
-
teardownDevice(beta);
|
|
75
|
-
});
|
|
76
|
-
it('alpha adds a memory, beta receives it', async () => {
|
|
77
|
-
const memId = `mem-${Date.now()}`;
|
|
78
|
-
const item = {
|
|
79
|
-
id: memId,
|
|
80
|
-
type: 'notes',
|
|
81
|
-
source_id: 'manual',
|
|
82
|
-
content: 'hello from alpha',
|
|
83
|
-
content_hash: 'hash-alpha-1',
|
|
84
|
-
properties: { title: 'Alpha note', tags: ['sync'] },
|
|
85
|
-
};
|
|
86
|
-
// Alpha: local write → log op
|
|
87
|
-
const opId = alpha.logger.append('add_memory', memId, { item });
|
|
88
|
-
// Push to relay
|
|
89
|
-
const pending = alpha.logger.listPending();
|
|
90
|
-
expect(pending).toHaveLength(1);
|
|
91
|
-
await relay.broadcast(pending, undefined);
|
|
92
|
-
alpha.logger.markSent(pending.map((p) => p.op_id));
|
|
93
|
-
// Beta should now have the memory in SQLite
|
|
94
|
-
const row = beta.db.prepare(`SELECT id, content FROM memories WHERE id = ?`).get(memId);
|
|
95
|
-
expect(row).toBeDefined();
|
|
96
|
-
expect(row?.id).toBe(memId);
|
|
97
|
-
expect(row?.content).toBe('hello from alpha');
|
|
98
|
-
expect(opId).toBeTruthy();
|
|
99
|
-
});
|
|
100
|
-
it('beta adds a memory, alpha receives it', async () => {
|
|
101
|
-
const memId = `mem-beta-${Date.now()}`;
|
|
102
|
-
const item = {
|
|
103
|
-
id: memId,
|
|
104
|
-
type: 'notes',
|
|
105
|
-
source_id: 'manual',
|
|
106
|
-
content: 'hello from beta',
|
|
107
|
-
content_hash: 'hash-beta-1',
|
|
108
|
-
properties: { title: 'Beta note', tags: ['sync'] },
|
|
109
|
-
};
|
|
110
|
-
beta.logger.append('add_memory', memId, { item });
|
|
111
|
-
const pending = beta.logger.listPending();
|
|
112
|
-
await relay.broadcast(pending);
|
|
113
|
-
beta.logger.markSent(pending.map((p) => p.op_id));
|
|
114
|
-
const row = alpha.db.prepare(`SELECT id, content FROM memories WHERE id = ?`).get(memId);
|
|
115
|
-
expect(row).toBeDefined();
|
|
116
|
-
expect(row?.content).toBe('hello from beta');
|
|
117
|
-
});
|
|
118
|
-
it('concurrent property updates: LWW + tag union', async () => {
|
|
119
|
-
const memId = `mem-concurrent-${Date.now()}`;
|
|
120
|
-
const item = {
|
|
121
|
-
id: memId,
|
|
122
|
-
type: 'notes',
|
|
123
|
-
source_id: 'manual',
|
|
124
|
-
content: 'shared',
|
|
125
|
-
content_hash: 'hash-shared-1',
|
|
126
|
-
properties: { title: 'original', tags: ['base'] },
|
|
127
|
-
};
|
|
128
|
-
// Both devices know about the memory (simulate initial sync)
|
|
129
|
-
for (const dev of [alpha, beta]) {
|
|
130
|
-
dev.db
|
|
131
|
-
.prepare(`INSERT OR REPLACE INTO memories
|
|
132
|
-
(id, type, source_id, content, content_hash, properties_json,
|
|
133
|
-
wikilinks_json, related_ids_json, embedding_model, created_at)
|
|
134
|
-
VALUES (?, ?, ?, ?, ?, ?, '[]', '[]', 'nomic-embed-text', ?)`)
|
|
135
|
-
.run(memId, item.type, item.source_id, item.content, item.content_hash, JSON.stringify(item.properties), Date.now());
|
|
136
|
-
}
|
|
137
|
-
// Alpha: log + apply locally (simulates MemoryStore write-through)
|
|
138
|
-
alpha.logger.append('update_properties', memId, {
|
|
139
|
-
memory_id: memId,
|
|
140
|
-
delta: { title: 'alpha-title', tags: ['alpha-tag'] },
|
|
141
|
-
});
|
|
142
|
-
// Apply alpha's own write directly (simulates MemoryStore.setProperties)
|
|
143
|
-
alpha.db
|
|
144
|
-
.prepare(`UPDATE memories SET properties_json = ? WHERE id = ?`)
|
|
145
|
-
.run(JSON.stringify({ title: 'alpha-title', tags: ['base', 'alpha-tag'] }), memId);
|
|
146
|
-
// Beta: log + apply locally (simulates MemoryStore write-through)
|
|
147
|
-
beta.logger.append('update_properties', memId, {
|
|
148
|
-
memory_id: memId,
|
|
149
|
-
delta: { title: 'beta-title', tags: ['beta-tag'] },
|
|
150
|
-
});
|
|
151
|
-
// Apply beta's own write directly (simulates MemoryStore.setProperties)
|
|
152
|
-
beta.db
|
|
153
|
-
.prepare(`UPDATE memories SET properties_json = ? WHERE id = ?`)
|
|
154
|
-
.run(JSON.stringify({ title: 'beta-title', tags: ['base', 'beta-tag'] }), memId);
|
|
155
|
-
// Cross-broadcast
|
|
156
|
-
const alphaPending = alpha.logger.listPending();
|
|
157
|
-
const betaPending = beta.logger.listPending();
|
|
158
|
-
await relay.broadcast(alphaPending);
|
|
159
|
-
await relay.broadcast(betaPending);
|
|
160
|
-
alpha.logger.markSent(alphaPending.map((p) => p.op_id));
|
|
161
|
-
beta.logger.markSent(betaPending.map((p) => p.op_id));
|
|
162
|
-
// Both devices: tags should be union containing both devices' tags
|
|
163
|
-
const alphaRow = alpha.db
|
|
164
|
-
.prepare(`SELECT properties_json FROM memories WHERE id = ?`)
|
|
165
|
-
.get(memId);
|
|
166
|
-
const betaRow = beta.db
|
|
167
|
-
.prepare(`SELECT properties_json FROM memories WHERE id = ?`)
|
|
168
|
-
.get(memId);
|
|
169
|
-
const alphaProps = JSON.parse(alphaRow.properties_json);
|
|
170
|
-
const betaProps = JSON.parse(betaRow.properties_json);
|
|
171
|
-
// Tags must be union (may contain all three)
|
|
172
|
-
expect(alphaProps.tags).toEqual(expect.arrayContaining(['alpha-tag']));
|
|
173
|
-
expect(alphaProps.tags).toEqual(expect.arrayContaining(['beta-tag']));
|
|
174
|
-
expect(betaProps.tags).toEqual(expect.arrayContaining(['alpha-tag']));
|
|
175
|
-
expect(betaProps.tags).toEqual(expect.arrayContaining(['beta-tag']));
|
|
176
|
-
});
|
|
177
|
-
it('delete on alpha, beta receives tombstone', async () => {
|
|
178
|
-
const memId = `mem-del-${Date.now()}`;
|
|
179
|
-
// Insert on both sides
|
|
180
|
-
for (const dev of [alpha, beta]) {
|
|
181
|
-
dev.db
|
|
182
|
-
.prepare(`INSERT OR REPLACE INTO memories
|
|
183
|
-
(id, type, source_id, content, content_hash, properties_json,
|
|
184
|
-
wikilinks_json, related_ids_json, embedding_model, created_at)
|
|
185
|
-
VALUES (?, 'notes', 'manual', 'to be deleted', 'hash-del', '{}', '[]', '[]', 'nomic', ?)`)
|
|
186
|
-
.run(memId, Date.now());
|
|
187
|
-
}
|
|
188
|
-
// Alpha deletes
|
|
189
|
-
alpha.logger.append('delete_memory', memId, { memory_id: memId });
|
|
190
|
-
const pending = alpha.logger.listPending();
|
|
191
|
-
await relay.broadcast(pending);
|
|
192
|
-
alpha.logger.markSent(pending.map((p) => p.op_id));
|
|
193
|
-
// Beta: memory should be gone from SQLite, tombstone should exist
|
|
194
|
-
const betaMemory = beta.db.prepare(`SELECT id FROM memories WHERE id = ?`).get(memId);
|
|
195
|
-
const betaTomb = beta.db
|
|
196
|
-
.prepare(`SELECT memory_id FROM tombstones WHERE memory_id = ?`)
|
|
197
|
-
.get(memId);
|
|
198
|
-
expect(betaMemory).toBeUndefined();
|
|
199
|
-
expect(betaTomb).toBeDefined();
|
|
200
|
-
expect(betaTomb?.memory_id).toBe(memId);
|
|
201
|
-
});
|
|
202
|
-
it('dedup: same content_hash from both devices is kept only once', async () => {
|
|
203
|
-
const memId = `mem-dedup-${Date.now()}`;
|
|
204
|
-
const item = {
|
|
205
|
-
id: memId,
|
|
206
|
-
type: 'notes',
|
|
207
|
-
source_id: 'manual',
|
|
208
|
-
content: 'same content',
|
|
209
|
-
content_hash: 'hash-same-content',
|
|
210
|
-
properties: { title: 'shared' },
|
|
211
|
-
};
|
|
212
|
-
// Both devices try to add the same item independently
|
|
213
|
-
alpha.logger.append('add_memory', memId, { item });
|
|
214
|
-
beta.logger.append('add_memory', memId, { item });
|
|
215
|
-
const alphaPending = alpha.logger.listPending();
|
|
216
|
-
const betaPending = beta.logger.listPending();
|
|
217
|
-
// Alpha's op goes to beta first
|
|
218
|
-
await relay.broadcast(alphaPending);
|
|
219
|
-
alpha.logger.markSent(alphaPending.map((p) => p.op_id));
|
|
220
|
-
// Beta's op goes to alpha (already has it — dedup should kick in)
|
|
221
|
-
await relay.broadcast(betaPending);
|
|
222
|
-
beta.logger.markSent(betaPending.map((p) => p.op_id));
|
|
223
|
-
// Alpha: only 1 row with that content_hash
|
|
224
|
-
const alphaCount = alpha.db
|
|
225
|
-
.prepare(`SELECT COUNT(*) as c FROM memories WHERE content_hash = 'hash-same-content'`)
|
|
226
|
-
.get().c;
|
|
227
|
-
expect(alphaCount).toBeLessThanOrEqual(1);
|
|
228
|
-
});
|
|
229
|
-
it('ops not from this device are stored and marked applied', async () => {
|
|
230
|
-
const memId = `mem-track-${Date.now()}`;
|
|
231
|
-
const item = {
|
|
232
|
-
id: memId,
|
|
233
|
-
type: 'notes',
|
|
234
|
-
source_id: 'manual',
|
|
235
|
-
content: 'from beta for tracking',
|
|
236
|
-
content_hash: 'hash-track-1',
|
|
237
|
-
properties: { title: 'tracked' },
|
|
238
|
-
};
|
|
239
|
-
beta.logger.append('add_memory', memId, { item });
|
|
240
|
-
const pending = beta.logger.listPending();
|
|
241
|
-
await relay.broadcast(pending);
|
|
242
|
-
// Alpha: op should be in ops_log with applied=1
|
|
243
|
-
const alphaOp = alpha.db
|
|
244
|
-
.prepare(`SELECT applied FROM ops_log WHERE op_id = ?`)
|
|
245
|
-
.get(pending[0].op_id);
|
|
246
|
-
expect(alphaOp).toBeDefined();
|
|
247
|
-
expect(alphaOp?.applied).toBe(1);
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
//# sourceMappingURL=two-device-sync.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"two-device-sync.test.js","sourceRoot":"","sources":["../../../src/sync/tests/two-device-sync.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chunker.test.d.ts","sourceRoot":"","sources":["../../src/tests/chunker.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// src/tests/chunker.test.ts
|
|
2
|
-
import { describe, it, expect } from 'vitest';
|
|
3
|
-
import { chunkText } from '../memory/core/chunker.js';
|
|
4
|
-
describe('chunker', () => {
|
|
5
|
-
it('returns a single chunk for short content', () => {
|
|
6
|
-
const chunks = chunkText('Hello world');
|
|
7
|
-
expect(chunks).toHaveLength(1);
|
|
8
|
-
expect(chunks[0]).toBe('Hello world');
|
|
9
|
-
});
|
|
10
|
-
it('splits long content into multiple chunks by paragraph', () => {
|
|
11
|
-
const longText = 'Para one.\n\n' + 'Para two has more content. '.repeat(200);
|
|
12
|
-
const chunks = chunkText(longText, { maxChars: 500 });
|
|
13
|
-
expect(chunks.length).toBeGreaterThan(1);
|
|
14
|
-
});
|
|
15
|
-
it('preserves all content when joining chunks (modulo overlap)', () => {
|
|
16
|
-
const text = 'A. B. C. D. E.\n\nF. G. H.';
|
|
17
|
-
const chunks = chunkText(text, { maxChars: 10 });
|
|
18
|
-
// Every word from the source should appear in at least one chunk
|
|
19
|
-
for (const word of ['A.', 'B.', 'C.', 'D.', 'E.', 'F.', 'G.', 'H.']) {
|
|
20
|
-
expect(chunks.some((c) => c.includes(word))).toBe(true);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
//# sourceMappingURL=chunker.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chunker.test.js","sourceRoot":"","sources":["../../src/tests/chunker.test.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAEtD,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,QAAQ,GAAG,eAAe,GAAG,6BAA6B,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7E,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,IAAI,GAAG,4BAA4B,CAAC;QAC1C,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACjD,iEAAiE;QACjE,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACpE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-auth.test.d.ts","sourceRoot":"","sources":["../../src/tests/cloud-auth.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { initDb, closeDb } from '../db/index.js';
|
|
6
|
-
import { saveTokens, loadTokens, clearTokens, isPaired, parseJwtExpiry, getApiKey, } from '../cloud/auth.js';
|
|
7
|
-
// Minimal JWT with exp claim — not a real signed JWT but parseJwtExpiry only
|
|
8
|
-
// reads the payload, so this is fine for unit tests.
|
|
9
|
-
function makeTestJwt(expUnix) {
|
|
10
|
-
const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
|
|
11
|
-
const payload = Buffer.from(JSON.stringify({ sub: 'user_test', exp: expUnix })).toString('base64url');
|
|
12
|
-
return `${header}.${payload}.fakesig`;
|
|
13
|
-
}
|
|
14
|
-
describe('cloud/auth', () => {
|
|
15
|
-
let tmpDir;
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'engram-auth-'));
|
|
18
|
-
initDb(tmpDir);
|
|
19
|
-
});
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
closeDb();
|
|
22
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
23
|
-
});
|
|
24
|
-
it('isPaired() returns false before any save', () => {
|
|
25
|
-
expect(isPaired()).toBe(false);
|
|
26
|
-
});
|
|
27
|
-
it('saveTokens + loadTokens round-trips all fields', () => {
|
|
28
|
-
const expMs = Date.now() + 3600_000;
|
|
29
|
-
const jwt = makeTestJwt(Math.floor(expMs / 1000));
|
|
30
|
-
saveTokens({ jwt, refreshToken: 'rt-abc', apiKey: 'ak-xyz', expiresAt: expMs });
|
|
31
|
-
expect(isPaired()).toBe(true);
|
|
32
|
-
const loaded = loadTokens();
|
|
33
|
-
expect(loaded).not.toBeNull();
|
|
34
|
-
expect(loaded.jwt).toBe(jwt);
|
|
35
|
-
expect(loaded.refreshToken).toBe('rt-abc');
|
|
36
|
-
expect(loaded.apiKey).toBe('ak-xyz');
|
|
37
|
-
expect(loaded.expiresAt).toBe(expMs);
|
|
38
|
-
});
|
|
39
|
-
it('saveTokens is idempotent — overwrites on second call', () => {
|
|
40
|
-
const exp1 = Date.now() + 1000;
|
|
41
|
-
const exp2 = Date.now() + 9999;
|
|
42
|
-
saveTokens({ jwt: 'jwt1', refreshToken: 'rt1', apiKey: 'ak1', expiresAt: exp1 });
|
|
43
|
-
saveTokens({ jwt: 'jwt2', refreshToken: 'rt2', apiKey: 'ak2', expiresAt: exp2 });
|
|
44
|
-
const t = loadTokens();
|
|
45
|
-
expect(t.jwt).toBe('jwt2');
|
|
46
|
-
expect(t.apiKey).toBe('ak2');
|
|
47
|
-
});
|
|
48
|
-
it('clearTokens removes the row', () => {
|
|
49
|
-
saveTokens({ jwt: 'j', refreshToken: 'r', apiKey: 'a', expiresAt: 1 });
|
|
50
|
-
clearTokens();
|
|
51
|
-
expect(isPaired()).toBe(false);
|
|
52
|
-
expect(loadTokens()).toBeNull();
|
|
53
|
-
});
|
|
54
|
-
it('parseJwtExpiry extracts exp in ms', () => {
|
|
55
|
-
const expSec = Math.floor(Date.now() / 1000) + 3600;
|
|
56
|
-
const jwt = makeTestJwt(expSec);
|
|
57
|
-
expect(parseJwtExpiry(jwt)).toBe(expSec * 1000);
|
|
58
|
-
});
|
|
59
|
-
it('parseJwtExpiry throws on malformed JWT', () => {
|
|
60
|
-
expect(() => parseJwtExpiry('notajwt')).toThrow(/Malformed/);
|
|
61
|
-
});
|
|
62
|
-
it('getApiKey throws when not paired', () => {
|
|
63
|
-
expect(() => getApiKey()).toThrow(/Not paired/);
|
|
64
|
-
});
|
|
65
|
-
it('getApiKey returns stored key when paired', () => {
|
|
66
|
-
saveTokens({
|
|
67
|
-
jwt: makeTestJwt(Math.floor(Date.now() / 1000) + 3600),
|
|
68
|
-
refreshToken: 'rt',
|
|
69
|
-
apiKey: 'my-api-key',
|
|
70
|
-
expiresAt: Date.now() + 3600_000,
|
|
71
|
-
});
|
|
72
|
-
expect(getApiKey()).toBe('my-api-key');
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
//# sourceMappingURL=cloud-auth.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-auth.test.js","sourceRoot":"","sources":["../../src/tests/cloud-auth.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-crypto.test.d.ts","sourceRoot":"","sources":["../../src/tests/cloud-crypto.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { generateMasterKeySalt, deriveMasterKey, encryptBlob, decryptBlob, generateEphemeralKeypair, deriveSessionKey, } from '../cloud/crypto.js';
|
|
3
|
-
describe('cloud/crypto', () => {
|
|
4
|
-
it('generateMasterKeySalt returns 64-char hex string (32 bytes)', async () => {
|
|
5
|
-
const salt = await generateMasterKeySalt();
|
|
6
|
-
expect(typeof salt).toBe('string');
|
|
7
|
-
expect(salt).toHaveLength(64);
|
|
8
|
-
expect(/^[0-9a-f]+$/i.test(salt)).toBe(true);
|
|
9
|
-
});
|
|
10
|
-
it('deriveMasterKey produces 32-byte key deterministically', async () => {
|
|
11
|
-
const salt = await generateMasterKeySalt();
|
|
12
|
-
const key1 = await deriveMasterKey('correct horse battery staple', salt);
|
|
13
|
-
const key2 = await deriveMasterKey('correct horse battery staple', salt);
|
|
14
|
-
expect(key1.length).toBe(32);
|
|
15
|
-
expect(Buffer.from(key1).toString('hex')).toBe(Buffer.from(key2).toString('hex'));
|
|
16
|
-
});
|
|
17
|
-
it('deriveMasterKey differs for different passphrases', async () => {
|
|
18
|
-
const salt = await generateMasterKeySalt();
|
|
19
|
-
const k1 = await deriveMasterKey('passA', salt);
|
|
20
|
-
const k2 = await deriveMasterKey('passB', salt);
|
|
21
|
-
expect(Buffer.from(k1).toString('hex')).not.toBe(Buffer.from(k2).toString('hex'));
|
|
22
|
-
});
|
|
23
|
-
it('encryptBlob + decryptBlob round-trips cleanly', async () => {
|
|
24
|
-
const salt = await generateMasterKeySalt();
|
|
25
|
-
const key = await deriveMasterKey('test passphrase', salt);
|
|
26
|
-
const plaintext = new TextEncoder().encode('Hello, Engram transit!');
|
|
27
|
-
const wire = await encryptBlob(plaintext, key);
|
|
28
|
-
// wire length = 24 (nonce) + plaintext + 16 (Poly1305 MAC)
|
|
29
|
-
expect(wire.length).toBe(24 + plaintext.length + 16);
|
|
30
|
-
const recovered = await decryptBlob(wire, key);
|
|
31
|
-
expect(new TextDecoder().decode(recovered)).toBe('Hello, Engram transit!');
|
|
32
|
-
});
|
|
33
|
-
it('decryptBlob throws on wrong key', async () => {
|
|
34
|
-
const salt = await generateMasterKeySalt();
|
|
35
|
-
const keyGood = await deriveMasterKey('right', salt);
|
|
36
|
-
const keyBad = await deriveMasterKey('wrong', salt);
|
|
37
|
-
const wire = await encryptBlob(new TextEncoder().encode('secret'), keyGood);
|
|
38
|
-
await expect(decryptBlob(wire, keyBad)).rejects.toThrow(/[Dd]ecryption failed/);
|
|
39
|
-
});
|
|
40
|
-
it('decryptBlob throws on truncated input', async () => {
|
|
41
|
-
const salt = await generateMasterKeySalt();
|
|
42
|
-
const key = await deriveMasterKey('pass', salt);
|
|
43
|
-
await expect(decryptBlob(new Uint8Array(10), key)).rejects.toThrow(/too short/);
|
|
44
|
-
});
|
|
45
|
-
it('generateEphemeralKeypair returns valid 32-byte keys', async () => {
|
|
46
|
-
const { publicKey, privateKey } = await generateEphemeralKeypair();
|
|
47
|
-
expect(publicKey.length).toBe(32);
|
|
48
|
-
expect(privateKey.length).toBe(32);
|
|
49
|
-
});
|
|
50
|
-
it('deriveSessionKey is commutative (DH)', async () => {
|
|
51
|
-
const alice = await generateEphemeralKeypair();
|
|
52
|
-
const bob = await generateEphemeralKeypair();
|
|
53
|
-
const s1 = await deriveSessionKey(alice.privateKey, bob.publicKey);
|
|
54
|
-
const s2 = await deriveSessionKey(bob.privateKey, alice.publicKey);
|
|
55
|
-
expect(Buffer.from(s1).toString('hex')).toBe(Buffer.from(s2).toString('hex'));
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
//# sourceMappingURL=cloud-crypto.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-crypto.test.js","sourceRoot":"","sources":["../../src/tests/cloud-crypto.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-integration.test.d.ts","sourceRoot":"","sources":["../../src/tests/cloud-integration.test.ts"],"names":[],"mappings":""}
|