@undefineds.co/xpod 0.3.5 → 0.3.14

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 (253) hide show
  1. package/config/cli.json +1 -1
  2. package/config/cloud.json +54 -22
  3. package/config/local.json +56 -12
  4. package/config/resolver.json +10 -2
  5. package/config/xpod.base.json +50 -0
  6. package/config/xpod.json +8 -8
  7. package/dist/agents/config/resolve.js +10 -10
  8. package/dist/agents/config/resolve.js.map +1 -1
  9. package/dist/api/chatkit/index.d.ts +1 -1
  10. package/dist/api/chatkit/index.js.map +1 -1
  11. package/dist/api/chatkit/pod-store.d.ts +14 -11
  12. package/dist/api/chatkit/pod-store.js +114 -78
  13. package/dist/api/chatkit/pod-store.js.map +1 -1
  14. package/dist/api/chatkit/runtime/AcpAgentRuntime.js +1 -1
  15. package/dist/api/chatkit/runtime/AcpAgentRuntime.js.map +1 -1
  16. package/dist/api/chatkit/service.js +1 -1
  17. package/dist/api/chatkit/service.js.map +1 -1
  18. package/dist/api/chatkit/types.d.ts +11 -11
  19. package/dist/api/chatkit/types.js +3 -3
  20. package/dist/api/chatkit/types.js.map +1 -1
  21. package/dist/api/container/cloud.js +0 -8
  22. package/dist/api/container/cloud.js.map +1 -1
  23. package/dist/api/container/index.js +2 -1
  24. package/dist/api/container/index.js.map +1 -1
  25. package/dist/api/container/local.js +0 -7
  26. package/dist/api/container/local.js.map +1 -1
  27. package/dist/api/container/routes.js +3 -17
  28. package/dist/api/container/routes.js.map +1 -1
  29. package/dist/api/container/types.d.ts +0 -2
  30. package/dist/api/container/types.js.map +1 -1
  31. package/dist/api/handlers/PodManagementHandler.d.ts +3 -0
  32. package/dist/api/handlers/PodManagementHandler.js +71 -1
  33. package/dist/api/handlers/PodManagementHandler.js.map +1 -1
  34. package/dist/api/handlers/RunHandler.js +5 -5
  35. package/dist/api/handlers/RunHandler.js.map +1 -1
  36. package/dist/api/runs/AgentRuntimeTypes.d.ts +7 -8
  37. package/dist/api/runs/AgentRuntimeTypes.js.map +1 -1
  38. package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
  39. package/dist/api/runs/ManagedRunWorker.d.ts +1 -1
  40. package/dist/api/runs/ManagedRunWorker.js +6 -6
  41. package/dist/api/runs/ManagedRunWorker.js.map +1 -1
  42. package/dist/api/runs/PiAgentRuntimeDriver.d.ts +16 -1
  43. package/dist/api/runs/PiAgentRuntimeDriver.js +182 -23
  44. package/dist/api/runs/PiAgentRuntimeDriver.js.map +1 -1
  45. package/dist/api/runs/RunStateCenter.d.ts +3 -3
  46. package/dist/api/runs/RunStateCenter.js +13 -13
  47. package/dist/api/runs/RunStateCenter.js.map +1 -1
  48. package/dist/api/runs/store.d.ts +4 -4
  49. package/dist/api/runs/store.js +2 -2
  50. package/dist/api/runs/store.js.map +1 -1
  51. package/dist/api/service/VectorStoreService.d.ts +1 -1
  52. package/dist/api/service/VectorStoreService.js +16 -16
  53. package/dist/api/service/VectorStoreService.js.map +1 -1
  54. package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
  55. package/dist/api/tasks/TaskMaterializer.d.ts +3 -3
  56. package/dist/api/tasks/TaskMaterializer.js +11 -11
  57. package/dist/api/tasks/TaskMaterializer.js.map +1 -1
  58. package/dist/api/tasks/TaskService.d.ts +3 -3
  59. package/dist/api/tasks/TaskService.js +11 -7
  60. package/dist/api/tasks/TaskService.js.map +1 -1
  61. package/dist/api/tasks/store.d.ts +10 -4
  62. package/dist/api/tasks/store.js +14 -4
  63. package/dist/api/tasks/store.js.map +1 -1
  64. package/dist/api/workspace/types.d.ts +3 -3
  65. package/dist/api/workspace/types.js +6 -6
  66. package/dist/api/workspace/types.js.map +1 -1
  67. package/dist/cli/commands/config.js +2 -2
  68. package/dist/cli/commands/config.js.map +1 -1
  69. package/dist/cli/commands/start.js +9 -3
  70. package/dist/cli/commands/start.js.map +1 -1
  71. package/dist/components/components.jsonld +8 -2
  72. package/dist/components/context.jsonld +302 -51
  73. package/dist/http/search/SearchHttpHandler.js +8 -8
  74. package/dist/http/search/SearchHttpHandler.js.map +1 -1
  75. package/dist/identity/drizzle/PodLookupRepository.d.ts +11 -1
  76. package/dist/identity/drizzle/PodLookupRepository.js +95 -4
  77. package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
  78. package/dist/identity/drizzle/db.js +4 -43
  79. package/dist/identity/drizzle/db.js.map +1 -1
  80. package/dist/identity/drizzle/schema.pg.d.ts +0 -5
  81. package/dist/identity/drizzle/schema.pg.js +2 -16
  82. package/dist/identity/drizzle/schema.pg.js.map +1 -1
  83. package/dist/identity/drizzle/schema.sqlite.d.ts +19 -176
  84. package/dist/identity/drizzle/schema.sqlite.js +2 -16
  85. package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
  86. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.d.ts +4 -4
  87. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js +7 -7
  88. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js.map +1 -1
  89. package/dist/identity/oidc/AutoDetectIdentityProviderHandler.jsonld +6 -6
  90. package/dist/identity/oidc/AutoDetectOidcHandler.d.ts +4 -4
  91. package/dist/identity/oidc/AutoDetectOidcHandler.js +6 -6
  92. package/dist/identity/oidc/AutoDetectOidcHandler.js.map +1 -1
  93. package/dist/identity/oidc/AutoDetectOidcHandler.jsonld +6 -6
  94. package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +37 -0
  95. package/dist/identity/oidc/ScopedPickWebIdHandler.js +211 -0
  96. package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -0
  97. package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +158 -0
  98. package/dist/index.d.ts +12 -2
  99. package/dist/index.js +16 -4
  100. package/dist/index.js.map +1 -1
  101. package/dist/main.js +8 -2
  102. package/dist/main.js.map +1 -1
  103. package/dist/provision/ProvisionPodCreator.d.ts +3 -4
  104. package/dist/provision/ProvisionPodCreator.js +8 -13
  105. package/dist/provision/ProvisionPodCreator.js.map +1 -1
  106. package/dist/provision/ProvisionPodCreator.jsonld +7 -7
  107. package/dist/runtime/Proxy.d.ts +0 -1
  108. package/dist/runtime/Proxy.js +0 -9
  109. package/dist/runtime/Proxy.js.map +1 -1
  110. package/dist/runtime/bootstrap.d.ts +1 -0
  111. package/dist/runtime/bootstrap.js +5 -2
  112. package/dist/runtime/bootstrap.js.map +1 -1
  113. package/dist/runtime/css-process.d.ts +12 -4
  114. package/dist/runtime/css-process.js +61 -14
  115. package/dist/runtime/css-process.js.map +1 -1
  116. package/dist/runtime/oidc-issuer.d.ts +3 -2
  117. package/dist/runtime/oidc-issuer.js +3 -2
  118. package/dist/runtime/oidc-issuer.js.map +1 -1
  119. package/dist/runtime/runtime-types.d.ts +1 -0
  120. package/dist/runtime/runtime-types.js.map +1 -1
  121. package/dist/solidfs/LocalFirstRdfRepresentationResolver.d.ts +21 -0
  122. package/dist/solidfs/LocalFirstRdfRepresentationResolver.js +38 -0
  123. package/dist/solidfs/LocalFirstRdfRepresentationResolver.js.map +1 -0
  124. package/dist/solidfs/LocalSolidFS.d.ts +18 -0
  125. package/dist/solidfs/LocalSolidFS.js +539 -0
  126. package/dist/solidfs/LocalSolidFS.js.map +1 -0
  127. package/dist/solidfs/PodSolidFsHttpClient.d.ts +16 -0
  128. package/dist/solidfs/PodSolidFsHttpClient.js +93 -0
  129. package/dist/solidfs/PodSolidFsHttpClient.js.map +1 -0
  130. package/dist/solidfs/PodSolidFsHydrator.d.ts +27 -0
  131. package/dist/solidfs/PodSolidFsHydrator.js +127 -0
  132. package/dist/solidfs/PodSolidFsHydrator.js.map +1 -0
  133. package/dist/solidfs/PodSolidFsSyncer.d.ts +21 -0
  134. package/dist/solidfs/PodSolidFsSyncer.js +78 -0
  135. package/dist/solidfs/PodSolidFsSyncer.js.map +1 -0
  136. package/dist/solidfs/RdfIndexSolidFsSyncer.d.ts +22 -0
  137. package/dist/solidfs/RdfIndexSolidFsSyncer.js +131 -0
  138. package/dist/solidfs/RdfIndexSolidFsSyncer.js.map +1 -0
  139. package/dist/solidfs/index.d.ts +7 -0
  140. package/dist/solidfs/index.js +24 -0
  141. package/dist/solidfs/index.js.map +1 -0
  142. package/dist/solidfs/types.d.ts +131 -0
  143. package/dist/solidfs/types.js +19 -0
  144. package/dist/solidfs/types.js.map +1 -0
  145. package/dist/storage/RepresentationPartialConvertingStore.js +6 -13
  146. package/dist/storage/RepresentationPartialConvertingStore.js.map +1 -1
  147. package/dist/storage/SparqlUpdateResourceStore.d.ts +4 -0
  148. package/dist/storage/SparqlUpdateResourceStore.js +13 -0
  149. package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
  150. package/dist/storage/SparqlUpdateResourceStore.jsonld +26 -0
  151. package/dist/storage/accessors/MinioDataAccessor.d.ts +2 -0
  152. package/dist/storage/accessors/MinioDataAccessor.js +13 -7
  153. package/dist/storage/accessors/MinioDataAccessor.js.map +1 -1
  154. package/dist/storage/accessors/MinioDataAccessor.jsonld +8 -0
  155. package/dist/storage/accessors/MixDataAccessor.d.ts +85 -4
  156. package/dist/storage/accessors/MixDataAccessor.js +511 -16
  157. package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
  158. package/dist/storage/accessors/MixDataAccessor.jsonld +176 -1
  159. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.d.ts +7 -0
  160. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js +72 -4
  161. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js.map +1 -1
  162. package/dist/storage/accessors/QuintStoreSparqlDataAccessor.jsonld +24 -0
  163. package/dist/storage/quint/BaseQuintStore.d.ts +3 -0
  164. package/dist/storage/quint/BaseQuintStore.js +51 -27
  165. package/dist/storage/quint/BaseQuintStore.js.map +1 -1
  166. package/dist/storage/quint/PgQuintStore.d.ts +1 -0
  167. package/dist/storage/quint/PgQuintStore.js +50 -32
  168. package/dist/storage/quint/PgQuintStore.js.map +1 -1
  169. package/dist/storage/quint/PgQuintStore.jsonld +4 -3
  170. package/dist/storage/quint/SqliteQuintStore.d.ts +5 -0
  171. package/dist/storage/quint/SqliteQuintStore.js +100 -0
  172. package/dist/storage/quint/SqliteQuintStore.js.map +1 -1
  173. package/dist/storage/quint/SqliteQuintStore.jsonld +20 -0
  174. package/dist/storage/quint/types.d.ts +16 -0
  175. package/dist/storage/quint/types.js.map +1 -1
  176. package/dist/storage/rdf/Rdf3xTripleIndex.d.ts +55 -0
  177. package/dist/storage/rdf/Rdf3xTripleIndex.js +1235 -0
  178. package/dist/storage/rdf/Rdf3xTripleIndex.js.map +1 -0
  179. package/dist/storage/rdf/RdfContentTypes.d.ts +9 -0
  180. package/dist/storage/rdf/RdfContentTypes.js +79 -0
  181. package/dist/storage/rdf/RdfContentTypes.js.map +1 -0
  182. package/dist/storage/rdf/RdfLocalQueryEngine.d.ts +76 -0
  183. package/dist/storage/rdf/RdfLocalQueryEngine.js +2636 -0
  184. package/dist/storage/rdf/RdfLocalQueryEngine.js.map +1 -0
  185. package/dist/storage/rdf/RdfQuadIndex.d.ts +98 -0
  186. package/dist/storage/rdf/RdfQuadIndex.js +1840 -0
  187. package/dist/storage/rdf/RdfQuadIndex.js.map +1 -0
  188. package/dist/storage/rdf/RdfQuadIndex.jsonld +416 -0
  189. package/dist/storage/rdf/RdfShadowComparator.d.ts +12 -0
  190. package/dist/storage/rdf/RdfShadowComparator.js +47 -0
  191. package/dist/storage/rdf/RdfShadowComparator.js.map +1 -0
  192. package/dist/storage/rdf/RdfSparqlAdapter.d.ts +147 -0
  193. package/dist/storage/rdf/RdfSparqlAdapter.js +2420 -0
  194. package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -0
  195. package/dist/storage/rdf/RdfSparqlAdapter.jsonld +414 -0
  196. package/dist/storage/rdf/RdfTermDictionary.d.ts +27 -0
  197. package/dist/storage/rdf/RdfTermDictionary.js +352 -0
  198. package/dist/storage/rdf/RdfTermDictionary.js.map +1 -0
  199. package/dist/storage/rdf/RdfTermDictionary.jsonld +114 -0
  200. package/dist/storage/rdf/RdfTermSemantics.d.ts +6 -0
  201. package/dist/storage/rdf/RdfTermSemantics.js +40 -0
  202. package/dist/storage/rdf/RdfTermSemantics.js.map +1 -0
  203. package/dist/storage/rdf/RdfTextIndex.d.ts +23 -0
  204. package/dist/storage/rdf/RdfTextIndex.js +569 -0
  205. package/dist/storage/rdf/RdfTextIndex.js.map +1 -0
  206. package/dist/storage/rdf/RdfVectorIndex.d.ts +22 -0
  207. package/dist/storage/rdf/RdfVectorIndex.js +631 -0
  208. package/dist/storage/rdf/RdfVectorIndex.js.map +1 -0
  209. package/dist/storage/rdf/RdfXmlSerializer.d.ts +2 -0
  210. package/dist/storage/rdf/RdfXmlSerializer.js +123 -0
  211. package/dist/storage/rdf/RdfXmlSerializer.js.map +1 -0
  212. package/dist/storage/rdf/ShadowRdfQuintStore.d.ts +58 -0
  213. package/dist/storage/rdf/ShadowRdfQuintStore.js +202 -0
  214. package/dist/storage/rdf/ShadowRdfQuintStore.js.map +1 -0
  215. package/dist/storage/rdf/ShadowRdfQuintStore.jsonld +308 -0
  216. package/dist/storage/rdf/SolidRdfEngine.d.ts +51 -0
  217. package/dist/storage/rdf/SolidRdfEngine.js +264 -0
  218. package/dist/storage/rdf/SolidRdfEngine.js.map +1 -0
  219. package/dist/storage/rdf/SolidRdfEngine.jsonld +338 -0
  220. package/dist/storage/rdf/SolidRdfSparqlEngine.d.ts +92 -0
  221. package/dist/storage/rdf/SolidRdfSparqlEngine.js +477 -0
  222. package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -0
  223. package/dist/storage/rdf/SolidRdfSparqlEngine.jsonld +257 -0
  224. package/dist/storage/rdf/index.d.ts +15 -0
  225. package/dist/storage/rdf/index.js +61 -0
  226. package/dist/storage/rdf/index.js.map +1 -0
  227. package/dist/storage/rdf/models-benchmark.d.ts +260 -0
  228. package/dist/storage/rdf/models-benchmark.js +1405 -0
  229. package/dist/storage/rdf/models-benchmark.js.map +1 -0
  230. package/dist/storage/rdf/types.d.ts +726 -0
  231. package/dist/storage/rdf/types.js +3 -0
  232. package/dist/storage/rdf/types.js.map +1 -0
  233. package/dist/storage/rdf/types.jsonld +316 -0
  234. package/dist/storage/vector/VectorIndexingListener.d.ts +5 -5
  235. package/dist/storage/vector/VectorIndexingListener.js +19 -19
  236. package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
  237. package/package.json +3 -2
  238. package/templates/pod/acp/.acr.hbs +39 -0
  239. package/templates/pod/acp/README.acr +18 -0
  240. package/templates/pod/acp/profile/card.acr +22 -0
  241. package/templates/pod/base/README$.md.hbs +27 -0
  242. package/templates/pod/base/profile/card$.ttl.hbs +13 -0
  243. package/templates/pod/wac/.acl.hbs +26 -0
  244. package/templates/pod/wac/README.acl.hbs +14 -0
  245. package/templates/pod/wac/profile/card.acl.hbs +19 -0
  246. package/dist/api/handlers/WebIdProfileHandler.d.ts +0 -16
  247. package/dist/api/handlers/WebIdProfileHandler.js +0 -423
  248. package/dist/api/handlers/WebIdProfileHandler.js.map +0 -1
  249. package/dist/identity/drizzle/WebIdProfileRepository.d.ts +0 -63
  250. package/dist/identity/drizzle/WebIdProfileRepository.js +0 -168
  251. package/dist/identity/drizzle/WebIdProfileRepository.js.map +0 -1
  252. package/dist/identity/drizzle/WebIdProfileRepository.jsonld +0 -112
  253. package/dist/storage/quint/BaseQuintStore.jsonld +0 -257
