@twelvehart/supermemory-runtime 1.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/.env.example +57 -0
  2. package/README.md +374 -0
  3. package/dist/index.js +189 -0
  4. package/dist/mcp/index.js +1132 -0
  5. package/docker-compose.prod.yml +91 -0
  6. package/docker-compose.yml +358 -0
  7. package/drizzle/0000_dapper_the_professor.sql +159 -0
  8. package/drizzle/0001_api_keys.sql +51 -0
  9. package/drizzle/meta/0000_snapshot.json +1532 -0
  10. package/drizzle/meta/_journal.json +13 -0
  11. package/drizzle.config.ts +20 -0
  12. package/package.json +114 -0
  13. package/scripts/add-extraction-job.ts +122 -0
  14. package/scripts/benchmark-pgvector.ts +122 -0
  15. package/scripts/bootstrap.sh +209 -0
  16. package/scripts/check-runtime-pack.ts +111 -0
  17. package/scripts/claude-mcp-config.ts +336 -0
  18. package/scripts/docker-entrypoint.sh +183 -0
  19. package/scripts/doctor.ts +377 -0
  20. package/scripts/init-db.sql +33 -0
  21. package/scripts/install.sh +1110 -0
  22. package/scripts/mcp-setup.ts +271 -0
  23. package/scripts/migrations/001_create_pgvector_extension.sql +31 -0
  24. package/scripts/migrations/002_create_memory_embeddings_table.sql +75 -0
  25. package/scripts/migrations/003_create_hnsw_index.sql +94 -0
  26. package/scripts/migrations/004_create_memory_embeddings_standalone.sql +70 -0
  27. package/scripts/migrations/005_create_chunks_table.sql +95 -0
  28. package/scripts/migrations/006_create_processing_queue.sql +45 -0
  29. package/scripts/migrations/generate_test_data.sql +42 -0
  30. package/scripts/migrations/phase1_comprehensive_test.sql +204 -0
  31. package/scripts/migrations/run_migrations.sh +286 -0
  32. package/scripts/migrations/test_hnsw_index.sql +255 -0
  33. package/scripts/pre-commit-secrets +282 -0
  34. package/scripts/run-extraction-worker.ts +46 -0
  35. package/scripts/run-phase1-tests.sh +291 -0
  36. package/scripts/setup.ts +222 -0
  37. package/scripts/smoke-install.sh +12 -0
  38. package/scripts/test-health-endpoint.sh +328 -0
  39. package/src/api/index.ts +2 -0
  40. package/src/api/middleware/auth.ts +80 -0
  41. package/src/api/middleware/csrf.ts +308 -0
  42. package/src/api/middleware/errorHandler.ts +166 -0
  43. package/src/api/middleware/rateLimit.ts +360 -0
  44. package/src/api/middleware/validation.ts +514 -0
  45. package/src/api/routes/documents.ts +286 -0
  46. package/src/api/routes/profiles.ts +237 -0
  47. package/src/api/routes/search.ts +71 -0
  48. package/src/api/stores/index.ts +58 -0
  49. package/src/config/bootstrap-env.ts +3 -0
  50. package/src/config/env.ts +71 -0
  51. package/src/config/feature-flags.ts +25 -0
  52. package/src/config/index.ts +140 -0
  53. package/src/config/secrets.config.ts +291 -0
  54. package/src/db/client.ts +92 -0
  55. package/src/db/index.ts +73 -0
  56. package/src/db/postgres.ts +72 -0
  57. package/src/db/schema/chunks.schema.ts +31 -0
  58. package/src/db/schema/containers.schema.ts +46 -0
  59. package/src/db/schema/documents.schema.ts +49 -0
  60. package/src/db/schema/embeddings.schema.ts +32 -0
  61. package/src/db/schema/index.ts +11 -0
  62. package/src/db/schema/memories.schema.ts +72 -0
  63. package/src/db/schema/profiles.schema.ts +34 -0
  64. package/src/db/schema/queue.schema.ts +59 -0
  65. package/src/db/schema/relationships.schema.ts +42 -0
  66. package/src/db/schema.ts +223 -0
  67. package/src/db/worker-connection.ts +47 -0
  68. package/src/index.ts +235 -0
  69. package/src/mcp/CLAUDE.md +1 -0
  70. package/src/mcp/index.ts +1380 -0
  71. package/src/mcp/legacyState.ts +22 -0
  72. package/src/mcp/rateLimit.ts +358 -0
  73. package/src/mcp/resources.ts +309 -0
  74. package/src/mcp/results.ts +104 -0
  75. package/src/mcp/tools.ts +401 -0
  76. package/src/queues/config.ts +119 -0
  77. package/src/queues/index.ts +289 -0
  78. package/src/sdk/client.ts +225 -0
  79. package/src/sdk/errors.ts +266 -0
  80. package/src/sdk/http.ts +560 -0
  81. package/src/sdk/index.ts +244 -0
  82. package/src/sdk/resources/base.ts +65 -0
  83. package/src/sdk/resources/connections.ts +204 -0
  84. package/src/sdk/resources/documents.ts +163 -0
  85. package/src/sdk/resources/index.ts +10 -0
  86. package/src/sdk/resources/memories.ts +150 -0
  87. package/src/sdk/resources/search.ts +60 -0
  88. package/src/sdk/resources/settings.ts +36 -0
  89. package/src/sdk/types.ts +674 -0
  90. package/src/services/chunking/index.ts +451 -0
  91. package/src/services/chunking.service.ts +650 -0
  92. package/src/services/csrf.service.ts +252 -0
  93. package/src/services/documents.repository.ts +219 -0
  94. package/src/services/documents.service.ts +191 -0
  95. package/src/services/embedding.service.ts +404 -0
  96. package/src/services/extraction.service.ts +300 -0
  97. package/src/services/extractors/code.extractor.ts +451 -0
  98. package/src/services/extractors/index.ts +9 -0
  99. package/src/services/extractors/markdown.extractor.ts +461 -0
  100. package/src/services/extractors/pdf.extractor.ts +315 -0
  101. package/src/services/extractors/text.extractor.ts +118 -0
  102. package/src/services/extractors/url.extractor.ts +243 -0
  103. package/src/services/index.ts +235 -0
  104. package/src/services/ingestion.service.ts +177 -0
  105. package/src/services/llm/anthropic.ts +400 -0
  106. package/src/services/llm/base.ts +460 -0
  107. package/src/services/llm/contradiction-detector.service.ts +526 -0
  108. package/src/services/llm/heuristics.ts +148 -0
  109. package/src/services/llm/index.ts +309 -0
  110. package/src/services/llm/memory-classifier.service.ts +383 -0
  111. package/src/services/llm/memory-extension-detector.service.ts +523 -0
  112. package/src/services/llm/mock.ts +470 -0
  113. package/src/services/llm/openai.ts +398 -0
  114. package/src/services/llm/prompts.ts +438 -0
  115. package/src/services/llm/types.ts +373 -0
  116. package/src/services/memory.repository.ts +1769 -0
  117. package/src/services/memory.service.ts +1338 -0
  118. package/src/services/memory.types.ts +234 -0
  119. package/src/services/persistence/index.ts +295 -0
  120. package/src/services/pipeline.service.ts +509 -0
  121. package/src/services/profile.repository.ts +436 -0
  122. package/src/services/profile.service.ts +560 -0
  123. package/src/services/profile.types.ts +270 -0
  124. package/src/services/relationships/detector.ts +1128 -0
  125. package/src/services/relationships/index.ts +268 -0
  126. package/src/services/relationships/memory-integration.ts +459 -0
  127. package/src/services/relationships/strategies.ts +132 -0
  128. package/src/services/relationships/types.ts +370 -0
  129. package/src/services/search.service.ts +761 -0
  130. package/src/services/search.types.ts +220 -0
  131. package/src/services/secrets.service.ts +384 -0
  132. package/src/services/vectorstore/base.ts +327 -0
  133. package/src/services/vectorstore/index.ts +444 -0
  134. package/src/services/vectorstore/memory.ts +286 -0
  135. package/src/services/vectorstore/migration.ts +295 -0
  136. package/src/services/vectorstore/mock.ts +403 -0
  137. package/src/services/vectorstore/pgvector.ts +695 -0
  138. package/src/services/vectorstore/types.ts +247 -0
  139. package/src/startup.ts +389 -0
  140. package/src/types/api.types.ts +193 -0
  141. package/src/types/document.types.ts +103 -0
  142. package/src/types/index.ts +241 -0
  143. package/src/types/profile.base.ts +133 -0
  144. package/src/utils/errors.ts +447 -0
  145. package/src/utils/id.ts +15 -0
  146. package/src/utils/index.ts +101 -0
  147. package/src/utils/logger.ts +313 -0
  148. package/src/utils/sanitization.ts +501 -0
  149. package/src/utils/secret-validation.ts +273 -0
  150. package/src/utils/synonyms.ts +188 -0
  151. package/src/utils/validation.ts +581 -0
  152. package/src/workers/chunking.worker.ts +242 -0
  153. package/src/workers/embedding.worker.ts +358 -0
  154. package/src/workers/extraction.worker.ts +346 -0
  155. package/src/workers/indexing.worker.ts +505 -0
  156. package/tsconfig.json +38 -0
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Base Vector Store
3
+ *
4
+ * Abstract base class for vector store implementations.
5
+ * Provides common utilities and defines the interface that all
6
+ * vector store implementations must follow.
7
+ */
8
+
9
+ import {
10
+ VectorEntry,
11
+ VectorSearchResult,
12
+ SearchOptions,
13
+ AddOptions,
14
+ DeleteOptions,
15
+ VectorStoreConfig,
16
+ VectorStoreStats,
17
+ BatchResult,
18
+ MetadataFilter,
19
+ SimilarityMetric,
20
+ DEFAULT_SEARCH_OPTIONS,
21
+ VectorStoreEvent,
22
+ VectorStoreEventListener,
23
+ } from './types.js'
24
+ import { ValidationError } from '../../utils/errors.js'
25
+
26
+ /**
27
+ * Calculate cosine similarity between two vectors
28
+ */
29
+ export function cosineSimilarity(a: number[], b: number[]): number {
30
+ if (a.length !== b.length) {
31
+ throw new ValidationError(`Vector dimension mismatch: ${a.length} vs ${b.length}`, {
32
+ vectorA: [`Expected dimension ${b.length}, got ${a.length}`],
33
+ })
34
+ }
35
+
36
+ let dotProduct = 0
37
+ let normA = 0
38
+ let normB = 0
39
+
40
+ for (let i = 0; i < a.length; i++) {
41
+ const aVal = a[i] ?? 0
42
+ const bVal = b[i] ?? 0
43
+ dotProduct += aVal * bVal
44
+ normA += aVal * aVal
45
+ normB += bVal * bVal
46
+ }
47
+
48
+ const magnitude = Math.sqrt(normA) * Math.sqrt(normB)
49
+ if (magnitude === 0) return 0
50
+
51
+ return dotProduct / magnitude
52
+ }
53
+
54
+ /**
55
+ * Calculate Euclidean distance between two vectors
56
+ */
57
+ export function euclideanDistance(a: number[], b: number[]): number {
58
+ if (a.length !== b.length) {
59
+ throw new ValidationError(`Vector dimension mismatch: ${a.length} vs ${b.length}`, {
60
+ vectorA: [`Expected dimension ${b.length}, got ${a.length}`],
61
+ })
62
+ }
63
+
64
+ let sum = 0
65
+ for (let i = 0; i < a.length; i++) {
66
+ const diff = (a[i] ?? 0) - (b[i] ?? 0)
67
+ sum += diff * diff
68
+ }
69
+
70
+ return Math.sqrt(sum)
71
+ }
72
+
73
+ /**
74
+ * Calculate dot product between two vectors
75
+ */
76
+ export function dotProduct(a: number[], b: number[]): number {
77
+ if (a.length !== b.length) {
78
+ throw new ValidationError(`Vector dimension mismatch: ${a.length} vs ${b.length}`, {
79
+ vectorA: [`Expected dimension ${b.length}, got ${a.length}`],
80
+ })
81
+ }
82
+
83
+ let sum = 0
84
+ for (let i = 0; i < a.length; i++) {
85
+ sum += (a[i] ?? 0) * (b[i] ?? 0)
86
+ }
87
+
88
+ return sum
89
+ }
90
+
91
+ /**
92
+ * Normalize a vector to unit length (L2 normalization)
93
+ */
94
+ export function normalizeVector(vector: number[]): number[] {
95
+ const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0))
96
+ if (magnitude === 0) return vector
97
+ return vector.map((val) => val / magnitude)
98
+ }
99
+
100
+ /**
101
+ * Validate vector dimensions
102
+ */
103
+ export function validateVector(vector: number[], expectedDimensions: number): void {
104
+ if (!Array.isArray(vector)) {
105
+ throw new ValidationError('Vector must be an array', {
106
+ vector: ['Vector must be an array of numbers'],
107
+ })
108
+ }
109
+ if (vector.length !== expectedDimensions) {
110
+ throw new ValidationError(`Vector dimension mismatch: expected ${expectedDimensions}, got ${vector.length}`, {
111
+ vector: [`Expected ${expectedDimensions} dimensions, got ${vector.length}`],
112
+ })
113
+ }
114
+ if (vector.some((v) => typeof v !== 'number' || Number.isNaN(v))) {
115
+ throw new ValidationError('Vector must contain only valid numbers', {
116
+ vector: ['All vector elements must be valid numbers (no NaN or non-numeric values)'],
117
+ })
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Abstract base class for vector stores
123
+ */
124
+ export abstract class BaseVectorStore {
125
+ protected readonly config: VectorStoreConfig
126
+ protected readonly listeners: VectorStoreEventListener[] = []
127
+
128
+ constructor(config: VectorStoreConfig) {
129
+ this.config = {
130
+ metric: 'cosine',
131
+ indexType: 'flat',
132
+ defaultNamespace: 'default',
133
+ ...config,
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Get the configured dimensions
139
+ */
140
+ getDimensions(): number {
141
+ return this.config.dimensions
142
+ }
143
+
144
+ /**
145
+ * Get the configured similarity metric
146
+ */
147
+ getMetric(): SimilarityMetric {
148
+ return this.config.metric ?? 'cosine'
149
+ }
150
+
151
+ /**
152
+ * Calculate similarity between two vectors using configured metric
153
+ */
154
+ calculateSimilarity(a: number[], b: number[]): number {
155
+ const metric = this.getMetric()
156
+ switch (metric) {
157
+ case 'cosine':
158
+ return cosineSimilarity(a, b)
159
+ case 'euclidean':
160
+ // Convert distance to similarity (1 / (1 + distance))
161
+ return 1 / (1 + euclideanDistance(a, b))
162
+ case 'dot_product':
163
+ return dotProduct(a, b)
164
+ default:
165
+ return cosineSimilarity(a, b)
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Validate a vector entry
171
+ */
172
+ protected validateEntry(entry: VectorEntry): void {
173
+ if (!entry.id || typeof entry.id !== 'string') {
174
+ throw new ValidationError('Vector entry must have a valid string ID', {
175
+ id: ['Entry ID must be a non-empty string'],
176
+ })
177
+ }
178
+ validateVector(entry.embedding, this.config.dimensions)
179
+ }
180
+
181
+ /**
182
+ * Apply metadata filters to entries
183
+ */
184
+ protected applyFilters(entries: VectorEntry[], filters?: MetadataFilter[]): VectorEntry[] {
185
+ if (!filters || filters.length === 0) {
186
+ return entries
187
+ }
188
+
189
+ return entries.filter((entry) => {
190
+ return filters.every((filter) => this.matchesFilter(entry.metadata, filter))
191
+ })
192
+ }
193
+
194
+ /**
195
+ * Check if metadata matches a filter
196
+ */
197
+ protected matchesFilter(metadata: Record<string, unknown>, filter: MetadataFilter): boolean {
198
+ const value = metadata[filter.key]
199
+ if (value === undefined) return false
200
+
201
+ switch (filter.operator) {
202
+ case 'eq':
203
+ return value === filter.value
204
+ case 'ne':
205
+ return value !== filter.value
206
+ case 'gt':
207
+ return typeof value === 'number' && typeof filter.value === 'number' && value > filter.value
208
+ case 'gte':
209
+ return typeof value === 'number' && typeof filter.value === 'number' && value >= filter.value
210
+ case 'lt':
211
+ return typeof value === 'number' && typeof filter.value === 'number' && value < filter.value
212
+ case 'lte':
213
+ return typeof value === 'number' && typeof filter.value === 'number' && value <= filter.value
214
+ case 'in':
215
+ return Array.isArray(filter.value) && filter.value.includes(value as string | number)
216
+ case 'nin':
217
+ return Array.isArray(filter.value) && !filter.value.includes(value as string | number)
218
+ case 'contains':
219
+ return typeof value === 'string' && typeof filter.value === 'string' && value.includes(filter.value)
220
+ case 'startsWith':
221
+ return typeof value === 'string' && typeof filter.value === 'string' && value.startsWith(filter.value)
222
+ default:
223
+ return false
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Merge search options with defaults
229
+ */
230
+ protected mergeOptions(options?: SearchOptions): Required<Omit<SearchOptions, 'filters'>> & {
231
+ filters?: MetadataFilter[]
232
+ } {
233
+ return {
234
+ ...DEFAULT_SEARCH_OPTIONS,
235
+ ...options,
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Add an event listener
241
+ */
242
+ addEventListener(event: VectorStoreEvent, callback: (data: unknown) => void): void {
243
+ this.listeners.push({ event, callback })
244
+ }
245
+
246
+ /**
247
+ * Remove an event listener
248
+ */
249
+ removeEventListener(event: VectorStoreEvent, callback: (data: unknown) => void): void {
250
+ const index = this.listeners.findIndex((l) => l.event === event && l.callback === callback)
251
+ if (index !== -1) {
252
+ this.listeners.splice(index, 1)
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Emit an event to all listeners
258
+ */
259
+ protected emit(event: VectorStoreEvent, data: unknown): void {
260
+ for (const listener of this.listeners) {
261
+ if (listener.event === event) {
262
+ try {
263
+ listener.callback(data)
264
+ } catch (error) {
265
+ console.error(`Error in vector store event listener:`, error)
266
+ }
267
+ }
268
+ }
269
+ }
270
+
271
+ // Abstract methods that must be implemented by subclasses
272
+
273
+ /**
274
+ * Initialize the vector store
275
+ */
276
+ abstract initialize(): Promise<void>
277
+
278
+ /**
279
+ * Add a single vector entry
280
+ */
281
+ abstract add(entry: VectorEntry, options?: AddOptions): Promise<void>
282
+
283
+ /**
284
+ * Add multiple vector entries
285
+ */
286
+ abstract addBatch(entries: VectorEntry[], options?: AddOptions): Promise<BatchResult>
287
+
288
+ /**
289
+ * Update an existing vector entry
290
+ */
291
+ abstract update(id: string, entry: Partial<VectorEntry>): Promise<boolean>
292
+
293
+ /**
294
+ * Delete vector entries
295
+ */
296
+ abstract delete(options: DeleteOptions): Promise<number>
297
+
298
+ /**
299
+ * Get a vector entry by ID
300
+ */
301
+ abstract get(id: string): Promise<VectorEntry | null>
302
+
303
+ /**
304
+ * Check if a vector entry exists
305
+ */
306
+ abstract exists(id: string): Promise<boolean>
307
+
308
+ /**
309
+ * Search for similar vectors
310
+ */
311
+ abstract search(query: number[], options?: SearchOptions): Promise<VectorSearchResult[]>
312
+
313
+ /**
314
+ * Get statistics about the vector store
315
+ */
316
+ abstract getStats(): Promise<VectorStoreStats>
317
+
318
+ /**
319
+ * Clear all vectors from the store
320
+ */
321
+ abstract clear(): Promise<void>
322
+
323
+ /**
324
+ * Close the vector store and release resources
325
+ */
326
+ abstract close(): Promise<void>
327
+ }