@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,193 @@
1
+ import { z } from 'zod'
2
+
3
+ // ============================================================================
4
+ // Security Constants
5
+ // ============================================================================
6
+
7
+ /** Maximum content size in characters (50KB) */
8
+ const MAX_CONTENT_CHARS = 50000
9
+
10
+ /** Maximum query size in characters (10KB) */
11
+ const MAX_QUERY_CHARS = 10000
12
+
13
+ /** Maximum metadata size in bytes (10KB) */
14
+ const MAX_METADATA_BYTES = 10240
15
+
16
+ // ============================================================================
17
+ // Base Response Types
18
+ // ============================================================================
19
+
20
+ export interface SuccessResponse<T> {
21
+ data: T
22
+ timing: number
23
+ }
24
+
25
+ export interface ErrorResponse {
26
+ error: {
27
+ code: string
28
+ message: string
29
+ }
30
+ status: number
31
+ }
32
+
33
+ export type ApiResponse<T> = SuccessResponse<T> | ErrorResponse
34
+
35
+ // ============================================================================
36
+ // Document Types
37
+ // ============================================================================
38
+
39
+ export const DocumentMetadataSchema = z
40
+ .record(z.unknown())
41
+ .optional()
42
+ .refine(
43
+ (metadata) => {
44
+ if (!metadata) return true
45
+ try {
46
+ const jsonSize = new TextEncoder().encode(JSON.stringify(metadata)).length
47
+ return jsonSize <= MAX_METADATA_BYTES
48
+ } catch {
49
+ return false
50
+ }
51
+ },
52
+ { message: `Metadata must be at most ${MAX_METADATA_BYTES} bytes (10KB)` }
53
+ )
54
+
55
+ export const CreateDocumentSchema = z.object({
56
+ content: z
57
+ .string()
58
+ .min(1, 'Content is required')
59
+ .max(MAX_CONTENT_CHARS, `Content must be at most ${MAX_CONTENT_CHARS} characters`),
60
+ containerTag: z.string().min(1).max(100).optional(),
61
+ metadata: DocumentMetadataSchema,
62
+ customId: z.string().min(1).max(255).optional(),
63
+ })
64
+
65
+ export const UpdateDocumentSchema = z.object({
66
+ content: z
67
+ .string()
68
+ .min(1)
69
+ .max(MAX_CONTENT_CHARS, `Content must be at most ${MAX_CONTENT_CHARS} characters`)
70
+ .optional(),
71
+ containerTag: z.string().min(1).max(100).optional(),
72
+ metadata: DocumentMetadataSchema,
73
+ })
74
+
75
+ export const ListDocumentsQuerySchema = z.object({
76
+ containerTag: z.string().optional(),
77
+ limit: z.coerce.number().int().min(1).max(100).default(20),
78
+ offset: z.coerce.number().int().min(0).default(0),
79
+ })
80
+
81
+ export const BulkDeleteSchema = z
82
+ .object({
83
+ ids: z.array(z.string()).optional(),
84
+ containerTags: z.array(z.string()).optional(),
85
+ })
86
+ .refine((data) => data.ids?.length || data.containerTags?.length, {
87
+ message: 'Either ids or containerTags must be provided',
88
+ })
89
+
90
+ export interface ApiDocument {
91
+ id: string
92
+ content: string
93
+ containerTag?: string
94
+ metadata?: Record<string, unknown>
95
+ customId?: string
96
+ createdAt: string
97
+ updatedAt: string
98
+ }
99
+
100
+ export type CreateDocumentInput = z.infer<typeof CreateDocumentSchema>
101
+ export type UpdateDocumentInput = z.infer<typeof UpdateDocumentSchema>
102
+ export type ListDocumentsQuery = z.infer<typeof ListDocumentsQuerySchema>
103
+ export type BulkDeleteInput = z.infer<typeof BulkDeleteSchema>
104
+
105
+ // ============================================================================
106
+ // Search Types
107
+ // ============================================================================
108
+
109
+ export const SearchModeSchema = z.enum(['vector', 'fulltext', 'hybrid'])
110
+
111
+ export const SearchFiltersSchema = z.object({
112
+ createdAfter: z.string().datetime().optional(),
113
+ createdBefore: z.string().datetime().optional(),
114
+ metadata: z.record(z.unknown()).optional(),
115
+ })
116
+
117
+ export const SearchRequestSchema = z.object({
118
+ q: z.string().min(1, 'Query is required').max(MAX_QUERY_CHARS, `Query must be at most ${MAX_QUERY_CHARS} characters`),
119
+ containerTag: z.string().max(100).optional(),
120
+ searchMode: SearchModeSchema.default('hybrid'),
121
+ limit: z.coerce.number().int().min(1).max(100).default(10),
122
+ threshold: z.coerce.number().min(0).max(1).default(0.7),
123
+ rerank: z.boolean().default(false),
124
+ filters: SearchFiltersSchema.optional(),
125
+ })
126
+
127
+ export interface SearchResult {
128
+ id: string
129
+ content: string
130
+ score: number
131
+ containerTag?: string
132
+ metadata?: Record<string, unknown>
133
+ highlights?: string[]
134
+ }
135
+
136
+ export interface SearchResponse {
137
+ results: SearchResult[]
138
+ total: number
139
+ query: string
140
+ searchMode: string
141
+ }
142
+
143
+ export type SearchRequest = z.infer<typeof SearchRequestSchema>
144
+ export type SearchFilters = z.infer<typeof SearchFiltersSchema>
145
+
146
+ // ============================================================================
147
+ // Profile Types
148
+ // ============================================================================
149
+
150
+ export const UpdateProfileSchema = z.object({
151
+ name: z.string().min(1).max(255).optional(),
152
+ description: z.string().max(1000).optional(),
153
+ settings: z.record(z.unknown()).optional(),
154
+ })
155
+
156
+ export interface ApiProfile {
157
+ containerTag: string
158
+ name?: string
159
+ description?: string
160
+ settings?: Record<string, unknown>
161
+ documentCount: number
162
+ createdAt: string
163
+ updatedAt: string
164
+ }
165
+
166
+ export type UpdateProfileInput = z.infer<typeof UpdateProfileSchema>
167
+
168
+ // ============================================================================
169
+ // Authentication Types
170
+ // ============================================================================
171
+
172
+ export interface AuthContext {
173
+ userId: string
174
+ apiKey: string
175
+ scopes: string[]
176
+ }
177
+
178
+ // ============================================================================
179
+ // Error Codes
180
+ // ============================================================================
181
+
182
+ export const ErrorCodes = {
183
+ VALIDATION_ERROR: 'VALIDATION_ERROR',
184
+ UNAUTHORIZED: 'UNAUTHORIZED',
185
+ FORBIDDEN: 'FORBIDDEN',
186
+ NOT_FOUND: 'NOT_FOUND',
187
+ CONFLICT: 'CONFLICT',
188
+ RATE_LIMITED: 'RATE_LIMITED',
189
+ INTERNAL_ERROR: 'INTERNAL_ERROR',
190
+ BAD_REQUEST: 'BAD_REQUEST',
191
+ } as const
192
+
193
+ export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes]
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Document and extraction types for supermemory content pipeline
3
+ */
4
+
5
+ export type ContentType = 'text' | 'url' | 'pdf' | 'markdown' | 'code' | 'unknown'
6
+
7
+ export type DocumentStatus = 'queued' | 'extracting' | 'chunking' | 'embedding' | 'indexing' | 'done' | 'error'
8
+
9
+ export interface Document {
10
+ id: string
11
+ content: string
12
+ contentType?: ContentType
13
+ sourceUrl?: string
14
+ fileName?: string
15
+ language?: string
16
+ status: DocumentStatus
17
+ metadata: DocumentMetadata
18
+ createdAt: Date
19
+ updatedAt: Date
20
+ errorMessage?: string
21
+ retryCount: number
22
+ }
23
+
24
+ export interface DocumentMetadata {
25
+ title?: string
26
+ author?: string
27
+ description?: string
28
+ tags?: string[]
29
+ source?: string
30
+ mimeType?: string
31
+ wordCount?: number
32
+ charCount?: number
33
+ [key: string]: unknown
34
+ }
35
+
36
+ export interface Chunk {
37
+ id: string
38
+ documentId: string
39
+ content: string
40
+ type: ChunkType
41
+ position: ChunkPosition
42
+ metadata: ChunkMetadata
43
+ embedding?: number[]
44
+ }
45
+
46
+ export type ChunkType =
47
+ | 'paragraph'
48
+ | 'heading'
49
+ | 'code_block'
50
+ | 'function'
51
+ | 'class'
52
+ | 'list'
53
+ | 'table'
54
+ | 'quote'
55
+ | 'section'
56
+ | 'raw'
57
+
58
+ export interface ChunkPosition {
59
+ index: number
60
+ start: number
61
+ end: number
62
+ lineStart?: number
63
+ lineEnd?: number
64
+ }
65
+
66
+ export interface ChunkMetadata {
67
+ headingLevel?: number
68
+ headingText?: string
69
+ language?: string
70
+ functionName?: string
71
+ className?: string
72
+ parentChunkId?: string
73
+ wordCount: number
74
+ charCount: number
75
+ [key: string]: unknown
76
+ }
77
+
78
+ export interface ExtractionResult {
79
+ content: string
80
+ contentType: ContentType
81
+ metadata: DocumentMetadata
82
+ rawContent?: string
83
+ }
84
+
85
+ export interface ChunkingOptions {
86
+ maxChunkSize?: number
87
+ minChunkSize?: number
88
+ overlap?: number
89
+ preserveStructure?: boolean
90
+ }
91
+
92
+ export interface PipelineResult {
93
+ documentId: string
94
+ status: DocumentStatus
95
+ chunks: Chunk[]
96
+ processingTimeMs: number
97
+ error?: string
98
+ }
99
+
100
+ export interface ExtractorInterface {
101
+ extract(content: string | Buffer, options?: Record<string, unknown>): Promise<ExtractionResult>
102
+ canHandle(content: string | Buffer): boolean
103
+ }
@@ -0,0 +1,241 @@
1
+ import { z } from 'zod'
2
+
3
+ // ============================================================================
4
+ // Memory Types
5
+ // ============================================================================
6
+
7
+ export const MemoryTypeSchema = z.enum(['fact', 'event', 'preference', 'skill', 'relationship', 'context', 'note'])
8
+
9
+ export type MemoryType = z.infer<typeof MemoryTypeSchema>
10
+
11
+ export const RelationshipTypeSchema = z.enum(['updates', 'extends', 'derives', 'contradicts', 'related', 'supersedes'])
12
+
13
+ export type RelationshipType = z.infer<typeof RelationshipTypeSchema>
14
+
15
+ export interface MemoryRelationship {
16
+ type: RelationshipType
17
+ targetId: string
18
+ confidence: number
19
+ metadata?: Record<string, unknown>
20
+ }
21
+
22
+ export interface Memory {
23
+ id: string
24
+ content: string
25
+ type: MemoryType
26
+ embedding?: number[]
27
+ relationships: MemoryRelationship[]
28
+ isLatest: boolean
29
+ supersededBy?: string
30
+ containerTag?: string
31
+ metadata: MemoryMetadata
32
+ createdAt: Date
33
+ updatedAt: Date
34
+ }
35
+
36
+ export interface MemoryMetadata {
37
+ source?: string
38
+ confidence?: number
39
+ extractedFrom?: string
40
+ keywords?: string[]
41
+ entities?: Entity[]
42
+ [key: string]: unknown
43
+ }
44
+
45
+ export interface Entity {
46
+ name: string
47
+ type: 'person' | 'place' | 'organization' | 'date' | 'concept' | 'other'
48
+ mentions: number
49
+ }
50
+
51
+ // ============================================================================
52
+ // Search Types
53
+ // ============================================================================
54
+
55
+ export const SearchModeSchema = z.enum(['vector', 'keyword', 'hybrid'])
56
+ export type SearchMode = z.infer<typeof SearchModeSchema>
57
+
58
+ export interface SearchQuery {
59
+ query: string
60
+ mode?: SearchMode
61
+ containerTag?: string
62
+ filters?: SearchFilters
63
+ limit?: number
64
+ offset?: number
65
+ rerank?: boolean
66
+ minScore?: number
67
+ }
68
+
69
+ export interface SearchFilters {
70
+ types?: MemoryType[]
71
+ dateRange?: {
72
+ start?: Date
73
+ end?: Date
74
+ }
75
+ metadata?: Record<string, unknown>
76
+ isLatest?: boolean
77
+ }
78
+
79
+ export interface SearchResult {
80
+ memory: Memory
81
+ score: number
82
+ highlights?: string[]
83
+ }
84
+
85
+ export interface SearchResponse {
86
+ results: SearchResult[]
87
+ total: number
88
+ query: string
89
+ mode: SearchMode
90
+ took: number
91
+ }
92
+
93
+ // ============================================================================
94
+ // Profile Types
95
+ // ============================================================================
96
+
97
+ import { FactLifecycleCategorySchema, FactLifecycleCategory, BaseProfileFact } from './profile.base.js'
98
+
99
+ /**
100
+ * Fact lifecycle category - determines expiration behavior
101
+ * Re-exported from profile.base for convenience
102
+ */
103
+ export const FactCategorySchema = FactLifecycleCategorySchema
104
+
105
+ /**
106
+ * Fact lifecycle category type
107
+ * Note: This represents the fact's lifecycle (static/dynamic/inferred),
108
+ * not its semantic category. For semantic categories (identity, skill, etc.),
109
+ * see FactSemanticCategory in profile.base.ts
110
+ */
111
+ export type FactCategory = FactLifecycleCategory
112
+
113
+ /**
114
+ * API-level ProfileFact - simplified version for API contracts
115
+ * Extends BaseProfileFact with key-value structure for API compatibility
116
+ */
117
+ export interface ProfileFact extends BaseProfileFact {
118
+ /** Key for the fact (for key-value style access) */
119
+ key: string
120
+ /** Value of the fact */
121
+ value: string
122
+ /** Lifecycle category */
123
+ category: FactCategory
124
+ /** Source identifier */
125
+ source?: string
126
+ }
127
+
128
+ export interface Profile {
129
+ id: string
130
+ name?: string
131
+ facts: ProfileFact[]
132
+ memories: string[]
133
+ containerTags: string[]
134
+ createdAt: Date
135
+ updatedAt: Date
136
+ }
137
+
138
+ // ============================================================================
139
+ // Extraction Types
140
+ // ============================================================================
141
+
142
+ export const ContentTypeSchema = z.enum(['text', 'url', 'markdown', 'html', 'json', 'pdf', 'image', 'unknown'])
143
+
144
+ export type ContentType = z.infer<typeof ContentTypeSchema>
145
+
146
+ export const ChunkingStrategySchema = z.enum(['sentence', 'paragraph', 'fixed', 'semantic', 'sliding_window'])
147
+
148
+ export type ChunkingStrategy = z.infer<typeof ChunkingStrategySchema>
149
+
150
+ export interface ExtractionResult {
151
+ content: string
152
+ contentType: ContentType
153
+ chunks: ContentChunk[]
154
+ metadata: ExtractionMetadata
155
+ }
156
+
157
+ export interface ContentChunk {
158
+ id: string
159
+ content: string
160
+ index: number
161
+ startOffset: number
162
+ endOffset: number
163
+ metadata?: Record<string, unknown>
164
+ }
165
+
166
+ export interface ExtractionMetadata {
167
+ originalLength: number
168
+ chunkCount: number
169
+ processingTime: number
170
+ strategy: ChunkingStrategy
171
+ sourceUrl?: string
172
+ title?: string
173
+ author?: string
174
+ publishedAt?: Date
175
+ }
176
+
177
+ // ============================================================================
178
+ // Document Types
179
+ // ============================================================================
180
+
181
+ export const DocumentSchema = z.object({
182
+ id: z.string().optional(),
183
+ content: z.string().min(1, 'Content is required'),
184
+ containerTag: z.string().optional(),
185
+ metadata: z.record(z.unknown()).optional(),
186
+ })
187
+
188
+ export type DocumentInput = z.infer<typeof DocumentSchema>
189
+
190
+ export interface Document {
191
+ id: string
192
+ content: string
193
+ containerTag?: string
194
+ memories: Memory[]
195
+ metadata: Record<string, unknown>
196
+ createdAt: Date
197
+ updatedAt: Date
198
+ }
199
+
200
+ // ============================================================================
201
+ // API Types
202
+ // ============================================================================
203
+
204
+ export interface APIError {
205
+ code: string
206
+ message: string
207
+ details?: unknown
208
+ }
209
+
210
+ export interface APIResponse<T> {
211
+ success: boolean
212
+ data?: T
213
+ error?: APIError
214
+ }
215
+
216
+ export interface PaginatedResponse<T> extends APIResponse<T[]> {
217
+ pagination: {
218
+ total: number
219
+ limit: number
220
+ offset: number
221
+ hasMore: boolean
222
+ }
223
+ }
224
+
225
+ // ============================================================================
226
+ // SDK Types
227
+ // ============================================================================
228
+
229
+ export interface SDKConfig {
230
+ apiKey: string
231
+ baseUrl?: string
232
+ timeout?: number
233
+ retries?: number
234
+ retryDelay?: number
235
+ }
236
+
237
+ export interface RateLimitInfo {
238
+ limit: number
239
+ remaining: number
240
+ reset: Date
241
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Base Profile Types for Supermemory Clone
3
+ *
4
+ * Shared base interfaces for profile-related types to prevent duplication
5
+ * across profile.types.ts and types/index.ts
6
+ */
7
+
8
+ import { z } from 'zod'
9
+
10
+ // ============================================================================
11
+ // Base Schemas
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Fact lifecycle category - determines expiration behavior
16
+ * Used in types/index.ts Profile system
17
+ */
18
+ export const FactLifecycleCategorySchema = z.enum([
19
+ 'static', // Long-term, rarely changes
20
+ 'dynamic', // Temporary, expires over time
21
+ 'inferred', // Derived from other facts
22
+ ])
23
+
24
+ export type FactLifecycleCategory = z.infer<typeof FactLifecycleCategorySchema>
25
+
26
+ /**
27
+ * Fact semantic category - describes what the fact is about
28
+ * Used in services/profile.types.ts ProfileFact
29
+ */
30
+ export const FactSemanticCategorySchema = z.enum([
31
+ 'identity', // Name, role, company
32
+ 'preference', // Likes, dislikes, preferences
33
+ 'skill', // Technical skills, expertise
34
+ 'background', // Education, history
35
+ 'relationship', // Connections, team members
36
+ 'project', // Current/past projects
37
+ 'goal', // Objectives, aspirations
38
+ 'context', // Current situation, temporary context
39
+ 'other', // Uncategorized
40
+ ])
41
+
42
+ export type FactSemanticCategory = z.infer<typeof FactSemanticCategorySchema>
43
+
44
+ /**
45
+ * Fact type - static or dynamic lifecycle
46
+ */
47
+ export const FactTypeSchema = z.enum(['static', 'dynamic'])
48
+
49
+ export type FactType = z.infer<typeof FactTypeSchema>
50
+
51
+ // ============================================================================
52
+ // Base ProfileFact Schema
53
+ // ============================================================================
54
+
55
+ /**
56
+ * Base schema for ProfileFact - shared between service and type layers
57
+ * Contains the common fields that all ProfileFact implementations must have
58
+ */
59
+ export const BaseProfileFactSchema = z.object({
60
+ /** Unique identifier for the fact */
61
+ id: z.string(),
62
+
63
+ /** The actual fact content */
64
+ content: z.string().min(1),
65
+
66
+ /** Confidence score of the extraction (0-1) */
67
+ confidence: z.number().min(0).max(1),
68
+
69
+ /** When this fact was created/extracted */
70
+ createdAt: z.date(),
71
+
72
+ /** When this fact was last updated */
73
+ updatedAt: z.date(),
74
+
75
+ /** Source content or document this was extracted from */
76
+ sourceId: z.string().optional(),
77
+ })
78
+
79
+ export type BaseProfileFact = z.infer<typeof BaseProfileFactSchema>
80
+
81
+ // ============================================================================
82
+ // Service Layer ProfileFact (extended version)
83
+ // ============================================================================
84
+
85
+ /**
86
+ * Service layer ProfileFact schema - used in profile.service.ts
87
+ * Extends base with service-specific fields
88
+ */
89
+ export const ServiceProfileFactSchema = BaseProfileFactSchema.extend({
90
+ /** Whether this is a static (long-term) or dynamic (temporary) fact */
91
+ type: FactTypeSchema,
92
+
93
+ /** When this fact was extracted */
94
+ extractedAt: z.date(),
95
+
96
+ /** When this fact expires (only for dynamic facts) */
97
+ expiresAt: z.date().optional(),
98
+
99
+ /** Category of the fact for organization */
100
+ category: FactSemanticCategorySchema.optional(),
101
+
102
+ /** Number of times this fact has been reinforced */
103
+ reinforcementCount: z.number().int().min(0),
104
+
105
+ /** Last time this fact was accessed or reinforced */
106
+ lastAccessedAt: z.date(),
107
+ })
108
+
109
+ export type ServiceProfileFact = z.infer<typeof ServiceProfileFactSchema>
110
+
111
+ // ============================================================================
112
+ // Type Layer ProfileFact (API version)
113
+ // ============================================================================
114
+
115
+ /**
116
+ * Type layer ProfileFact schema - used in types/index.ts
117
+ * Simpler version for API contracts
118
+ */
119
+ export const TypeProfileFactSchema = BaseProfileFactSchema.extend({
120
+ /** Key-value style fact key */
121
+ key: z.string(),
122
+
123
+ /** Fact value */
124
+ value: z.string(),
125
+
126
+ /** Lifecycle category */
127
+ category: FactLifecycleCategorySchema,
128
+
129
+ /** Source identifier */
130
+ source: z.string().optional(),
131
+ })
132
+
133
+ export type TypeProfileFact = z.infer<typeof TypeProfileFactSchema>