@melandlabs/memory-store 0.2.6 → 0.3.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.
@@ -35,13 +35,14 @@ function isRawMessageChromaEnabled() {
35
35
  // src/storage/sqlite-raw-message-store.ts
36
36
  var manager = null;
37
37
  var DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
38
- function resolveSQLiteRawMessageDbPath() {
38
+ function resolveSQLiteRawMessageDbPath(dbPath) {
39
+ if (dbPath && dbPath.length > 0) return dbPath;
39
40
  const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
40
41
  return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
41
42
  }
42
- async function getSQLiteRawMessageManager(_env) {
43
+ async function getSQLiteRawMessageManager(options = {}) {
43
44
  if (!manager) {
44
- const dbPath = resolveSQLiteRawMessageDbPath();
45
+ const dbPath = resolveSQLiteRawMessageDbPath(options.dbPath);
45
46
  mkdirSync(dirname(dbPath), { recursive: true });
46
47
  manager = new SQLiteRawMessageManager({
47
48
  dbPath,
@@ -60,7 +61,7 @@ async function closeSQLiteRawMessageManager() {
60
61
  }
61
62
 
62
63
  // src/storage/raw-message-store.ts
63
- function resolveBackend(env) {
64
+ function resolveBackend(_env) {
64
65
  const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
65
66
  if (explicit === "postgres") return "postgres";
66
67
  return "sqlite";
@@ -87,7 +88,9 @@ function createRawMessageStore(options = {}) {
87
88
  }
88
89
  return pg;
89
90
  }
90
- return await getSQLiteRawMessageManager();
91
+ return await getSQLiteRawMessageManager({
92
+ dbPath: options.dbPath
93
+ });
91
94
  },
92
95
  async close() {
93
96
  await closeSQLiteRawMessageManager();
@@ -278,6 +281,9 @@ async function buildUnified(args) {
278
281
  } else if (args.memoryBackend === "chroma") {
279
282
  if (!args.chromaUrl)
280
283
  throw new Error("--memory-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)");
284
+ if (!aiRag) {
285
+ throw new Error("ai-rag modules not loaded");
286
+ }
281
287
  const store = new aiRag.ChromaVectorStore({
282
288
  url: args.chromaUrl,
283
289
  collectionName: "opencontext_raw_messages"
@@ -316,6 +322,9 @@ async function buildUnified(args) {
316
322
  throw new Error("--insights-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)");
317
323
  if (!unified.embedQuery)
318
324
  throw new Error("--insights-backend=chroma requires --embedding-provider local|openrouter");
325
+ if (!aiRag) {
326
+ throw new Error("ai-rag modules not loaded");
327
+ }
319
328
  const store = new aiRag.ChromaVectorStore({
320
329
  url: args.chromaUrl,
321
330
  collectionName: args.insightsCollection
@@ -333,6 +342,9 @@ async function buildUnified(args) {
333
342
  throw new Error("--knowledge-backend=chroma requires --chroma-url <url> (or CHROMA_URL env)");
334
343
  if (!unified.embedQuery)
335
344
  throw new Error("--knowledge-backend=chroma requires --embedding-provider local|openrouter");
345
+ if (!aiRag) {
346
+ throw new Error("ai-rag modules not loaded");
347
+ }
336
348
  const store = new aiRag.ChromaVectorStore({
337
349
  url: args.chromaUrl,
338
350
  collectionName: args.knowledgeCollection
@@ -1,4 +1,4 @@
1
- import { b as MemoryStoreEnv } from '../config-BYfTzG3h.js';
1
+ import { i as MemoryStoreEnv } from '../config-2Q092MUz.js';
2
2
 
3
3
  /**
4
4
  * Lazy registration slot for the host's Postgres-backed raw message
@@ -1,5 +1,5 @@
1
1
  import { RawMessageStorageManager } from '@melandlabs/indexeddb/storage';
2
- import { b as MemoryStoreEnv, M as MemoryStoreConfig } from '../config-BYfTzG3h.js';
2
+ import { i as MemoryStoreEnv, M as MemoryStoreConfig } from '../config-2Q092MUz.js';
3
3
 
4
4
  /**
5
5
  * Top-level raw-message store facade.
@@ -45,6 +45,8 @@ type RawMessageStorageManagerWithSearch = RawMessageStorageManager & {
45
45
  };
46
46
  interface CreateRawMessageStoreOptions {
47
47
  env?: MemoryStoreEnv;
48
+ /** Custom SQLite DB file path. Only used by the SQLite backend. */
49
+ dbPath?: string;
48
50
  }
49
51
  interface RawMessageStore {
50
52
  getManager(): Promise<RawMessageStorageManagerWithSearch>;
@@ -34,13 +34,14 @@ function isRawMessageChromaEnabled() {
34
34
  // src/storage/sqlite-raw-message-store.ts
35
35
  var manager = null;
36
36
  var DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
37
- function resolveSQLiteRawMessageDbPath() {
37
+ function resolveSQLiteRawMessageDbPath(dbPath) {
38
+ if (dbPath && dbPath.length > 0) return dbPath;
38
39
  const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
39
40
  return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
40
41
  }
41
- async function getSQLiteRawMessageManager(_env) {
42
+ async function getSQLiteRawMessageManager(options = {}) {
42
43
  if (!manager) {
43
- const dbPath = resolveSQLiteRawMessageDbPath();
44
+ const dbPath = resolveSQLiteRawMessageDbPath(options.dbPath);
44
45
  mkdirSync(dirname(dbPath), { recursive: true });
45
46
  manager = new SQLiteRawMessageManager({
46
47
  dbPath,
@@ -59,7 +60,7 @@ async function closeSQLiteRawMessageManager() {
59
60
  }
60
61
 
61
62
  // src/storage/raw-message-store.ts
62
- function resolveBackend(env) {
63
+ function resolveBackend(_env) {
63
64
  const explicit = process.env.OPENCONTEXT_MEMORY_STORE_BACKEND?.trim().toLowerCase();
64
65
  if (explicit === "postgres") return "postgres";
65
66
  return "sqlite";
@@ -86,7 +87,9 @@ function createRawMessageStore(options = {}) {
86
87
  }
87
88
  return pg;
88
89
  }
89
- return await getSQLiteRawMessageManager();
90
+ return await getSQLiteRawMessageManager({
91
+ dbPath: options.dbPath
92
+ });
90
93
  },
91
94
  async close() {
92
95
  await closeSQLiteRawMessageManager();
@@ -95,26 +98,34 @@ function createRawMessageStore(options = {}) {
95
98
  }
96
99
  var moduleStore = null;
97
100
  var moduleConfig = null;
101
+ function resolveDbPath(config) {
102
+ if (!config) return void 0;
103
+ if (config.dbPath) return config.dbPath;
104
+ if (config.db && typeof config.db === "object" && "path" in config.db) {
105
+ return config.db.path;
106
+ }
107
+ return void 0;
108
+ }
98
109
  function configureRawMessageStore(config) {
99
110
  moduleConfig = config;
100
- moduleStore = createRawMessageStore({ env: config.env });
111
+ moduleStore = createRawMessageStore({ env: config.env, dbPath: resolveDbPath(config) });
101
112
  return moduleStore;
102
113
  }
103
114
  function getRawMessageStorageBackend() {
104
115
  if (!moduleStore) {
105
- moduleStore = createRawMessageStore({ env: moduleConfig?.env });
116
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env, dbPath: resolveDbPath(moduleConfig) });
106
117
  }
107
118
  return moduleStore.getBackend();
108
119
  }
109
120
  function isRawMessageStorageAvailable() {
110
121
  if (!moduleStore) {
111
- moduleStore = createRawMessageStore({ env: moduleConfig?.env });
122
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env, dbPath: resolveDbPath(moduleConfig) });
112
123
  }
113
124
  return moduleStore.isAvailable();
114
125
  }
115
126
  async function getRawMessageManager() {
116
127
  if (!moduleStore) {
117
- moduleStore = createRawMessageStore({ env: moduleConfig?.env });
128
+ moduleStore = createRawMessageStore({ env: moduleConfig?.env, dbPath: resolveDbPath(moduleConfig) });
118
129
  }
119
130
  return moduleStore.getManager();
120
131
  }
@@ -1,5 +1,5 @@
1
1
  import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
2
- import { b as MemoryStoreEnv } from '../config-BYfTzG3h.js';
2
+ import { i as MemoryStoreEnv } from '../config-2Q092MUz.js';
3
3
 
4
4
  /**
5
5
  * SQLite-backed raw message store.
@@ -18,13 +18,16 @@ import { b as MemoryStoreEnv } from '../config-BYfTzG3h.js';
18
18
  * Resolve the SQLite DB file path from env vars. Exposed so other storage
19
19
  * layers (vector index) can stay in sync with the same default.
20
20
  */
21
- declare function resolveSQLiteRawMessageDbPath(): string;
21
+ declare function resolveSQLiteRawMessageDbPath(dbPath?: string): string;
22
22
  /**
23
23
  * Local SQLite is the default. Every host (Tauri, server, CLI, tests) can
24
24
  * open the manager; the only failure mode is filesystem write permission.
25
25
  */
26
26
  declare function isSQLiteRawMessageStorageAvailable(_env?: MemoryStoreEnv): boolean;
27
- declare function getSQLiteRawMessageManager(_env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager>;
27
+ declare function getSQLiteRawMessageManager(options?: {
28
+ env?: MemoryStoreEnv;
29
+ dbPath?: string;
30
+ }): Promise<SQLiteRawMessageManager>;
28
31
  declare function closeSQLiteRawMessageManager(): Promise<void>;
29
32
  /**
30
33
  * Test-only: reset the singleton. Used by vitest between test cases.
@@ -27,16 +27,17 @@ function isRawMessageChromaEnabled() {
27
27
  // src/storage/sqlite-raw-message-store.ts
28
28
  var manager = null;
29
29
  var DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
30
- function resolveSQLiteRawMessageDbPath() {
30
+ function resolveSQLiteRawMessageDbPath(dbPath) {
31
+ if (dbPath && dbPath.length > 0) return dbPath;
31
32
  const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
32
33
  return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
33
34
  }
34
35
  function isSQLiteRawMessageStorageAvailable(_env) {
35
36
  return true;
36
37
  }
37
- async function getSQLiteRawMessageManager(_env) {
38
+ async function getSQLiteRawMessageManager(options = {}) {
38
39
  if (!manager) {
39
- const dbPath = resolveSQLiteRawMessageDbPath();
40
+ const dbPath = resolveSQLiteRawMessageDbPath(options.dbPath);
40
41
  mkdirSync(dirname(dbPath), { recursive: true });
41
42
  manager = new SQLiteRawMessageManager({
42
43
  dbPath,
@@ -1,5 +1,5 @@
1
1
  import { VectorSearchResult } from '@melandlabs/rag/vector-service';
2
- import { b as MemoryStoreEnv } from '../config-BYfTzG3h.js';
2
+ import { i as MemoryStoreEnv } from '../config-2Q092MUz.js';
3
3
 
4
4
  /**
5
5
  * SQLite-vec-backed raw-message + insight vector index.
@@ -9,7 +9,7 @@ import '@melandlabs/rag';
9
9
 
10
10
  // src/storage/sqlite-raw-message-store.ts
11
11
  var DEFAULT_SQLITE_PATH = join(homedir(), ".opencontext", "memory", "store.db");
12
- function resolveSQLiteRawMessageDbPath() {
12
+ function resolveSQLiteRawMessageDbPath(dbPath) {
13
13
  const fromEnv = process.env.MEMORY_STORE_DB_PATH?.trim();
14
14
  return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_SQLITE_PATH;
15
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melandlabs/memory-store",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -60,14 +60,14 @@
60
60
  "@modelcontextprotocol/sdk": "^1.25.3",
61
61
  "hono": "^4.6.14",
62
62
  "zod": "^4.3.6",
63
- "@melandlabs/shared": "0.2.0",
64
- "@melandlabs/sqlite": "0.2.0",
65
- "@melandlabs/ai": "0.2.0",
66
- "@melandlabs/rag": "0.2.0"
63
+ "@melandlabs/ai": "0.3.0",
64
+ "@melandlabs/sqlite": "0.3.0",
65
+ "@melandlabs/rag": "0.2.2",
66
+ "@melandlabs/shared": "0.3.0"
67
67
  },
68
68
  "peerDependencies": {
69
- "@melandlabs/ai-rag": "0.2.2",
70
- "@melandlabs/indexeddb": "0.2.0"
69
+ "@melandlabs/ai-rag": "0.2.4",
70
+ "@melandlabs/indexeddb": "0.3.0"
71
71
  },
72
72
  "peerDependenciesMeta": {
73
73
  "@melandlabs/ai-rag": {
@@ -80,8 +80,8 @@
80
80
  "devDependencies": {
81
81
  "@types/node": "^22.13.10",
82
82
  "typescript": "^5.6.3",
83
- "@melandlabs/ai-rag": "0.2.2",
84
- "@melandlabs/config": "0.2.0"
83
+ "@melandlabs/config": "0.3.0",
84
+ "@melandlabs/ai-rag": "0.2.4"
85
85
  },
86
86
  "scripts": {
87
87
  "build": "tsup",
@@ -89,6 +89,7 @@
89
89
  "lint": "biome check .",
90
90
  "lint:fix": "biome check --write .",
91
91
  "test": "vitest run",
92
+ "test:integration": "vitest run --config vitest.integration.config.ts",
92
93
  "test:watch": "vitest"
93
94
  }
94
95
  }
@@ -1,170 +0,0 @@
1
- /**
2
- * Memory store configuration — injected by the host application.
3
- *
4
- * The memory-store package is intentionally decoupled from the
5
- * opencontext web app's database layer. Each consumer wires up its own
6
- * implementation of the `db` contract.
7
- *
8
- * Backend selection is env-var driven, not host-injected:
9
- * - Default: local SQLite at `~/.opencontext/memory/store.db`
10
- * (override with `MEMORY_STORE_DB_PATH`).
11
- * - Set `OPENCONTEXT_MEMORY_STORE_BACKEND=postgres` to opt into the
12
- * host's registered Postgres factory (call `registerPostgresFactory`
13
- * at startup). SQLite stays as the default in every other case.
14
- *
15
- * Required for raw-message persistence:
16
- * - `db.getDb()` — returns a Drizzle DB handle (Postgres path only)
17
- *
18
- * Required for vector indexing:
19
- * - one of `vector.sqlite-vec.dbPath` or `vector.chroma.url`
20
- *
21
- * Required for unified semantic search:
22
- * - `unified.embedQuery` — the embedding provider's query embedder
23
- *
24
- * Optional for cross-source unified search:
25
- * - `unified.searchKnowledge` — RAG over uploaded documents
26
- * - `unified.searchInsights` — over extracted insights
27
- *
28
- * If `unified.*` are absent, the SDK still works but the corresponding
29
- * sources in `searchUnifiedMemory` will return empty results with a
30
- * warning — fine for a standalone memory daemon.
31
- */
32
-
33
- interface MemoryStoreDb {
34
- /** Resolve the active Drizzle DB handle. Must be server-side. */
35
- getDb(): unknown;
36
- /** Whether the DB has finished initializing (optional, for startup gating). */
37
- isDbInitialized?(): boolean;
38
- /** Initialize the DB (optional, called by `createMemoryStore` if present). */
39
- initDb?(): unknown;
40
- /**
41
- * Drizzle table references for the postgres backend. Required when
42
- * running outside Tauri mode without a registered factory. The host
43
- * application owns the actual schema.
44
- */
45
- tables?: {
46
- rawMessages?: unknown;
47
- memorySummaries?: unknown;
48
- };
49
- }
50
- /**
51
- * Placeholder for the historical host-injected environment. The fields
52
- * it used to expose (`isTauriMode`, `getTauriDbPath`, `getTauriDataDir`)
53
- * were Tauri-specific and have been removed. Backend selection is now
54
- * driven entirely by the `OPENCONTEXT_MEMORY_STORE_BACKEND` env var.
55
- *
56
- * The interface is kept (empty) so existing `env?: MemoryStoreEnv`
57
- * parameters on the public surface still type-check, but new code
58
- * should not need to construct a value of this type.
59
- */
60
- interface MemoryStoreEnv {
61
- }
62
- type VectorBackend = "sqlite-vec" | "chroma";
63
- interface MemoryStoreVectorConfig {
64
- /** Active backend selector. Defaults to env-based detection. */
65
- backend?: VectorBackend;
66
- /** SQLite-vec options (used when backend === "sqlite-vec"). */
67
- sqliteVec?: {
68
- dbPath?: string;
69
- insightsCollection?: string;
70
- };
71
- /** Chroma options (used when backend === "chroma"). */
72
- chroma?: {
73
- url?: string;
74
- rawMessagesCollection?: string;
75
- insightsCollection?: string;
76
- };
77
- }
78
- type EmbedQueryFn = (input: {
79
- userId: string;
80
- query: string;
81
- authToken?: string;
82
- }) => Promise<number[]>;
83
- interface UnifiedSearchKnowledgeResult {
84
- chunkId: string;
85
- documentId: string;
86
- documentName: string;
87
- content: string;
88
- similarity: number;
89
- chunkIndex: number;
90
- }
91
- interface UnifiedSearchInsightsResult {
92
- id: string;
93
- content: string;
94
- similarity: number;
95
- metadata: Record<string, unknown>;
96
- }
97
- interface UnifiedSearchDeps {
98
- /** Embed a query string using the active user's provider. */
99
- embedQuery?: EmbedQueryFn;
100
- /**
101
- * Postgres-side ANN search over `raw_messages`. Used when chroma is
102
- * not enabled but the host has a postgres-backed manager. If both
103
- * chroma and this are absent, the memory source will return empty
104
- * (with a warning) in standalone mode.
105
- */
106
- searchRawMessagesAnn?: (input: {
107
- userId: string;
108
- queryEmbedding: number[];
109
- limit: number;
110
- threshold: number;
111
- botId?: string;
112
- }) => Promise<Array<{
113
- id: string;
114
- content: string;
115
- similarity: number;
116
- metadata: Record<string, unknown>;
117
- }>>;
118
- /** RAG over uploaded knowledge documents. Returns a list of chunk hits. */
119
- searchKnowledge?: (input: {
120
- userId: string;
121
- query: string;
122
- options: {
123
- limit: number;
124
- threshold: number;
125
- documentIds?: string[];
126
- };
127
- authToken?: string;
128
- }) => Promise<UnifiedSearchKnowledgeResult[]>;
129
- /** Semantic search over extracted insights. */
130
- searchInsights?: (input: {
131
- userId: string;
132
- query: string;
133
- limit: number;
134
- threshold: number;
135
- botIds?: string[];
136
- includeArchived?: boolean;
137
- authToken?: string;
138
- }) => Promise<UnifiedSearchInsightsResult[]>;
139
- /**
140
- * Optional BM25 (lexical) sub-query for the memory source. Mirrors the
141
- * `searchRawMessagesAnn` shape but operates on FTS5 keywords instead of
142
- * dense embeddings. When absent, the unified pipeline skips the lexical
143
- * path and emits a `memory_lexical_search_not_configured` warning.
144
- */
145
- searchRawMessagesLexical?: (input: {
146
- userId: string;
147
- keywords: string[];
148
- limit: number;
149
- botId?: string;
150
- }) => Promise<Array<{
151
- id: string;
152
- content: string;
153
- similarity: number;
154
- metadata: Record<string, unknown>;
155
- }>>;
156
- }
157
- interface MemoryStoreConfig {
158
- /** Database handle factory. Required for any persistence. */
159
- db?: MemoryStoreDb;
160
- /** Environment helpers. Defaults to a process.env-only stub if omitted. */
161
- env?: MemoryStoreEnv;
162
- /** Vector backend config. Defaults to env-based detection. */
163
- vector?: MemoryStoreVectorConfig;
164
- /** Optional cross-source search providers. */
165
- unified?: UnifiedSearchDeps;
166
- /** Optional logger. Defaults to console. */
167
- logger?: Pick<Console, "log" | "warn" | "error">;
168
- }
169
-
170
- export type { EmbedQueryFn as E, MemoryStoreConfig as M, UnifiedSearchInsightsResult as U, VectorBackend as V, MemoryStoreDb as a, MemoryStoreEnv as b, UnifiedSearchKnowledgeResult as c, UnifiedSearchDeps as d };