@apart-tech/intelligence-core 1.11.5 → 1.12.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 (88) hide show
  1. package/dist/auth/ability.d.ts +4 -4
  2. package/dist/auth/ability.d.ts.map +1 -1
  3. package/dist/auth/ability.js +17 -11
  4. package/dist/auth/ability.js.map +1 -1
  5. package/dist/auth/ability.test.js +25 -12
  6. package/dist/auth/ability.test.js.map +1 -1
  7. package/dist/config/index.d.ts.map +1 -1
  8. package/dist/config/index.js +5 -1
  9. package/dist/config/index.js.map +1 -1
  10. package/dist/db/tenant.d.ts.map +1 -1
  11. package/dist/db/tenant.js +8 -0
  12. package/dist/db/tenant.js.map +1 -1
  13. package/dist/index.d.ts +6 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +4 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/services/__tests__/chunk-service.test.d.ts +2 -0
  18. package/dist/services/__tests__/chunk-service.test.d.ts.map +1 -0
  19. package/dist/services/__tests__/chunk-service.test.js +111 -0
  20. package/dist/services/__tests__/chunk-service.test.js.map +1 -0
  21. package/dist/services/__tests__/chunker.test.d.ts +2 -0
  22. package/dist/services/__tests__/chunker.test.d.ts.map +1 -0
  23. package/dist/services/__tests__/chunker.test.js +113 -0
  24. package/dist/services/__tests__/chunker.test.js.map +1 -0
  25. package/dist/services/__tests__/node-service.test.d.ts +2 -0
  26. package/dist/services/__tests__/node-service.test.d.ts.map +1 -0
  27. package/dist/services/__tests__/node-service.test.js +207 -0
  28. package/dist/services/__tests__/node-service.test.js.map +1 -0
  29. package/dist/services/__tests__/pii-detector-service.test.js +51 -0
  30. package/dist/services/__tests__/pii-detector-service.test.js.map +1 -1
  31. package/dist/services/__tests__/pii-encryption-service.test.js +37 -0
  32. package/dist/services/__tests__/pii-encryption-service.test.js.map +1 -1
  33. package/dist/services/__tests__/search-service.test.d.ts +2 -0
  34. package/dist/services/__tests__/search-service.test.d.ts.map +1 -0
  35. package/dist/services/__tests__/search-service.test.js +163 -0
  36. package/dist/services/__tests__/search-service.test.js.map +1 -0
  37. package/dist/services/backfill-chunks.d.ts +30 -0
  38. package/dist/services/backfill-chunks.d.ts.map +1 -0
  39. package/dist/services/backfill-chunks.js +55 -0
  40. package/dist/services/backfill-chunks.js.map +1 -0
  41. package/dist/services/chunk-service.d.ts +45 -0
  42. package/dist/services/chunk-service.d.ts.map +1 -0
  43. package/dist/services/chunk-service.js +111 -0
  44. package/dist/services/chunk-service.js.map +1 -0
  45. package/dist/services/chunker.d.ts +32 -0
  46. package/dist/services/chunker.d.ts.map +1 -0
  47. package/dist/services/chunker.js +289 -0
  48. package/dist/services/chunker.js.map +1 -0
  49. package/dist/services/context-service.d.ts +3 -1
  50. package/dist/services/context-service.d.ts.map +1 -1
  51. package/dist/services/context-service.js +17 -1
  52. package/dist/services/context-service.js.map +1 -1
  53. package/dist/services/node-service.d.ts +12 -1
  54. package/dist/services/node-service.d.ts.map +1 -1
  55. package/dist/services/node-service.js +54 -11
  56. package/dist/services/node-service.js.map +1 -1
  57. package/dist/services/pii-detector-service.d.ts +1 -0
  58. package/dist/services/pii-detector-service.d.ts.map +1 -1
  59. package/dist/services/pii-detector-service.js +95 -2
  60. package/dist/services/pii-detector-service.js.map +1 -1
  61. package/dist/services/pii-encryption-service.d.ts +10 -0
  62. package/dist/services/pii-encryption-service.d.ts.map +1 -1
  63. package/dist/services/pii-encryption-service.js +32 -0
  64. package/dist/services/pii-encryption-service.js.map +1 -1
  65. package/dist/services/search-service.d.ts +30 -1
  66. package/dist/services/search-service.d.ts.map +1 -1
  67. package/dist/services/search-service.js +262 -45
  68. package/dist/services/search-service.js.map +1 -1
  69. package/dist/services/tag-service.d.ts +78 -0
  70. package/dist/services/tag-service.d.ts.map +1 -0
  71. package/dist/services/tag-service.js +639 -0
  72. package/dist/services/tag-service.js.map +1 -0
  73. package/dist/services/tag-service.test.d.ts +2 -0
  74. package/dist/services/tag-service.test.d.ts.map +1 -0
  75. package/dist/services/tag-service.test.js +448 -0
  76. package/dist/services/tag-service.test.js.map +1 -0
  77. package/dist/services/user-service.d.ts +1 -0
  78. package/dist/services/user-service.d.ts.map +1 -1
  79. package/dist/services/user-service.test.js +72 -1
  80. package/dist/services/user-service.test.js.map +1 -1
  81. package/dist/services/workspace-service.d.ts +2 -0
  82. package/dist/services/workspace-service.d.ts.map +1 -1
  83. package/dist/services/workspace-service.js +7 -1
  84. package/dist/services/workspace-service.js.map +1 -1
  85. package/dist/types/index.d.ts +67 -2
  86. package/dist/types/index.d.ts.map +1 -1
  87. package/package.json +2 -2
  88. package/prisma/schema.prisma +180 -3