@@ -0,0 +1,569 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RdfTextIndex = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ const HeadingChunker_1 = require("../../document/HeadingChunker");
8
+ const SqliteRuntime_1 = require("../SqliteRuntime");
9
+ class RdfTextIndex {
10
+ constructor(options) {
11
+ this.options = options;
12
+ this.sqliteRuntime = (0, SqliteRuntime_1.createSqliteRuntime)();
13
+ this.db = null;
14
+ }
15
+ open() {
16
+ if (this.db) {
17
+ return;
18
+ }
19
+ if (this.options.path !== ':memory:') {
20
+ const dir = (0, node_path_1.dirname)(this.options.path);
21
+ if (!(0, node_fs_1.existsSync)(dir)) {
22
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
23
+ }
24
+ }
25
+ this.db = this.sqliteRuntime.openDatabase(this.options.path);
26
+ this.initializeSchema();
27
+ }
28
+ close() {
29
+ this.db?.close();
30
+ this.db = null;
31
+ }
32
+ clear() {
33
+ this.requireDb().exec('DELETE FROM rdf_text_terms; DELETE FROM rdf_text_chunks; DELETE FROM rdf_text_sources;');
34
+ }
35
+ indexText(source, text, chunks) {
36
+ const db = this.requireDb();
37
+ const indexedChunks = chunks ?? this.chunkText(source, text);
38
+ const sourceId = this.upsertSource({
39
+ ...source,
40
+ sourceHash: source.sourceHash ?? sha256(text),
41
+ });
42
+ const insertChunk = db.prepare(`
43
+ INSERT INTO rdf_text_chunks (
44
+ source_id,
45
+ chunk_key,
46
+ ordinal,
47
+ level,
48
+ heading,
49
+ path,
50
+ content,
51
+ start_offset,
52
+ end_offset,
53
+ normalized_text,
54
+ token_count,
55
+ updated_at
56
+ )
57
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
58
+ `);
59
+ const insertTerm = db.prepare(`
60
+ INSERT INTO rdf_text_terms (
61
+ term,
62
+ source_id,
63
+ chunk_id,
64
+ occurrences,
65
+ updated_at
66
+ )
67
+ VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
68
+ `);
69
+ db.transaction(() => {
70
+ db.prepare('DELETE FROM rdf_text_terms WHERE source_id = ?').run(sourceId);
71
+ db.prepare('DELETE FROM rdf_text_chunks WHERE source_id = ?').run(sourceId);
72
+ for (const chunk of indexedChunks) {
73
+ const normalizedText = normalizeText(chunk.content);
74
+ const result = insertChunk.run(sourceId, chunk.chunkKey, chunk.ordinal, chunk.level, chunk.heading || null, JSON.stringify(chunk.path ?? []), chunk.content, chunk.startOffset, chunk.endOffset, normalizedText, tokenCountNormalized(normalizedText));
75
+ insertTermOccurrences(insertTerm, sourceId, Number(result.lastInsertRowid), normalizedText);
76
+ }
77
+ })();
78
+ }
79
+ deleteSource(source) {
80
+ const db = this.requireDb();
81
+ const row = db.prepare('SELECT id FROM rdf_text_sources WHERE source = ?').get(source);
82
+ if (!row) {
83
+ return 0;
84
+ }
85
+ return db.transaction(() => {
86
+ db.prepare('DELETE FROM rdf_text_terms WHERE source_id = ?').run(row.id);
87
+ const deletedChunks = db.prepare('DELETE FROM rdf_text_chunks WHERE source_id = ?').run(row.id).changes;
88
+ db.prepare('DELETE FROM rdf_text_sources WHERE id = ?').run(row.id);
89
+ return deletedChunks;
90
+ })();
91
+ }
92
+ search(options) {
93
+ const query = normalizeText(options.query);
94
+ if (!query) {
95
+ return [];
96
+ }
97
+ const predicate = buildTextSearchPredicate(query);
98
+ const params = [...predicate.params];
99
+ const conditions = [predicate.sql];
100
+ if (options.workspace) {
101
+ conditions.push('source.workspace = ?');
102
+ params.push(options.workspace);
103
+ }
104
+ if (options.source) {
105
+ conditions.push('source.source = ?');
106
+ params.push(options.source);
107
+ }
108
+ if (options.sourcePrefix) {
109
+ conditions.push('source.source >= ? AND source.source < ?');
110
+ params.push(options.sourcePrefix, `${options.sourcePrefix}\uffff`);
111
+ }
112
+ const sql = `
113
+ SELECT
114
+ chunk.id,
115
+ chunk.source_id,
116
+ source.source,
117
+ source.workspace,
118
+ source.local_path,
119
+ source.content_type,
120
+ source.source_version,
121
+ source.source_hash,
122
+ chunk.chunk_key,
123
+ chunk.ordinal,
124
+ chunk.level,
125
+ chunk.heading,
126
+ chunk.path,
127
+ chunk.content,
128
+ chunk.start_offset,
129
+ chunk.end_offset,
130
+ chunk.normalized_text,
131
+ chunk.token_count,
132
+ chunk.updated_at
133
+ FROM rdf_text_chunks chunk
134
+ JOIN rdf_text_sources source ON source.id = chunk.source_id
135
+ WHERE ${conditions.join(' AND ')}
136
+ ORDER BY chunk.source_id ASC, chunk.ordinal ASC
137
+ `;
138
+ const rows = this.requireDb().prepare(sql).all(...params);
139
+ const results = rows
140
+ .map((row) => ({ row, score: occurrenceCount(row.normalized_text, query) }))
141
+ .filter((result) => result.score > 0)
142
+ .sort((left, right) => compareTextSearchHits(left, right, options.orderBy))
143
+ .map((result) => this.toSearchResult(result.row, result.score));
144
+ return results.slice(options.offset ?? 0, options.limit === undefined ? undefined : (options.offset ?? 0) + options.limit);
145
+ }
146
+ estimateSearchCardinality(options) {
147
+ const query = normalizeText(options.query);
148
+ if (!query) {
149
+ return {
150
+ rows: 0,
151
+ source: 'text-normalized-scan',
152
+ indexChoice: 'text-normalized-scan',
153
+ };
154
+ }
155
+ const predicate = buildTextSearchPredicate(query);
156
+ const params = [...predicate.params];
157
+ const conditions = [predicate.sql];
158
+ if (options.workspace) {
159
+ conditions.push('source.workspace = ?');
160
+ params.push(options.workspace);
161
+ }
162
+ if (options.source) {
163
+ conditions.push('source.source = ?');
164
+ params.push(options.source);
165
+ }
166
+ if (options.sourcePrefix) {
167
+ conditions.push('source.source >= ? AND source.source < ?');
168
+ params.push(options.sourcePrefix, `${options.sourcePrefix}\uffff`);
169
+ }
170
+ const rows = this.requireDb().prepare(`
171
+ SELECT COUNT(*) AS count
172
+ FROM rdf_text_chunks chunk
173
+ JOIN rdf_text_sources source ON source.id = chunk.source_id
174
+ WHERE ${conditions.join(' AND ')}
175
+ `).get(...params)?.count ?? 0;
176
+ return {
177
+ rows: applyResultWindow(rows, options.offset, options.limit),
178
+ source: predicate.indexChoice,
179
+ indexChoice: predicate.indexChoice,
180
+ };
181
+ }
182
+ stats() {
183
+ const db = this.requireDb();
184
+ return {
185
+ sourceCount: db.prepare('SELECT COUNT(*) AS count FROM rdf_text_sources').get()?.count ?? 0,
186
+ chunkCount: db.prepare('SELECT COUNT(*) AS count FROM rdf_text_chunks').get()?.count ?? 0,
187
+ databaseBytes: this.estimateDatabaseBytes(),
188
+ termDocumentFrequency: this.termDocumentFrequency(),
189
+ };
190
+ }
191
+ termDocumentFrequency(limit = 100) {
192
+ const rows = this.requireDb().prepare(`
193
+ SELECT
194
+ term,
195
+ COUNT(DISTINCT source_id) AS source_count,
196
+ COUNT(*) AS chunk_count,
197
+ COALESCE(SUM(occurrences), 0) AS total_occurrences
198
+ FROM rdf_text_terms
199
+ GROUP BY term
200
+ ORDER BY source_count DESC, chunk_count DESC, total_occurrences DESC, term ASC
201
+ LIMIT ?
202
+ `).all(Math.max(0, limit));
203
+ return rows
204
+ .map((row) => ({
205
+ term: row.term,
206
+ sourceCount: row.source_count,
207
+ chunkCount: row.chunk_count,
208
+ totalOccurrences: row.total_occurrences,
209
+ }));
210
+ }
211
+ initializeSchema() {
212
+ this.requireDb().exec(`
213
+ CREATE TABLE IF NOT EXISTS rdf_text_sources (
214
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
215
+ source TEXT NOT NULL UNIQUE,
216
+ workspace TEXT NOT NULL,
217
+ local_path TEXT,
218
+ content_type TEXT,
219
+ source_version TEXT,
220
+ source_hash TEXT,
221
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
222
+ );
223
+
224
+ CREATE TABLE IF NOT EXISTS rdf_text_chunks (
225
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
226
+ source_id INTEGER NOT NULL,
227
+ chunk_key TEXT NOT NULL,
228
+ ordinal INTEGER NOT NULL,
229
+ level INTEGER NOT NULL,
230
+ heading TEXT,
231
+ path TEXT,
232
+ content TEXT NOT NULL,
233
+ start_offset INTEGER NOT NULL,
234
+ end_offset INTEGER NOT NULL,
235
+ normalized_text TEXT NOT NULL,
236
+ token_count INTEGER NOT NULL,
237
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
238
+ UNIQUE (source_id, chunk_key),
239
+ FOREIGN KEY (source_id) REFERENCES rdf_text_sources(id)
240
+ );
241
+
242
+ CREATE TABLE IF NOT EXISTS rdf_text_terms (
243
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
244
+ term TEXT NOT NULL,
245
+ source_id INTEGER NOT NULL,
246
+ chunk_id INTEGER NOT NULL,
247
+ occurrences INTEGER NOT NULL,
248
+ updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
249
+ UNIQUE (term, chunk_id),
250
+ FOREIGN KEY (source_id) REFERENCES rdf_text_sources(id),
251
+ FOREIGN KEY (chunk_id) REFERENCES rdf_text_chunks(id)
252
+ );
253
+
254
+ CREATE INDEX IF NOT EXISTS rdf_text_sources_workspace ON rdf_text_sources(workspace);
255
+ CREATE INDEX IF NOT EXISTS rdf_text_sources_source ON rdf_text_sources(source);
256
+ CREATE INDEX IF NOT EXISTS rdf_text_chunks_source ON rdf_text_chunks(source_id, ordinal);
257
+ CREATE INDEX IF NOT EXISTS rdf_text_chunks_normalized ON rdf_text_chunks(normalized_text);
258
+ CREATE INDEX IF NOT EXISTS rdf_text_terms_term ON rdf_text_terms(term);
259
+ CREATE INDEX IF NOT EXISTS rdf_text_terms_source_term ON rdf_text_terms(source_id, term);
260
+ CREATE INDEX IF NOT EXISTS rdf_text_terms_chunk ON rdf_text_terms(chunk_id);
261
+ `);
262
+ this.backfillTermPostings();
263
+ }
264
+ backfillTermPostings() {
265
+ const db = this.requireDb();
266
+ const rows = db.prepare(`
267
+ SELECT chunk.id, chunk.source_id, chunk.normalized_text
268
+ FROM rdf_text_chunks chunk
269
+ LEFT JOIN rdf_text_terms term ON term.chunk_id = chunk.id
270
+ WHERE term.chunk_id IS NULL AND chunk.normalized_text <> ''
271
+ `).all();
272
+ if (rows.length === 0) {
273
+ return;
274
+ }
275
+ const insertTerm = db.prepare(`
276
+ INSERT INTO rdf_text_terms (
277
+ term,
278
+ source_id,
279
+ chunk_id,
280
+ occurrences,
281
+ updated_at
282
+ )
283
+ VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
284
+ `);
285
+ db.transaction(() => {
286
+ for (const row of rows) {
287
+ insertTermOccurrences(insertTerm, row.source_id, row.id, row.normalized_text);
288
+ }
289
+ })();
290
+ }
291
+ upsertSource(source) {
292
+ const db = this.requireDb();
293
+ db.prepare(`
294
+ INSERT INTO rdf_text_sources (
295
+ source,
296
+ workspace,
297
+ local_path,
298
+ content_type,
299
+ source_version,
300
+ source_hash,
301
+ updated_at
302
+ )
303
+ VALUES (?, ?, ?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
304
+ ON CONFLICT (source)
305
+ DO UPDATE SET
306
+ workspace = excluded.workspace,
307
+ local_path = excluded.local_path,
308
+ content_type = excluded.content_type,
309
+ source_version = excluded.source_version,
310
+ source_hash = excluded.source_hash,
311
+ updated_at = excluded.updated_at
312
+ `).run(source.source, source.workspace, source.localPath ?? null, source.contentType ?? null, source.sourceVersion ?? null, source.sourceHash ?? null);
313
+ const row = db.prepare('SELECT * FROM rdf_text_sources WHERE source = ?').get(source.source);
314
+ if (!row) {
315
+ throw new Error(`Failed to upsert RDF text source: ${source.source}`);
316
+ }
317
+ return row.id;
318
+ }
319
+ chunkText(source, text) {
320
+ if (!text) {
321
+ return [];
322
+ }
323
+ if (isMarkdownSource(source)) {
324
+ const chunker = new HeadingChunker_1.HeadingChunker();
325
+ return chunker.flatten(chunker.chunk(text))
326
+ .filter((chunk) => chunk.content.trim().length > 0)
327
+ .map((chunk, index) => ({
328
+ chunkKey: deterministicChunkKey(source.source, index),
329
+ ordinal: index,
330
+ level: chunk.level,
331
+ heading: chunk.heading || undefined,
332
+ path: chunk.path,
333
+ content: chunk.content,
334
+ startOffset: chunk.startOffset,
335
+ endOffset: chunk.endOffset,
336
+ }));
337
+ }
338
+ return chunkPlainText(source.source, text);
339
+ }
340
+ estimateDatabaseBytes() {
341
+ const db = this.requireDb();
342
+ try {
343
+ const pageCount = db.prepare('PRAGMA page_count').get()?.page_count ?? 0;
344
+ const pageSize = db.prepare('PRAGMA page_size').get()?.page_size ?? 0;
345
+ return pageCount * pageSize;
346
+ }
347
+ catch {
348
+ return 0;
349
+ }
350
+ }
351
+ toSearchResult(row, score) {
352
+ return {
353
+ source: row.source,
354
+ workspace: row.workspace,
355
+ localPath: row.local_path ?? undefined,
356
+ contentType: row.content_type ?? undefined,
357
+ sourceVersion: row.source_version ?? undefined,
358
+ sourceHash: row.source_hash ?? undefined,
359
+ chunkKey: row.chunk_key,
360
+ ordinal: row.ordinal,
361
+ level: row.level,
362
+ heading: row.heading ?? undefined,
363
+ path: parsePath(row.path),
364
+ content: row.content,
365
+ startOffset: row.start_offset,
366
+ endOffset: row.end_offset,
367
+ score,
368
+ };
369
+ }
370
+ requireDb() {
371
+ if (!this.db) {
372
+ throw new Error('RdfTextIndex is not open');
373
+ }
374
+ return this.db;
375
+ }
376
+ }
377
+ exports.RdfTextIndex = RdfTextIndex;
378
+ function isMarkdownSource(source) {
379
+ const contentType = source.contentType?.split(';', 1)[0]?.trim().toLowerCase();
380
+ if (contentType === 'text/markdown' || contentType === 'text/x-markdown') {
381
+ return true;
382
+ }
383
+ const path = source.localPath ?? source.source;
384
+ return ['.md', '.markdown', '.mdown'].includes((0, node_path_1.extname)(path).toLowerCase());
385
+ }
386
+ function chunkPlainText(source, text) {
387
+ const chunks = [];
388
+ const paragraphPattern = /[^\S\r\n]*(?:\r?\n){2,}[^\S\r\n]*/g;
389
+ let ordinal = 0;
390
+ let start = 0;
391
+ let match;
392
+ while ((match = paragraphPattern.exec(text)) !== null) {
393
+ const end = match.index;
394
+ ordinal = pushPlainChunk(chunks, source, ordinal, text, start, end);
395
+ start = match.index + match[0].length;
396
+ }
397
+ pushPlainChunk(chunks, source, ordinal, text, start, text.length);
398
+ if (chunks.length <= 1 && /\r?\n/.test(text)) {
399
+ return chunkLines(source, text);
400
+ }
401
+ return chunks;
402
+ }
403
+ function chunkLines(source, text) {
404
+ const chunks = [];
405
+ const lines = text.split(/\r?\n/);
406
+ let offset = 0;
407
+ let ordinal = 0;
408
+ for (const line of lines) {
409
+ const start = offset;
410
+ const end = start + line.length;
411
+ ordinal = pushPlainChunk(chunks, source, ordinal, text, start, end);
412
+ offset = end + (text.slice(end, end + 2) === '\r\n' ? 2 : 1);
413
+ }
414
+ return chunks;
415
+ }
416
+ function pushPlainChunk(chunks, source, ordinal, text, start, end) {
417
+ const content = text.slice(start, end).trim();
418
+ if (!content) {
419
+ return ordinal;
420
+ }
421
+ chunks.push({
422
+ chunkKey: deterministicChunkKey(source, ordinal),
423
+ ordinal,
424
+ level: 0,
425
+ path: [],
426
+ content,
427
+ startOffset: start,
428
+ endOffset: end,
429
+ });
430
+ return ordinal + 1;
431
+ }
432
+ function deterministicChunkKey(source, ordinal) {
433
+ return (0, node_crypto_1.createHash)('sha256')
434
+ .update(source)
435
+ .update('\0')
436
+ .update(String(ordinal))
437
+ .digest('hex')
438
+ .slice(0, 24);
439
+ }
440
+ function sha256(value) {
441
+ return (0, node_crypto_1.createHash)('sha256').update(value).digest('hex');
442
+ }
443
+ function normalizeText(value) {
444
+ return value.toLowerCase().replace(/\s+/g, ' ').trim();
445
+ }
446
+ function tokenCountNormalized(value) {
447
+ return tokenizeNormalizedText(value).length;
448
+ }
449
+ function tokenizeNormalizedText(value) {
450
+ return value ? value.split(' ').filter(Boolean) : [];
451
+ }
452
+ function insertTermOccurrences(insertTerm, sourceId, chunkId, normalizedText) {
453
+ for (const [term, occurrences] of termOccurrences(normalizedText)) {
454
+ insertTerm.run(term, sourceId, chunkId, occurrences);
455
+ }
456
+ }
457
+ function termOccurrences(normalizedText) {
458
+ const terms = new Map();
459
+ for (const term of tokenizeNormalizedText(normalizedText)) {
460
+ terms.set(term, (terms.get(term) ?? 0) + 1);
461
+ }
462
+ return terms;
463
+ }
464
+ function buildTextSearchPredicate(query) {
465
+ const terms = [...new Set(tokenizeNormalizedText(query))];
466
+ const phraseCondition = "chunk.normalized_text LIKE ? ESCAPE '\\'";
467
+ const phrasePattern = `%${escapeLikePattern(query)}%`;
468
+ if (terms.length === 0) {
469
+ return {
470
+ sql: phraseCondition,
471
+ params: [phrasePattern],
472
+ indexChoice: 'text-normalized-scan',
473
+ };
474
+ }
475
+ return {
476
+ sql: `
477
+ chunk.id IN (
478
+ SELECT candidate.chunk_id
479
+ FROM (
480
+ ${terms.map(() => `
481
+ SELECT term.chunk_id, ? AS query_term
482
+ FROM rdf_text_terms term
483
+ WHERE term.term LIKE ? ESCAPE '\\'
484
+ `).join(' UNION ALL ')}
485
+ ) candidate
486
+ GROUP BY candidate.chunk_id
487
+ HAVING COUNT(DISTINCT candidate.query_term) = ?
488
+ )
489
+ AND ${phraseCondition}
490
+ `,
491
+ params: [
492
+ ...terms.flatMap((term) => [term, `%${escapeLikePattern(term)}%`]),
493
+ terms.length,
494
+ phrasePattern,
495
+ ],
496
+ indexChoice: 'text-term-posting',
497
+ };
498
+ }
499
+ function occurrenceCount(haystack, needle) {
500
+ if (!needle) {
501
+ return 0;
502
+ }
503
+ let count = 0;
504
+ let offset = 0;
505
+ while (true) {
506
+ const index = haystack.indexOf(needle, offset);
507
+ if (index === -1) {
508
+ break;
509
+ }
510
+ count++;
511
+ offset = index + needle.length;
512
+ }
513
+ return count;
514
+ }
515
+ function applyResultWindow(rows, offset, limit) {
516
+ const start = Math.max(0, offset ?? 0);
517
+ if (rows <= start) {
518
+ return 0;
519
+ }
520
+ const remaining = rows - start;
521
+ return limit === undefined ? remaining : Math.min(remaining, Math.max(0, limit));
522
+ }
523
+ function compareTextSearchHits(left, right, orderBy) {
524
+ const order = orderBy?.length ? orderBy : [{ field: 'score', direction: 'desc' }];
525
+ for (const entry of order) {
526
+ const direction = entry.direction === 'desc' ? -1 : 1;
527
+ const comparison = compareTextSearchField(left, right, entry.field);
528
+ if (comparison !== 0) {
529
+ return comparison * direction;
530
+ }
531
+ }
532
+ return left.row.source_id - right.row.source_id || left.row.ordinal - right.row.ordinal;
533
+ }
534
+ function compareTextSearchField(left, right, field) {
535
+ switch (field) {
536
+ case 'score':
537
+ return left.score - right.score;
538
+ case 'source':
539
+ return left.row.source.localeCompare(right.row.source);
540
+ case 'localPath':
541
+ return (left.row.local_path ?? '').localeCompare(right.row.local_path ?? '');
542
+ case 'ordinal':
543
+ return left.row.ordinal - right.row.ordinal;
544
+ case 'startOffset':
545
+ return left.row.start_offset - right.row.start_offset;
546
+ case 'endOffset':
547
+ return left.row.end_offset - right.row.end_offset;
548
+ default: {
549
+ const exhaustive = field;
550
+ throw new Error(`Unsupported RDF text search order field: ${exhaustive}`);
551
+ }
552
+ }
553
+ }
554
+ function escapeLikePattern(value) {
555
+ return value.replace(/[\\%_]/g, (match) => `\\${match}`);
556
+ }
557
+ function parsePath(value) {
558
+ if (!value) {
559
+ return [];
560
+ }
561
+ try {
562
+ const parsed = JSON.parse(value);
563
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === 'string') : [];
564
+ }
565
+ catch {
566
+ return [];
567
+ }
568
+ }
569
+ //# sourceMappingURL=RdfTextIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RdfTextIndex.js","sourceRoot":"","sources":["../../../src/storage/rdf/RdfTextIndex.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport { dirname, extname } from 'node:path';\nimport { HeadingChunker } from '../../document/HeadingChunker';\nimport { createSqliteRuntime, type SqliteDatabase, type SqliteStatement } from '../SqliteRuntime';\nimport type {\n RdfTextChunkInput,\n RdfTextChunkRow,\n RdfTextIndexOptions,\n RdfTextSearchOrder,\n RdfTextIndexStats,\n RdfSearchCardinalityEstimate,\n RdfTextSearchOptions,\n RdfTextSearchResult,\n RdfTextSourceInput,\n RdfTextTermDocumentFrequency,\n} from './types';\n\ninterface RdfTextSourceRow {\n id: number;\n source: string;\n workspace: string;\n local_path: string | null;\n content_type: string | null;\n source_version: string | null;\n source_hash: string | null;\n updated_at: string;\n}\n\ninterface RdfTextTermFrequencyRow {\n term: string;\n source_count: number;\n chunk_count: number;\n total_occurrences: number;\n}\n\ninterface TextSearchPredicate {\n sql: string;\n params: unknown[];\n indexChoice: 'text-normalized-scan' | 'text-term-posting';\n}\n\nexport class RdfTextIndex {\n private readonly sqliteRuntime = createSqliteRuntime();\n private db: SqliteDatabase | null = null;\n\n public constructor(private readonly options: RdfTextIndexOptions) {}\n\n public open(): void {\n if (this.db) {\n return;\n }\n\n if (this.options.path !== ':memory:') {\n const dir = dirname(this.options.path);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n }\n\n this.db = this.sqliteRuntime.openDatabase(this.options.path);\n this.initializeSchema();\n }\n\n public close(): void {\n this.db?.close();\n this.db = null;\n }\n\n public clear(): void {\n this.requireDb().exec('DELETE FROM rdf_text_terms; DELETE FROM rdf_text_chunks; DELETE FROM rdf_text_sources;');\n }\n\n public indexText(source: RdfTextSourceInput, text: string, chunks?: RdfTextChunkInput[]): void {\n const db = this.requireDb();\n const indexedChunks = chunks ?? this.chunkText(source, text);\n const sourceId = this.upsertSource({\n ...source,\n sourceHash: source.sourceHash ?? sha256(text),\n });\n const insertChunk = db.prepare(`\n INSERT INTO rdf_text_chunks (\n source_id,\n chunk_key,\n ordinal,\n level,\n heading,\n path,\n content,\n start_offset,\n end_offset,\n normalized_text,\n token_count,\n updated_at\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\n `);\n const insertTerm = db.prepare(`\n INSERT INTO rdf_text_terms (\n term,\n source_id,\n chunk_id,\n occurrences,\n updated_at\n )\n VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\n `);\n\n db.transaction(() => {\n db.prepare('DELETE FROM rdf_text_terms WHERE source_id = ?').run(sourceId);\n db.prepare('DELETE FROM rdf_text_chunks WHERE source_id = ?').run(sourceId);\n for (const chunk of indexedChunks) {\n const normalizedText = normalizeText(chunk.content);\n const result = insertChunk.run(\n sourceId,\n chunk.chunkKey,\n chunk.ordinal,\n chunk.level,\n chunk.heading || null,\n JSON.stringify(chunk.path ?? []),\n chunk.content,\n chunk.startOffset,\n chunk.endOffset,\n normalizedText,\n tokenCountNormalized(normalizedText),\n );\n insertTermOccurrences(insertTerm, sourceId, Number(result.lastInsertRowid), normalizedText);\n }\n })();\n }\n\n public deleteSource(source: string): number {\n const db = this.requireDb();\n const row = db.prepare<{ id: number }>('SELECT id FROM rdf_text_sources WHERE source = ?').get(source);\n if (!row) {\n return 0;\n }\n\n return db.transaction(() => {\n db.prepare('DELETE FROM rdf_text_terms WHERE source_id = ?').run(row.id);\n const deletedChunks = db.prepare('DELETE FROM rdf_text_chunks WHERE source_id = ?').run(row.id).changes;\n db.prepare('DELETE FROM rdf_text_sources WHERE id = ?').run(row.id);\n return deletedChunks;\n })();\n }\n\n public search(options: RdfTextSearchOptions): RdfTextSearchResult[] {\n const query = normalizeText(options.query);\n if (!query) {\n return [];\n }\n\n const predicate = buildTextSearchPredicate(query);\n const params: unknown[] = [...predicate.params];\n const conditions = [predicate.sql];\n\n if (options.workspace) {\n conditions.push('source.workspace = ?');\n params.push(options.workspace);\n }\n if (options.source) {\n conditions.push('source.source = ?');\n params.push(options.source);\n }\n if (options.sourcePrefix) {\n conditions.push('source.source >= ? AND source.source < ?');\n params.push(options.sourcePrefix, `${options.sourcePrefix}\\uffff`);\n }\n\n const sql = `\n SELECT\n chunk.id,\n chunk.source_id,\n source.source,\n source.workspace,\n source.local_path,\n source.content_type,\n source.source_version,\n source.source_hash,\n chunk.chunk_key,\n chunk.ordinal,\n chunk.level,\n chunk.heading,\n chunk.path,\n chunk.content,\n chunk.start_offset,\n chunk.end_offset,\n chunk.normalized_text,\n chunk.token_count,\n chunk.updated_at\n FROM rdf_text_chunks chunk\n JOIN rdf_text_sources source ON source.id = chunk.source_id\n WHERE ${conditions.join(' AND ')}\n ORDER BY chunk.source_id ASC, chunk.ordinal ASC\n `;\n\n const rows = this.requireDb().prepare<RdfTextChunkRow>(sql).all(...params);\n const results = rows\n .map((row) => ({ row, score: occurrenceCount(row.normalized_text, query) }))\n .filter((result) => result.score > 0)\n .sort((left, right) => compareTextSearchHits(left, right, options.orderBy))\n .map((result) => this.toSearchResult(result.row, result.score));\n return results.slice(options.offset ?? 0, options.limit === undefined ? undefined : (options.offset ?? 0) + options.limit);\n }\n\n public estimateSearchCardinality(options: RdfTextSearchOptions): RdfSearchCardinalityEstimate {\n const query = normalizeText(options.query);\n if (!query) {\n return {\n rows: 0,\n source: 'text-normalized-scan',\n indexChoice: 'text-normalized-scan',\n };\n }\n\n const predicate = buildTextSearchPredicate(query);\n const params: unknown[] = [...predicate.params];\n const conditions = [predicate.sql];\n\n if (options.workspace) {\n conditions.push('source.workspace = ?');\n params.push(options.workspace);\n }\n if (options.source) {\n conditions.push('source.source = ?');\n params.push(options.source);\n }\n if (options.sourcePrefix) {\n conditions.push('source.source >= ? AND source.source < ?');\n params.push(options.sourcePrefix, `${options.sourcePrefix}\\uffff`);\n }\n\n const rows = this.requireDb().prepare<{ count: number }>(`\n SELECT COUNT(*) AS count\n FROM rdf_text_chunks chunk\n JOIN rdf_text_sources source ON source.id = chunk.source_id\n WHERE ${conditions.join(' AND ')}\n `).get(...params)?.count ?? 0;\n\n return {\n rows: applyResultWindow(rows, options.offset, options.limit),\n source: predicate.indexChoice,\n indexChoice: predicate.indexChoice,\n };\n }\n\n public stats(): RdfTextIndexStats {\n const db = this.requireDb();\n return {\n sourceCount: db.prepare<{ count: number }>('SELECT COUNT(*) AS count FROM rdf_text_sources').get()?.count ?? 0,\n chunkCount: db.prepare<{ count: number }>('SELECT COUNT(*) AS count FROM rdf_text_chunks').get()?.count ?? 0,\n databaseBytes: this.estimateDatabaseBytes(),\n termDocumentFrequency: this.termDocumentFrequency(),\n };\n }\n\n public termDocumentFrequency(limit = 100): RdfTextTermDocumentFrequency[] {\n const rows = this.requireDb().prepare<RdfTextTermFrequencyRow>(`\n SELECT\n term,\n COUNT(DISTINCT source_id) AS source_count,\n COUNT(*) AS chunk_count,\n COALESCE(SUM(occurrences), 0) AS total_occurrences\n FROM rdf_text_terms\n GROUP BY term\n ORDER BY source_count DESC, chunk_count DESC, total_occurrences DESC, term ASC\n LIMIT ?\n `).all(Math.max(0, limit));\n\n return rows\n .map((row) => ({\n term: row.term,\n sourceCount: row.source_count,\n chunkCount: row.chunk_count,\n totalOccurrences: row.total_occurrences,\n }));\n }\n\n private initializeSchema(): void {\n this.requireDb().exec(`\n CREATE TABLE IF NOT EXISTS rdf_text_sources (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n source TEXT NOT NULL UNIQUE,\n workspace TEXT NOT NULL,\n local_path TEXT,\n content_type TEXT,\n source_version TEXT,\n source_hash TEXT,\n updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\n );\n\n CREATE TABLE IF NOT EXISTS rdf_text_chunks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n source_id INTEGER NOT NULL,\n chunk_key TEXT NOT NULL,\n ordinal INTEGER NOT NULL,\n level INTEGER NOT NULL,\n heading TEXT,\n path TEXT,\n content TEXT NOT NULL,\n start_offset INTEGER NOT NULL,\n end_offset INTEGER NOT NULL,\n normalized_text TEXT NOT NULL,\n token_count INTEGER NOT NULL,\n updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),\n UNIQUE (source_id, chunk_key),\n FOREIGN KEY (source_id) REFERENCES rdf_text_sources(id)\n );\n\n CREATE TABLE IF NOT EXISTS rdf_text_terms (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n term TEXT NOT NULL,\n source_id INTEGER NOT NULL,\n chunk_id INTEGER NOT NULL,\n occurrences INTEGER NOT NULL,\n updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),\n UNIQUE (term, chunk_id),\n FOREIGN KEY (source_id) REFERENCES rdf_text_sources(id),\n FOREIGN KEY (chunk_id) REFERENCES rdf_text_chunks(id)\n );\n\n CREATE INDEX IF NOT EXISTS rdf_text_sources_workspace ON rdf_text_sources(workspace);\n CREATE INDEX IF NOT EXISTS rdf_text_sources_source ON rdf_text_sources(source);\n CREATE INDEX IF NOT EXISTS rdf_text_chunks_source ON rdf_text_chunks(source_id, ordinal);\n CREATE INDEX IF NOT EXISTS rdf_text_chunks_normalized ON rdf_text_chunks(normalized_text);\n CREATE INDEX IF NOT EXISTS rdf_text_terms_term ON rdf_text_terms(term);\n CREATE INDEX IF NOT EXISTS rdf_text_terms_source_term ON rdf_text_terms(source_id, term);\n CREATE INDEX IF NOT EXISTS rdf_text_terms_chunk ON rdf_text_terms(chunk_id);\n `);\n this.backfillTermPostings();\n }\n\n private backfillTermPostings(): void {\n const db = this.requireDb();\n const rows = db.prepare<{\n id: number;\n source_id: number;\n normalized_text: string;\n }>(`\n SELECT chunk.id, chunk.source_id, chunk.normalized_text\n FROM rdf_text_chunks chunk\n LEFT JOIN rdf_text_terms term ON term.chunk_id = chunk.id\n WHERE term.chunk_id IS NULL AND chunk.normalized_text <> ''\n `).all();\n if (rows.length === 0) {\n return;\n }\n\n const insertTerm = db.prepare(`\n INSERT INTO rdf_text_terms (\n term,\n source_id,\n chunk_id,\n occurrences,\n updated_at\n )\n VALUES (?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\n `);\n db.transaction(() => {\n for (const row of rows) {\n insertTermOccurrences(insertTerm, row.source_id, row.id, row.normalized_text);\n }\n })();\n }\n\n private upsertSource(source: RdfTextSourceInput): number {\n const db = this.requireDb();\n db.prepare(`\n INSERT INTO rdf_text_sources (\n source,\n workspace,\n local_path,\n content_type,\n source_version,\n source_hash,\n updated_at\n )\n VALUES (?, ?, ?, ?, ?, ?, strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))\n ON CONFLICT (source)\n DO UPDATE SET\n workspace = excluded.workspace,\n local_path = excluded.local_path,\n content_type = excluded.content_type,\n source_version = excluded.source_version,\n source_hash = excluded.source_hash,\n updated_at = excluded.updated_at\n `).run(\n source.source,\n source.workspace,\n source.localPath ?? null,\n source.contentType ?? null,\n source.sourceVersion ?? null,\n source.sourceHash ?? null,\n );\n\n const row = db.prepare<RdfTextSourceRow>('SELECT * FROM rdf_text_sources WHERE source = ?').get(source.source);\n if (!row) {\n throw new Error(`Failed to upsert RDF text source: ${source.source}`);\n }\n return row.id;\n }\n\n private chunkText(source: RdfTextSourceInput, text: string): RdfTextChunkInput[] {\n if (!text) {\n return [];\n }\n if (isMarkdownSource(source)) {\n const chunker = new HeadingChunker();\n return chunker.flatten(chunker.chunk(text))\n .filter((chunk) => chunk.content.trim().length > 0)\n .map((chunk, index) => ({\n chunkKey: deterministicChunkKey(source.source, index),\n ordinal: index,\n level: chunk.level,\n heading: chunk.heading || undefined,\n path: chunk.path,\n content: chunk.content,\n startOffset: chunk.startOffset,\n endOffset: chunk.endOffset,\n }));\n }\n\n return chunkPlainText(source.source, text);\n }\n\n private estimateDatabaseBytes(): number {\n const db = this.requireDb();\n try {\n const pageCount = db.prepare<{ page_count: number }>('PRAGMA page_count').get()?.page_count ?? 0;\n const pageSize = db.prepare<{ page_size: number }>('PRAGMA page_size').get()?.page_size ?? 0;\n return pageCount * pageSize;\n } catch {\n return 0;\n }\n }\n\n private toSearchResult(row: RdfTextChunkRow, score: number): RdfTextSearchResult {\n return {\n source: row.source,\n workspace: row.workspace,\n localPath: row.local_path ?? undefined,\n contentType: row.content_type ?? undefined,\n sourceVersion: row.source_version ?? undefined,\n sourceHash: row.source_hash ?? undefined,\n chunkKey: row.chunk_key,\n ordinal: row.ordinal,\n level: row.level,\n heading: row.heading ?? undefined,\n path: parsePath(row.path),\n content: row.content,\n startOffset: row.start_offset,\n endOffset: row.end_offset,\n score,\n };\n }\n\n private requireDb(): SqliteDatabase {\n if (!this.db) {\n throw new Error('RdfTextIndex is not open');\n }\n return this.db;\n }\n}\n\nfunction isMarkdownSource(source: RdfTextSourceInput): boolean {\n const contentType = source.contentType?.split(';', 1)[0]?.trim().toLowerCase();\n if (contentType === 'text/markdown' || contentType === 'text/x-markdown') {\n return true;\n }\n const path = source.localPath ?? source.source;\n return ['.md', '.markdown', '.mdown'].includes(extname(path).toLowerCase());\n}\n\nfunction chunkPlainText(source: string, text: string): RdfTextChunkInput[] {\n const chunks: RdfTextChunkInput[] = [];\n const paragraphPattern = /[^\\S\\r\\n]*(?:\\r?\\n){2,}[^\\S\\r\\n]*/g;\n let ordinal = 0;\n let start = 0;\n let match: RegExpExecArray | null;\n\n while ((match = paragraphPattern.exec(text)) !== null) {\n const end = match.index;\n ordinal = pushPlainChunk(chunks, source, ordinal, text, start, end);\n start = match.index + match[0].length;\n }\n\n pushPlainChunk(chunks, source, ordinal, text, start, text.length);\n if (chunks.length <= 1 && /\\r?\\n/.test(text)) {\n return chunkLines(source, text);\n }\n return chunks;\n}\n\nfunction chunkLines(source: string, text: string): RdfTextChunkInput[] {\n const chunks: RdfTextChunkInput[] = [];\n const lines = text.split(/\\r?\\n/);\n let offset = 0;\n let ordinal = 0;\n\n for (const line of lines) {\n const start = offset;\n const end = start + line.length;\n ordinal = pushPlainChunk(chunks, source, ordinal, text, start, end);\n offset = end + (text.slice(end, end + 2) === '\\r\\n' ? 2 : 1);\n }\n\n return chunks;\n}\n\nfunction pushPlainChunk(\n chunks: RdfTextChunkInput[],\n source: string,\n ordinal: number,\n text: string,\n start: number,\n end: number,\n): number {\n const content = text.slice(start, end).trim();\n if (!content) {\n return ordinal;\n }\n\n chunks.push({\n chunkKey: deterministicChunkKey(source, ordinal),\n ordinal,\n level: 0,\n path: [],\n content,\n startOffset: start,\n endOffset: end,\n });\n return ordinal + 1;\n}\n\nfunction deterministicChunkKey(source: string, ordinal: number): string {\n return createHash('sha256')\n .update(source)\n .update('\\0')\n .update(String(ordinal))\n .digest('hex')\n .slice(0, 24);\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\nfunction normalizeText(value: string): string {\n return value.toLowerCase().replace(/\\s+/g, ' ').trim();\n}\n\nfunction tokenCountNormalized(value: string): number {\n return tokenizeNormalizedText(value).length;\n}\n\nfunction tokenizeNormalizedText(value: string): string[] {\n return value ? value.split(' ').filter(Boolean) : [];\n}\n\nfunction insertTermOccurrences(\n insertTerm: SqliteStatement,\n sourceId: number,\n chunkId: number,\n normalizedText: string,\n): void {\n for (const [term, occurrences] of termOccurrences(normalizedText)) {\n insertTerm.run(term, sourceId, chunkId, occurrences);\n }\n}\n\nfunction termOccurrences(normalizedText: string): Map<string, number> {\n const terms = new Map<string, number>();\n for (const term of tokenizeNormalizedText(normalizedText)) {\n terms.set(term, (terms.get(term) ?? 0) + 1);\n }\n return terms;\n}\n\nfunction buildTextSearchPredicate(query: string): TextSearchPredicate {\n const terms = [...new Set(tokenizeNormalizedText(query))];\n const phraseCondition = \"chunk.normalized_text LIKE ? ESCAPE '\\\\'\";\n const phrasePattern = `%${escapeLikePattern(query)}%`;\n if (terms.length === 0) {\n return {\n sql: phraseCondition,\n params: [phrasePattern],\n indexChoice: 'text-normalized-scan',\n };\n }\n\n return {\n sql: `\n chunk.id IN (\n SELECT candidate.chunk_id\n FROM (\n ${terms.map(() => `\n SELECT term.chunk_id, ? AS query_term\n FROM rdf_text_terms term\n WHERE term.term LIKE ? ESCAPE '\\\\'\n `).join(' UNION ALL ')}\n ) candidate\n GROUP BY candidate.chunk_id\n HAVING COUNT(DISTINCT candidate.query_term) = ?\n )\n AND ${phraseCondition}\n `,\n params: [\n ...terms.flatMap((term) => [term, `%${escapeLikePattern(term)}%`]),\n terms.length,\n phrasePattern,\n ],\n indexChoice: 'text-term-posting',\n };\n}\n\nfunction occurrenceCount(haystack: string, needle: string): number {\n if (!needle) {\n return 0;\n }\n\n let count = 0;\n let offset = 0;\n while (true) {\n const index = haystack.indexOf(needle, offset);\n if (index === -1) {\n break;\n }\n count++;\n offset = index + needle.length;\n }\n return count;\n}\n\nfunction applyResultWindow(rows: number, offset: number | undefined, limit: number | undefined): number {\n const start = Math.max(0, offset ?? 0);\n if (rows <= start) {\n return 0;\n }\n const remaining = rows - start;\n return limit === undefined ? remaining : Math.min(remaining, Math.max(0, limit));\n}\n\nfunction compareTextSearchHits(\n left: { row: RdfTextChunkRow; score: number },\n right: { row: RdfTextChunkRow; score: number },\n orderBy: RdfTextSearchOrder[] | undefined,\n): number {\n const order = orderBy?.length ? orderBy : [{ field: 'score' as const, direction: 'desc' as const }];\n for (const entry of order) {\n const direction = entry.direction === 'desc' ? -1 : 1;\n const comparison = compareTextSearchField(left, right, entry.field);\n if (comparison !== 0) {\n return comparison * direction;\n }\n }\n return left.row.source_id - right.row.source_id || left.row.ordinal - right.row.ordinal;\n}\n\nfunction compareTextSearchField(\n left: { row: RdfTextChunkRow; score: number },\n right: { row: RdfTextChunkRow; score: number },\n field: RdfTextSearchOrder['field'],\n): number {\n switch (field) {\n case 'score':\n return left.score - right.score;\n case 'source':\n return left.row.source.localeCompare(right.row.source);\n case 'localPath':\n return (left.row.local_path ?? '').localeCompare(right.row.local_path ?? '');\n case 'ordinal':\n return left.row.ordinal - right.row.ordinal;\n case 'startOffset':\n return left.row.start_offset - right.row.start_offset;\n case 'endOffset':\n return left.row.end_offset - right.row.end_offset;\n default: {\n const exhaustive: never = field;\n throw new Error(`Unsupported RDF text search order field: ${exhaustive}`);\n }\n }\n}\n\nfunction escapeLikePattern(value: string): string {\n return value.replace(/[\\\\%_]/g, (match) => `\\\\${match}`);\n}\n\nfunction parsePath(value: string | null): string[] {\n if (!value) {\n return [];\n }\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed) ? parsed.filter((item): item is string => typeof item === 'string') : [];\n } catch {\n return [];\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import type { RdfVectorChunkInput, RdfSearchCardinalityEstimate, RdfVectorIndexOptions, RdfVectorIndexStats, RdfVectorModelDistribution, RdfVectorSearchOptions, RdfVectorSearchResult, RdfVectorSourceInput } from './types';
2
+ export declare class RdfVectorIndex {
3
+ private readonly options;
4
+ private readonly sqliteRuntime;
5
+ private db;
6
+ constructor(options: RdfVectorIndexOptions);
7
+ open(): void;
8
+ close(): void;
9
+ clear(): void;
10
+ indexVector(source: RdfVectorSourceInput, chunks: RdfVectorChunkInput[]): void;
11
+ deleteSource(source: string): number;
12
+ search(options: RdfVectorSearchOptions): RdfVectorSearchResult[];
13
+ estimateSearchCardinality(options: RdfVectorSearchOptions): RdfSearchCardinalityEstimate;
14
+ stats(): RdfVectorIndexStats;
15
+ modelDistribution(): RdfVectorModelDistribution[];
16
+ private initializeSchema;
17
+ private backfillVectorComponents;
18
+ private upsertSource;
19
+ private estimateDatabaseBytes;
20
+ private toSearchResult;
21
+ private requireDb;
22
+ }