@@ -1,16 +1,29 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { Prisma } from "@prisma/client";
2
3
  import { tenantWhere, SINGLE_TENANT_ORG_ID } from "../db/tenant.js";
4
+ import { TagService } from "./tag-service.js";
3
5
  // Columns safe to select in raw queries (excludes Unsupported types: embedding, search_vector)
4
- const NODE_COLUMNS = Prisma.sql `id, type, title, content, metadata, status, created_by, created_at, updated_at, version, domain_id, organization_id`;
6
+ const NODE_COLUMNS = Prisma.sql `id, type, title, content, metadata, status, created_by, created_at, updated_at, version, domain_id, organization_id, has_pii, embedding_pii_mode`;
7
+ // Same columns with n. prefix for JOINed queries
8
+ const NODE_COLUMNS_PREFIXED = Prisma.sql `n.id, n.type, n.title, n.content, n.metadata, n.status, n.created_by, n.created_at, n.updated_at, n.version, n.domain_id, n.organization_id, n.has_pii, n.embedding_pii_mode`;
9
+ // Minimum query length for fuzzy branches (substring + trigram).
10
+ // Short queries produce pathological recall.
11
+ const MIN_FUZZY_QUERY_LENGTH = 3;
12
+ // Maximum number of terms in a split-term ILIKE query to prevent query explosion.
13
+ const MAX_ILIKE_TERMS = 10;
5
14
  export class SearchService {
6
15
  db;
7
16
  embeddings;
8
17
  config;
18
+ piiEncryption;
19
+ piiOptions;
9
20
  tenantCtx;
10
- constructor(db, embeddings, config, tenantCtx) {
21
+ constructor(db, embeddings, config, tenantCtx, piiEncryption, piiOptions) {
11
22
  this.db = db;
12
23
  this.embeddings = embeddings;
13
24
  this.config = config;
25
+ this.piiEncryption = piiEncryption;
26
+ this.piiOptions = piiOptions;
14
27
  this.tenantCtx = tenantCtx ?? { organizationId: SINGLE_TENANT_ORG_ID };
15
28
  }
16
29
  async search(options) {
@@ -19,26 +32,96 @@ export class SearchService {
19
32
  (options.includeDrafts ?? this.config.search.includeDrafts
20
33
  ? ["draft", "reviewed", "approved"]
21
34
  : ["approved"]);
22
- // Run semantic and keyword search in parallel
23
- const [semanticResults, keywordResults] = await Promise.all([
24
- this.semanticSearch(options.query, limit, statuses, options.types, options.domainIds),
25
- this.keywordSearch(options.query, limit, statuses, options.types, options.domainIds),
35
+ // Strip PII from query before sending to embedding provider
36
+ const { query: strippedQuery, piiTypes } = this.stripQueryPii(options.query);
37
+ // Fire-and-forget audit log if PII was detected
38
+ if (piiTypes.length > 0) {
39
+ this.logPiiQuery(options.query, piiTypes, "search").catch(() => { });
40
+ }
41
+ // Run all search branches in parallel using stripped query
42
+ // Chunk semantic search + fallback node semantic search run together
43
+ const [chunkSemanticResults, nodeFallbackResults, keywordResults, substringResults, trigramResults] = await Promise.all([
44
+ this.chunkSemanticSearch(strippedQuery, limit, statuses, options.types, options.domainIds, options.tagFilters),
45
+ this.semanticSearch(strippedQuery, limit, statuses, options.types, options.domainIds, options.tagFilters),
46
+ this.keywordSearch(strippedQuery, limit, statuses, options.types, options.domainIds, options.tagFilters),
47
+ this.substringSearch(strippedQuery, limit, statuses, options.types, options.domainIds, options.tagFilters),
48
+ this.trigramSearch(strippedQuery, limit, statuses, options.types, options.domainIds, options.tagFilters),
26
49
  ]);
27
- // Reciprocal rank fusion
28
- return this.reciprocalRankFusion(semanticResults, keywordResults, limit, this.config.search.semanticWeight);
50
+ // Merge chunk results with node-level fallback (for unchunked nodes)
51
+ const chunkNodeIds = new Set(chunkSemanticResults.map((r) => r.node.id));
52
+ const fallbackOnly = nodeFallbackResults.filter((r) => !chunkNodeIds.has(r.node.id));
53
+ const semanticResults = [...chunkSemanticResults, ...fallbackOnly];
54
+ // N-branch reciprocal rank fusion
55
+ return this.reciprocalRankFusion([
56
+ { results: semanticResults, weight: this.config.search.semanticWeight },
57
+ { results: keywordResults, weight: this.config.search.keywordWeight },
58
+ { results: substringResults, weight: this.config.search.substringWeight },
59
+ { results: trigramResults, weight: this.config.search.trigramWeight },
60
+ ], limit);
61
+ }
62
+ buildTagCondition(tagFilters) {
63
+ if (!tagFilters || tagFilters.length === 0)
64
+ return Prisma.sql `TRUE`;
65
+ const tagService = new TagService(this.db, this.tenantCtx);
66
+ return tagService.buildSearchTagCondition(tagFilters);
29
67
  }
30
- async semanticSearch(query, limit, statuses, types, domainIds) {
68
+ /**
69
+ * Chunk-level semantic search: finds the best-matching chunk per node,
70
+ * returns the parent node with snippet from the best chunk.
71
+ */
72
+ async chunkSemanticSearch(query, limit, statuses, types, domainIds, tagFilters) {
31
73
  const queryEmbedding = await this.embeddings.embed(query, { inputType: "query" });
32
74
  const embeddingStr = `[${queryEmbedding.join(",")}]`;
33
- let typeCondition = Prisma.sql `TRUE`;
34
- if (types?.length) {
35
- typeCondition = Prisma.sql `type = ANY(${types}::text[])`;
36
- }
37
- let domainCondition = Prisma.sql `TRUE`;
38
- if (domainIds?.length) {
39
- domainCondition = Prisma.sql `domain_id = ANY(${domainIds}::uuid[])`;
40
- }
75
+ const typeCondition = types?.length
76
+ ? Prisma.sql `n.type = ANY(${types}::text[])`
77
+ : Prisma.sql `TRUE`;
78
+ const domainCondition = domainIds?.length
79
+ ? Prisma.sql `n.domain_id = ANY(${domainIds}::uuid[])`
80
+ : Prisma.sql `TRUE`;
81
+ const orgCondition = tenantWhere(this.tenantCtx, "c");
82
+ const tagCondition = this.buildTagCondition(tagFilters);
83
+ const queryDims = queryEmbedding.length;
84
+ const results = await this.db.$queryRaw `
85
+ WITH ranked_chunks AS (
86
+ SELECT c.node_id, c.content AS chunk_content, c.chunk_index,
87
+ 1 - (c.embedding <=> ${embeddingStr}::vector) AS similarity,
88
+ ROW_NUMBER() OVER (PARTITION BY c.node_id ORDER BY c.embedding <=> ${embeddingStr}::vector) AS rn
89
+ FROM node_chunks c
90
+ JOIN nodes n ON n.id = c.node_id
91
+ WHERE n.status = ANY(${statuses}::text[])
92
+ AND c.embedding IS NOT NULL
93
+ AND vector_dims(c.embedding) = ${queryDims}
94
+ AND ${typeCondition}
95
+ AND ${domainCondition}
96
+ AND ${orgCondition}
97
+ AND ${tagCondition}
98
+ )
99
+ SELECT ${NODE_COLUMNS_PREFIXED}, rc.similarity, rc.chunk_content, rc.chunk_index
100
+ FROM ranked_chunks rc
101
+ JOIN nodes n ON n.id = rc.node_id
102
+ WHERE rc.rn = 1
103
+ ORDER BY rc.similarity DESC
104
+ LIMIT ${limit}
105
+ `;
106
+ return results.map((row) => ({
107
+ node: row,
108
+ score: Number(row.similarity),
109
+ matchType: "semantic",
110
+ snippet: row.chunk_content,
111
+ snippetChunkIndex: row.chunk_index,
112
+ }));
113
+ }
114
+ async semanticSearch(query, limit, statuses, types, domainIds, tagFilters) {
115
+ const queryEmbedding = await this.embeddings.embed(query, { inputType: "query" });
116
+ const embeddingStr = `[${queryEmbedding.join(",")}]`;
117
+ const typeCondition = types?.length
118
+ ? Prisma.sql `type = ANY(${types}::text[])`
119
+ : Prisma.sql `TRUE`;
120
+ const domainCondition = domainIds?.length
121
+ ? Prisma.sql `domain_id = ANY(${domainIds}::uuid[])`
122
+ : Prisma.sql `TRUE`;
41
123
  const orgCondition = tenantWhere(this.tenantCtx);
124
+ const tagCondition = this.buildTagCondition(tagFilters);
42
125
  const queryDims = queryEmbedding.length;
43
126
  const results = await this.db.$queryRaw `
44
127
  SELECT ${NODE_COLUMNS},
@@ -50,6 +133,7 @@ export class SearchService {
50
133
  AND ${typeCondition}
51
134
  AND ${domainCondition}
52
135
  AND ${orgCondition}
136
+ AND ${tagCondition}
53
137
  ORDER BY embedding <=> ${embeddingStr}::vector
54
138
  LIMIT ${limit}
55
139
  `;
@@ -59,16 +143,15 @@ export class SearchService {
59
143
  matchType: "semantic",
60
144
  }));
61
145
  }
62
- async keywordSearch(query, limit, statuses, types, domainIds) {
63
- let typeCondition = Prisma.sql `TRUE`;
64
- if (types?.length) {
65
- typeCondition = Prisma.sql `type = ANY(${types}::text[])`;
66
- }
67
- let domainCondition = Prisma.sql `TRUE`;
68
- if (domainIds?.length) {
69
- domainCondition = Prisma.sql `domain_id = ANY(${domainIds}::uuid[])`;
70
- }
146
+ async keywordSearch(query, limit, statuses, types, domainIds, tagFilters) {
147
+ const typeCondition = types?.length
148
+ ? Prisma.sql `type = ANY(${types}::text[])`
149
+ : Prisma.sql `TRUE`;
150
+ const domainCondition = domainIds?.length
151
+ ? Prisma.sql `domain_id = ANY(${domainIds}::uuid[])`
152
+ : Prisma.sql `TRUE`;
71
153
  const orgCondition = tenantWhere(this.tenantCtx);
154
+ const tagCondition = this.buildTagCondition(tagFilters);
72
155
  const results = await this.db.$queryRaw `
73
156
  SELECT ${NODE_COLUMNS},
74
157
  ts_rank(search_vector, plainto_tsquery('english', ${query})) as rank
@@ -78,6 +161,7 @@ export class SearchService {
78
161
  AND ${typeCondition}
79
162
  AND ${domainCondition}
80
163
  AND ${orgCondition}
164
+ AND ${tagCondition}
81
165
  ORDER BY rank DESC
82
166
  LIMIT ${limit}
83
167
  `;
@@ -87,28 +171,161 @@ export class SearchService {
87
171
  matchType: "keyword",
88
172
  }));
89
173
  }
90
- reciprocalRankFusion(semanticResults, keywordResults, limit, semanticWeight) {
174
+ /**
175
+ * Split-term ILIKE search: splits query on whitespace, requires all terms
176
+ * to appear (in any order) in title or content. Also matches with dots
177
+ * removed so "GDPR.2024" matches a search for "GDPR-2024" etc.
178
+ */
179
+ async substringSearch(query, limit, statuses, types, domainIds, tagFilters) {
180
+ const terms = query.trim().split(/\s+/).slice(0, MAX_ILIKE_TERMS);
181
+ if (query.length < MIN_FUZZY_QUERY_LENGTH || terms.length === 0) {
182
+ return [];
183
+ }
184
+ const typeCondition = types?.length
185
+ ? Prisma.sql `type = ANY(${types}::text[])`
186
+ : Prisma.sql `TRUE`;
187
+ const domainCondition = domainIds?.length
188
+ ? Prisma.sql `domain_id = ANY(${domainIds}::uuid[])`
189
+ : Prisma.sql `TRUE`;
190
+ const orgCondition = tenantWhere(this.tenantCtx);
191
+ const tagCondition = this.buildTagCondition(tagFilters);
192
+ // Build per-term conditions: each term must appear in title or content
193
+ // (also checking with dots removed for punctuation-agnostic matching)
194
+ const termConditions = terms.map((term) => {
195
+ const pattern = `%${term}%`;
196
+ return Prisma.sql `(
197
+ title ILIKE ${pattern}
198
+ OR content ILIKE ${pattern}
199
+ OR replace(title, '.', '') ILIKE ${pattern}
200
+ OR replace(content, '.', '') ILIKE ${pattern}
201
+ )`;
202
+ });
203
+ // Join all term conditions with AND
204
+ const allTermsCondition = Prisma.join(termConditions, " AND ");
205
+ const results = await this.db.$queryRaw `
206
+ SELECT ${NODE_COLUMNS},
207
+ 1.0::float as match_score
208
+ FROM nodes
209
+ WHERE status = ANY(${statuses}::text[])
210
+ AND ${allTermsCondition}
211
+ AND ${typeCondition}
212
+ AND ${domainCondition}
213
+ AND ${orgCondition}
214
+ AND ${tagCondition}
215
+ ORDER BY updated_at DESC
216
+ LIMIT ${limit}
217
+ `;
218
+ return results.map((row) => ({
219
+ node: row,
220
+ score: Number(row.match_score),
221
+ matchType: "substring",
222
+ }));
223
+ }
224
+ /**
225
+ * Trigram similarity search using pg_trgm word_similarity().
226
+ * Catches misspellings and fuzzy partial matches.
227
+ */
228
+ async trigramSearch(query, limit, statuses, types, domainIds, tagFilters) {
229
+ if (query.length < MIN_FUZZY_QUERY_LENGTH) {
230
+ return [];
231
+ }
232
+ const typeCondition = types?.length
233
+ ? Prisma.sql `type = ANY(${types}::text[])`
234
+ : Prisma.sql `TRUE`;
235
+ const domainCondition = domainIds?.length
236
+ ? Prisma.sql `domain_id = ANY(${domainIds}::uuid[])`
237
+ : Prisma.sql `TRUE`;
238
+ const orgCondition = tenantWhere(this.tenantCtx);
239
+ const tagCondition = this.buildTagCondition(tagFilters);
240
+ const threshold = this.config.search.trigramThreshold;
241
+ const results = await this.db.$queryRaw `
242
+ SELECT ${NODE_COLUMNS},
243
+ GREATEST(
244
+ word_similarity(${query}, title),
245
+ word_similarity(${query}, content)
246
+ ) as trgm_score
247
+ FROM nodes
248
+ WHERE status = ANY(${statuses}::text[])
249
+ AND (
250
+ word_similarity(${query}, title) >= ${threshold}
251
+ OR word_similarity(${query}, content) >= ${threshold}
252
+ )
253
+ AND ${typeCondition}
254
+ AND ${domainCondition}
255
+ AND ${orgCondition}
256
+ AND ${tagCondition}
257
+ ORDER BY trgm_score DESC
258
+ LIMIT ${limit}
259
+ `;
260
+ return results.map((row) => ({
261
+ node: row,
262
+ score: Number(row.trgm_score),
263
+ matchType: "trigram",
264
+ }));
265
+ }
266
+ stripQueryPii(query) {
267
+ if (!this.piiEncryption || !this.piiOptions || this.piiOptions.mode === "disabled") {
268
+ return { query, piiTypes: [] };
269
+ }
270
+ const result = this.piiEncryption.stripPii(query, this.piiOptions.allowedPiiTypes);
271
+ return {
272
+ query: result.text,
273
+ piiTypes: result.piiDetected ? result.types : [],
274
+ };
275
+ }
276
+ async logPiiQuery(originalQuery, piiTypes, source) {
277
+ const queryHash = createHash("sha256").update(originalQuery).digest("hex");
278
+ await this.db.$executeRaw `
279
+ INSERT INTO pii_query_logs (id, organization_id, query_hash, pii_types_detected, match_count, source, principal_id)
280
+ VALUES (
281
+ gen_random_uuid(),
282
+ ${this.tenantCtx.organizationId}::uuid,
283
+ ${queryHash},
284
+ ${piiTypes}::text[],
285
+ ${piiTypes.length},
286
+ ${source},
287
+ NULL
288
+ )
289
+ `;
290
+ }
291
+ /**
292
+ * Generalized reciprocal rank fusion over N ranked lists.
293
+ * Each list carries its own weight. Results appearing in multiple
294
+ * lists get combined scores and are marked as "hybrid".
295
+ * Snippets from semantic results are preserved through merging.
296
+ */
297
+ reciprocalRankFusion(rankedLists, limit) {
91
298
  const k = 60; // RRF constant
92
299
  const scores = new Map();
93
- for (let i = 0; i < semanticResults.length; i++) {
94
- const r = semanticResults[i];
95
- const rrf = semanticWeight * (1 / (k + i + 1));
96
- scores.set(r.node.id, { score: rrf, result: { ...r, matchType: "hybrid" } });
97
- }
98
- const keywordWeight = 1 - semanticWeight;
99
- for (let i = 0; i < keywordResults.length; i++) {
100
- const r = keywordResults[i];
101
- const rrf = keywordWeight * (1 / (k + i + 1));
102
- const existing = scores.get(r.node.id);
103
- if (existing) {
104
- existing.score += rrf;
105
- existing.result.matchType = "hybrid";
300
+ for (const { results, weight } of rankedLists) {
301
+ if (weight === 0 || results.length === 0)
302
+ continue;
303
+ for (let i = 0; i < results.length; i++) {
304
+ const r = results[i];
305
+ const rrf = weight * (1 / (k + i + 1));
306
+ const existing = scores.get(r.node.id);
307
+ if (existing) {
308
+ existing.score += rrf;
309
+ existing.listCount += 1;
310
+ // Preserve snippet from semantic results if existing entry lacks one
311
+ if (r.snippet && !existing.result.snippet) {
312
+ existing.result.snippet = r.snippet;
313
+ existing.result.snippetChunkIndex = r.snippetChunkIndex;
314
+ }
315
+ }
316
+ else {
317
+ scores.set(r.node.id, {
318
+ score: rrf,
319
+ result: { ...r },
320
+ listCount: 1,
321
+ });
322
+ }
106
323
  }
107
- else {
108
- scores.set(r.node.id, {
109
- score: rrf,
110
- result: { ...r, matchType: "hybrid" },
111
- });
324
+ }
325
+ // Mark nodes found in multiple lists as "hybrid"
326
+ for (const entry of scores.values()) {
327
+ if (entry.listCount > 1) {
328
+ entry.result.matchType = "hybrid";
112
329
  }
113
330
  }
114
331
  return [...scores.values()]
@@ -1 +1 @@
1
- {"version":3,"file":"search-service.js","sourceRoot":"","sources":["../../src/services/search-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search-service.js","sourceRoot":"","sources":["../../src/services/search-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { Prisma, type PrismaClient } from "@prisma/client";
2
+ import { type TenantContext } from "../db/tenant.js";
3
+ import type { TagDefinition, NodeTag, ApplyTagInput, TagFilter, TagQuery, TagQueryResult, BatchError, TagType, TagDefinitionStatus } from "../types/index.js";
4
+ export declare class TagValidationError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ export declare class TagNotFoundError extends Error {
8
+ constructor(message: string);
9
+ }
10
+ export declare class TagService {
11
+ private db;
12
+ private tenantCtx;
13
+ constructor(db: PrismaClient, tenantCtx?: TenantContext);
14
+ createDefinition(input: {
15
+ tagName: string;
16
+ tagType: TagType;
17
+ cardinality?: "singleton" | "multi";
18
+ source?: "extracted" | "computed" | "declared";
19
+ description?: string;
20
+ category?: string;
21
+ labels?: Record<string, string>;
22
+ applicableNodeTypes?: string[];
23
+ requiredForNodeTypes?: string[];
24
+ enumValues?: string[];
25
+ dependsOn?: string[];
26
+ autoAcceptThreshold?: number;
27
+ parentDefinitionId?: string;
28
+ createdBy: string;
29
+ }): Promise<TagDefinition>;
30
+ updateDefinition(id: string, input: {
31
+ description?: string;
32
+ category?: string | null;
33
+ labels?: Record<string, string> | null;
34
+ applicableNodeTypes?: string[];
35
+ requiredForNodeTypes?: string[];
36
+ enumValues?: string[];
37
+ autoAcceptThreshold?: number | null;
38
+ status?: TagDefinitionStatus;
39
+ replacedBy?: string | null;
40
+ }): Promise<TagDefinition>;
41
+ getDefinition(id: string): Promise<TagDefinition | null>;
42
+ getDefinitionByName(tagName: string): Promise<TagDefinition | null>;
43
+ listDefinitions(options?: {
44
+ status?: TagDefinitionStatus;
45
+ category?: string;
46
+ }): Promise<TagDefinition[]>;
47
+ applyTags(nodeId: string, tags: ApplyTagInput[], taggedBy: string): Promise<NodeTag[]>;
48
+ private applySingleTag;
49
+ private upsertSingletonRaw;
50
+ upsertSingleton(nodeId: string, input: ApplyTagInput, taggedBy: string): Promise<NodeTag>;
51
+ getNodeTags(nodeId: string, tagNames?: string[]): Promise<NodeTag[]>;
52
+ queryTags(query: TagQuery): Promise<TagQueryResult>;
53
+ verifyTag(tagId: string, verifiedBy: string, reason?: string): Promise<NodeTag>;
54
+ contestTag(tagId: string, contestedBy: string, reason: string): Promise<NodeTag>;
55
+ bulkApply(tags: Array<{
56
+ nodeId: string;
57
+ } & ApplyTagInput>, taggedBy: string): Promise<{
58
+ applied: NodeTag[];
59
+ errors: BatchError[];
60
+ }>;
61
+ rollbackBatch(batchId: string): Promise<number>;
62
+ getTagAtTime(nodeId: string, tagName: string, asOf: Date): Promise<Record<string, unknown> | null>;
63
+ private validateTagType;
64
+ private getDefinitionDepth;
65
+ private buildFilterConditions;
66
+ private resolveFilterColumn;
67
+ private getValueColumn;
68
+ /**
69
+ * Build tag filter conditions as EXISTS subqueries for search integration.
70
+ * Each TagFilter becomes:
71
+ * EXISTS (SELECT 1 FROM node_tags t WHERE t.node_id = nodes.id
72
+ * AND t.tag_name = :tagName AND t.superseded_by IS NULL AND <op condition>)
73
+ */
74
+ buildSearchTagCondition(filters: TagFilter[]): Prisma.Sql;
75
+ private tagValueSnapshot;
76
+ private writeAudit;
77
+ }
78
+ //# sourceMappingURL=tag-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag-service.d.ts","sourceRoot":"","sources":["../../src/services/tag-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EACV,aAAa,EACb,OAAO,EACP,aAAa,EACb,SAAS,EACT,QAAQ,EACR,cAAc,EACd,UAAU,EACV,OAAO,EACP,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAI3B,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAID,qBAAa,UAAU;IAInB,OAAO,CAAC,EAAE;IAHZ,OAAO,CAAC,SAAS,CAAgB;gBAGvB,EAAE,EAAE,YAAY,EACxB,SAAS,CAAC,EAAE,aAAa;IAOrB,gBAAgB,CAAC,KAAK,EAAE;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;QACpC,MAAM,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;QAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC/B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;QAChC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;QACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,SAAS,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,aAAa,CAAC;IAsDpB,gBAAgB,CACpB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE;QACL,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;QACvC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;QAC/B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;QAChC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACpC,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GACA,OAAO,CAAC,aAAa,CAAC;IA+BnB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAIxD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAanE,eAAe,CAAC,OAAO,CAAC,EAAE;QAC9B,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IA0BtB,SAAS,CACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,aAAa,EAAE,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,EAAE,CAAC;YAWP,cAAc;YAwGd,kBAAkB;IAyE1B,eAAe,CACnB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC;IAKb,WAAW,CACf,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,OAAO,EAAE,CAAC;IAWf,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC;IA2EnD,SAAS,CACb,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC;IAwBb,UAAU,CACd,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC;IAwBb,SAAS,CACb,IAAI,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,CAAC,EAC/C,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QAAC,MAAM,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IAgClD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAU/C,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAyB1C,OAAO,CAAC,eAAe;YA0BT,kBAAkB;IAiBhC,OAAO,CAAC,qBAAqB;IA0C7B,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,cAAc;IAMtB;;;;;OAKG;IACH,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,GAAG;IA6DzD,OAAO,CAAC,gBAAgB;YAWV,UAAU;CAkBzB"}