@ai-pip/csl 0.1.3 → 0.1.5

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 (57) hide show
  1. package/layers/csl/index.ts +1 -0
  2. package/layers/csl/src/adapters/index.ts +10 -0
  3. package/layers/csl/src/adapters/input/DOMAdapter.ts +236 -0
  4. package/layers/csl/src/adapters/input/UIAdapter.ts +0 -0
  5. package/layers/csl/src/adapters/output/ConsoleLogger.ts +34 -0
  6. package/layers/csl/src/adapters/output/CryptoHashGenerator.ts +29 -0
  7. package/layers/csl/src/adapters/output/FilePolicyRepository.ts +0 -0
  8. package/layers/csl/src/adapters/output/InMemoryPolicyRepository.ts +135 -0
  9. package/layers/csl/src/adapters/output/SystemTimestampProvider.ts +9 -0
  10. package/layers/csl/src/domain/entities/CSLResult.ts +309 -0
  11. package/layers/csl/src/domain/entities/Segment.ts +338 -0
  12. package/layers/csl/src/domain/entities/index.ts +2 -0
  13. package/layers/csl/src/domain/exceptions/ClassificationError.ts +26 -0
  14. package/layers/csl/src/domain/exceptions/SegmentationError.ts +30 -0
  15. package/layers/csl/src/domain/exceptions/index.ts +2 -0
  16. package/layers/csl/src/domain/index.ts +4 -0
  17. package/layers/csl/src/domain/services/AnomalyService.ts +255 -0
  18. package/layers/csl/src/domain/services/LineageService.ts +224 -0
  19. package/layers/csl/src/domain/services/NormalizationService.ts +392 -0
  20. package/layers/csl/src/domain/services/OriginClassificationService.ts +69 -0
  21. package/layers/csl/src/domain/services/PiDetectionService.ts +475 -0
  22. package/layers/csl/src/domain/services/PolicyService.ts +296 -0
  23. package/layers/csl/src/domain/services/SegmentClassificationService.ts +105 -0
  24. package/layers/csl/src/domain/services/SerializationService.ts +229 -0
  25. package/layers/csl/src/domain/services/index.ts +7 -0
  26. package/layers/csl/src/domain/value-objects/AnomalyScore.ts +23 -0
  27. package/layers/csl/src/domain/value-objects/ContentHash.ts +54 -0
  28. package/layers/csl/src/domain/value-objects/LineageEntry.ts +42 -0
  29. package/layers/csl/src/domain/value-objects/Origin-map.ts +67 -0
  30. package/layers/csl/src/domain/value-objects/Origin.ts +99 -0
  31. package/layers/csl/src/domain/value-objects/Pattern.ts +221 -0
  32. package/layers/csl/src/domain/value-objects/PiDetection.ts +140 -0
  33. package/layers/csl/src/domain/value-objects/PiDetectionResult.ts +275 -0
  34. package/layers/csl/src/domain/value-objects/PolicyRule.ts +151 -0
  35. package/layers/csl/src/domain/value-objects/TrustLevel.ts +34 -0
  36. package/layers/csl/src/domain/value-objects/index.ts +10 -0
  37. package/layers/csl/src/index.ts +7 -0
  38. package/layers/csl/src/ports/index.ts +10 -0
  39. package/layers/csl/src/ports/input/ClassificationPort.ts +76 -0
  40. package/layers/csl/src/ports/input/SegmentationPort.ts +81 -0
  41. package/layers/csl/src/ports/output/DOMAdapter.ts +14 -0
  42. package/layers/csl/src/ports/output/HashGenerator.ts +18 -0
  43. package/layers/csl/src/ports/output/Logger.ts +17 -0
  44. package/layers/csl/src/ports/output/PolicyRepository.ts +29 -0
  45. package/layers/csl/src/ports/output/SegmentClassified.ts +8 -0
  46. package/layers/csl/src/ports/output/TimeStampProvider.ts +5 -0
  47. package/layers/csl/src/services/CSLService.ts +393 -0
  48. package/layers/csl/src/services/index.ts +1 -0
  49. package/layers/csl/src/types/entities-types.ts +37 -0
  50. package/layers/csl/src/types/index.ts +4 -0
  51. package/layers/csl/src/types/pi-types.ts +111 -0
  52. package/layers/csl/src/types/port-output-types.ts +17 -0
  53. package/layers/csl/src/types/value-objects-types.ts +213 -0
  54. package/layers/csl/src/utils/colors.ts +25 -0
  55. package/layers/csl/src/utils/pattern-helpers.ts +174 -0
  56. package/package.json +4 -5
  57. package/src/index.ts +36 -36
@@ -0,0 +1,296 @@
1
+ import type { Segment } from '../entities'
2
+ import type { PolicyRule } from '../value-objects'
3
+ import type { PolicyRepositoryPort } from '../../ports/output/PolicyRepository'
4
+
5
+ /**
6
+ * Policy violation information
7
+ */
8
+ export interface PolicyViolation {
9
+ readonly type: 'blocked_intent' | 'sensitive_scope' | 'role_protection' | 'context_leak'
10
+ readonly description: string
11
+ readonly severity: 'high' | 'medium' | 'low'
12
+ }
13
+
14
+ /**
15
+ * Policy validation result
16
+ */
17
+ export interface PolicyValidationResult {
18
+ readonly isValid: boolean
19
+ readonly violations: readonly PolicyViolation[]
20
+ readonly policyVersion: string
21
+ }
22
+
23
+ /**
24
+ * PolicyService applies policy rules to content segments.
25
+ *
26
+ * @remarks
27
+ * This service validates segments against active policy rules retrieved from
28
+ * a PolicyRepository. It checks for:
29
+ * - Blocked intents in content
30
+ * - Sensitive scope violations
31
+ * - Role protection violations
32
+ * - Context leak prevention
33
+ *
34
+ * **Key Features:**
35
+ * - Depends on PolicyRepositoryPort for policy retrieval
36
+ * - Validates segments against active policies
37
+ * - Returns detailed violation information
38
+ * - Supports async policy loading
39
+ *
40
+ * **Usage:**
41
+ * PolicyService is instantiated with a PolicyRepository implementation.
42
+ * It validates segments during the processing pipeline to ensure compliance.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const policyRepository = new InMemoryPolicyRepository()
47
+ * const policyService = new PolicyService(policyRepository)
48
+ *
49
+ * // Validate a segment
50
+ * const result = await policyService.validateSegment(segment)
51
+ *
52
+ * if (!result.isValid) {
53
+ * console.log(`Policy violations: ${result.violations.length}`)
54
+ * result.violations.forEach(v => console.log(`- ${v.description}`))
55
+ * }
56
+ * ```
57
+ */
58
+ export class PolicyService {
59
+ constructor(private readonly policyRepository: PolicyRepositoryPort) {
60
+ if (!policyRepository) {
61
+ throw new TypeError('PolicyService: policyRepository is required')
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Validates a segment against the active policy
67
+ *
68
+ * @param segment - The segment to validate
69
+ * @returns PolicyValidationResult with validation status and violations
70
+ *
71
+ * @throws {TypeError} If segment is not a Segment instance
72
+ *
73
+ * @example
74
+ * ```typescript
75
+ * const result = await policyService.validateSegment(segment)
76
+ * if (!result.isValid) {
77
+ * // Handle violations
78
+ * }
79
+ * ```
80
+ */
81
+ async validateSegment(segment: Segment): Promise<PolicyValidationResult> {
82
+ if (!segment || typeof segment !== 'object' || !('id' in segment)) {
83
+ throw new TypeError('PolicyService.validateSegment: segment must be a Segment instance')
84
+ }
85
+
86
+ // Get active policy
87
+ const policy = await this.policyRepository.getActivePolicy()
88
+
89
+ // Collect all violations
90
+ const violations: PolicyViolation[] = []
91
+
92
+ // Check for blocked intents
93
+ const intentViolations = this.checkBlockedIntents(segment, policy)
94
+ violations.push(...intentViolations)
95
+
96
+ // Check for sensitive scope violations
97
+ const scopeViolations = this.checkSensitiveScope(segment, policy)
98
+ violations.push(...scopeViolations)
99
+
100
+ // Check role protection
101
+ const roleViolations = this.checkRoleProtection(segment, policy)
102
+ violations.push(...roleViolations)
103
+
104
+ // Check context leak prevention
105
+ const contextLeakViolations = this.checkContextLeakPrevention(segment, policy)
106
+ violations.push(...contextLeakViolations)
107
+
108
+ return {
109
+ isValid: violations.length === 0,
110
+ violations: Object.freeze(violations),
111
+ policyVersion: policy.version,
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Checks if the segment contains any blocked intents
117
+ */
118
+ private checkBlockedIntents(segment: Segment, policy: PolicyRule): PolicyViolation[] {
119
+ const violations: PolicyViolation[] = []
120
+ const content = segment.content.toLowerCase()
121
+
122
+ for (const blockedIntent of policy.blockedIntents) {
123
+ const intentPattern = blockedIntent.toLowerCase()
124
+
125
+ // Simple pattern matching (can be enhanced with regex or NLP)
126
+ if (content.includes(intentPattern)) {
127
+ violations.push({
128
+ type: 'blocked_intent',
129
+ description: `Blocked intent detected: ${blockedIntent}`,
130
+ severity: 'high',
131
+ })
132
+ }
133
+ }
134
+
135
+ return violations
136
+ }
137
+
138
+ /**
139
+ * Checks if the segment contains sensitive scope content
140
+ */
141
+ private checkSensitiveScope(segment: Segment, policy: PolicyRule): PolicyViolation[] {
142
+ const violations: PolicyViolation[] = []
143
+ const content = segment.content.toLowerCase()
144
+
145
+ for (const sensitiveScope of policy.sensitiveScope) {
146
+ const scopePattern = sensitiveScope.toLowerCase()
147
+
148
+ // Simple pattern matching (can be enhanced)
149
+ if (content.includes(scopePattern)) {
150
+ violations.push({
151
+ type: 'sensitive_scope',
152
+ description: `Sensitive scope detected: ${sensitiveScope}`,
153
+ severity: 'medium',
154
+ })
155
+ }
156
+ }
157
+
158
+ return violations
159
+ }
160
+
161
+ /**
162
+ * Checks if the segment violates role protection rules
163
+ */
164
+ private checkRoleProtection(segment: Segment, policy: PolicyRule): PolicyViolation[] {
165
+ const violations: PolicyViolation[] = []
166
+ const content = segment.content.toLowerCase()
167
+
168
+ // Check for protected role mentions
169
+ for (const protectedRole of policy.roleProtection.protectedRoles) {
170
+ const rolePattern = protectedRole.toLowerCase()
171
+
172
+ // Check for role override attempts
173
+ const overridePatterns = [
174
+ `you are no longer ${rolePattern}`,
175
+ `forget you are ${rolePattern}`,
176
+ `ignore your role as ${rolePattern}`,
177
+ `you are now ${rolePattern}`,
178
+ ]
179
+
180
+ for (const pattern of overridePatterns) {
181
+ if (content.includes(pattern)) {
182
+ violations.push({
183
+ type: 'role_protection',
184
+ description: `Protected role override attempt: ${protectedRole}`,
185
+ severity: 'high',
186
+ })
187
+ break // Only report once per role
188
+ }
189
+ }
190
+ }
191
+
192
+ // Check for immutable instruction modifications
193
+ for (const immutableInstruction of policy.roleProtection.immutableInstructions) {
194
+ const instructionPattern = immutableInstruction.toLowerCase()
195
+
196
+ // Check for instruction override attempts
197
+ const overridePatterns = [
198
+ `ignore ${instructionPattern}`,
199
+ `forget ${instructionPattern}`,
200
+ `disregard ${instructionPattern}`,
201
+ ]
202
+
203
+ for (const pattern of overridePatterns) {
204
+ if (content.includes(pattern)) {
205
+ violations.push({
206
+ type: 'role_protection',
207
+ description: `Immutable instruction override attempt: ${immutableInstruction}`,
208
+ severity: 'high',
209
+ })
210
+ break
211
+ }
212
+ }
213
+ }
214
+
215
+ return violations
216
+ }
217
+
218
+ /**
219
+ * Checks if the segment violates context leak prevention rules
220
+ */
221
+ private checkContextLeakPrevention(segment: Segment, policy: PolicyRule): PolicyViolation[] {
222
+ const violations: PolicyViolation[] = []
223
+
224
+ if (!policy.isContextLeakPreventionEnabled()) {
225
+ return violations // Context leak prevention is disabled
226
+ }
227
+
228
+ const content = segment.content
229
+
230
+ // Check for metadata exposure patterns
231
+ if (policy.contextLeakPrevention.blockMetadataExposure) {
232
+ const metadataPatterns = [
233
+ /system\s+prompt/i,
234
+ /initial\s+instructions/i,
235
+ /base\s+instructions/i,
236
+ /original\s+prompt/i,
237
+ /hidden\s+instructions/i,
238
+ ]
239
+
240
+ for (const pattern of metadataPatterns) {
241
+ if (pattern.test(content)) {
242
+ violations.push({
243
+ type: 'context_leak',
244
+ description: 'Potential metadata exposure detected',
245
+ severity: 'medium',
246
+ })
247
+ break
248
+ }
249
+ }
250
+ }
251
+
252
+ // Check for internal references
253
+ if (policy.contextLeakPrevention.sanitizeInternalReferences) {
254
+ const internalReferencePatterns = [
255
+ /internal\s+reference/i,
256
+ /system\s+variable/i,
257
+ /config\s+value/i,
258
+ /secret\s+key/i,
259
+ ]
260
+
261
+ for (const pattern of internalReferencePatterns) {
262
+ if (pattern.test(content)) {
263
+ violations.push({
264
+ type: 'context_leak',
265
+ description: 'Potential internal reference exposure detected',
266
+ severity: 'low',
267
+ })
268
+ break
269
+ }
270
+ }
271
+ }
272
+
273
+ return violations
274
+ }
275
+
276
+ /**
277
+ * Checks if a segment should be blocked based on policy violations
278
+ *
279
+ * @param segment - The segment to check
280
+ * @returns true if the segment should be blocked, false otherwise
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * const shouldBlock = await policyService.shouldBlock(segment)
285
+ * if (shouldBlock) {
286
+ * // Block the segment
287
+ * }
288
+ * ```
289
+ */
290
+ async shouldBlock(segment: Segment): Promise<boolean> {
291
+ const result = await this.validateSegment(segment)
292
+
293
+ // Block if there are high-severity violations
294
+ return result.violations.some(v => v.severity === 'high')
295
+ }
296
+ }
@@ -0,0 +1,105 @@
1
+ import type { SegmentClassified } from "../../ports";
2
+ import type { Segment } from "../entities";
3
+ import { OriginClassificationService } from "./OriginClassificationService";
4
+
5
+ /**
6
+ * SegmentClassificationService classifies individual segments by assigning trust levels.
7
+ *
8
+ * @remarks
9
+ * This service orchestrates the classification of a Segment by:
10
+ * 1. Using OriginClassificationService to determine TrustLevel from the Segment's Origin
11
+ * 2. Assigning the TrustLevel to the Segment entity
12
+ * 3. Returning a SegmentClassified DTO with the classification result
13
+ *
14
+ * **Key Characteristics:**
15
+ * - Works with individual Segment entities
16
+ * - Uses ClassificationService internally for origin-based classification
17
+ * - Assigns TrustLevel to the Segment (mutates the segment)
18
+ * - Returns a DTO (SegmentClassified) with classification information
19
+ *
20
+ * **Usage in Pipeline:**
21
+ * This service is typically used in the SegmentationService pipeline to classify
22
+ * segments after they are created from DOM adaptation.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const originClassificationService = new OriginClassificationService()
27
+ * const segmentClassifier = new SegmentClassificationService(originClassificationService)
28
+ *
29
+ * const segment = new Segment({
30
+ * id: 'seg-123',
31
+ * origin: new Origin(OriginType.USER),
32
+ * content: 'Hello, how can I help you?',
33
+ * mime: 'text/plain',
34
+ * timestamp: Date.now(),
35
+ * source: 'user-input-field'
36
+ * })
37
+ *
38
+ * const classified = segmentClassifier.classify(segment)
39
+ * // segment.trustLevel is now assigned (TrustLevelType.UC)
40
+ * // classified contains: { segmentId, text, origin, trustLevel }
41
+ * ```
42
+ */
43
+ export class SegmentClassificationService {
44
+ constructor(
45
+ private readonly originClassificationService: OriginClassificationService
46
+ ) {}
47
+
48
+ /**
49
+ * Classifies a segment by assigning a trust level based on its origin.
50
+ *
51
+ * @param segment - The Segment entity to classify. Must have an origin assigned.
52
+ *
53
+ * @returns A SegmentClassified object containing:
54
+ * - segmentId: The unique identifier of the segment
55
+ * - text: The content text of the segment
56
+ * - origin: The origin of the segment
57
+ * - trustLevel: The trust level assigned based on the origin
58
+ *
59
+ * @throws {ClassificationError} If classification fails (origin not mapped)
60
+ * @throws {Error} If segment already has a trust level assigned
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const classified = segmentClassifier.classify(segment)
65
+ * console.log(classified.trustLevel.value) // 'UC', 'STC', or 'TC'
66
+ * console.log(segment.trustLevel?.value) // Same value (assigned to segment)
67
+ * ```
68
+ */
69
+ classify(segment: Segment): SegmentClassified {
70
+ // 1. Use ClassificationService to get TrustLevel from the segment's Origin
71
+ const trustLevel = this.originClassificationService.classify(segment.origin);
72
+
73
+ // 2. Assign the TrustLevel to the Segment entity
74
+ segment.assignTrustLevel(trustLevel);
75
+
76
+ // 3. Return the classification result as a DTO
77
+ return {
78
+ segmentId: segment.id,
79
+ text: segment.content,
80
+ origin: segment.origin,
81
+ trustLevel: trustLevel
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Classifies multiple segments in batch.
87
+ *
88
+ * @param segments - Array of Segment entities to classify
89
+ *
90
+ * @returns Array of SegmentClassified objects, one for each segment
91
+ *
92
+ * @throws {ClassificationError} If classification fails for any segment
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * const segments = [segment1, segment2, segment3]
97
+ * const classified = segmentClassifier.classifyMany(segments)
98
+ * // All segments now have trustLevel assigned
99
+ * // Returns array of SegmentClassified objects
100
+ * ```
101
+ */
102
+ classifyMany(segments: Segment[]): SegmentClassified[] {
103
+ return segments.map(segment => this.classify(segment));
104
+ }
105
+ }
@@ -0,0 +1,229 @@
1
+ import type { Segment } from '../entities'
2
+ import { LineageEntry } from '../value-objects'
3
+
4
+ /**
5
+ * Serialized representation of a Segment for storage/transmission
6
+ */
7
+ export interface SerializedSegment {
8
+ readonly id: string
9
+ readonly origin: string
10
+ readonly content: string
11
+ readonly mime: string
12
+ readonly timestamp: number
13
+ readonly source: string
14
+ readonly metadata?: Record<string, unknown>
15
+ readonly trustLevel?: string
16
+ readonly hash?: {
17
+ readonly value: string
18
+ readonly algorithm: string
19
+ }
20
+ readonly anomalyScore?: {
21
+ readonly score: number
22
+ readonly action: string
23
+ }
24
+ readonly piDetection?: {
25
+ readonly score: number
26
+ readonly detections: Array<{
27
+ readonly pattern_type: string
28
+ readonly confidence: number
29
+ readonly position?: {
30
+ readonly start: number
31
+ readonly end: number
32
+ }
33
+ }>
34
+ readonly action: string
35
+ }
36
+ readonly lineage?: Array<{
37
+ readonly step: string
38
+ readonly timestamp: number
39
+ readonly notes?: string
40
+ }>
41
+ }
42
+
43
+ /**
44
+ * SerializationService provides serialization of domain entities to plain objects.
45
+ *
46
+ * @remarks
47
+ * This service converts domain entities (like Segment) into serializable formats
48
+ * (plain objects) that can be stored, transmitted, or logged. All methods are static
49
+ * since serialization is a stateless operation.
50
+ *
51
+ * **Key Features:**
52
+ * - Stateless: All methods are static
53
+ * - Type-safe: Returns well-defined serialized interfaces
54
+ * - Immutable: Serialized objects are frozen
55
+ * - Handles optional properties gracefully
56
+ *
57
+ * **Usage:**
58
+ * SerializationService is used when:
59
+ * - Storing segments in databases
60
+ * - Transmitting segments over networks
61
+ * - Logging segment information
62
+ * - Creating CSLResult output
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * // Serialize a segment
67
+ * const serialized = SerializationService.serializeSegment(segment)
68
+ *
69
+ * // Store or transmit
70
+ * await database.save(serialized)
71
+ *
72
+ * // Or log
73
+ * console.log(JSON.stringify(serialized, null, 2))
74
+ * ```
75
+ */
76
+ export class SerializationService {
77
+ /**
78
+ * Serializes a Segment entity to a plain object
79
+ *
80
+ * @param segment - The segment to serialize
81
+ * @returns SerializedSegment object ready for storage/transmission
82
+ *
83
+ * @throws {TypeError} If segment is not a Segment instance
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const serialized = SerializationService.serializeSegment(segment)
88
+ * const json = JSON.stringify(serialized)
89
+ * ```
90
+ */
91
+ static serializeSegment(segment: Segment): SerializedSegment {
92
+ if (!segment || typeof segment !== 'object' || !('id' in segment)) {
93
+ throw new TypeError('SerializationService.serializeSegment: segment must be a Segment instance')
94
+ }
95
+
96
+ const serialized: SerializedSegment = {
97
+ id: segment.id,
98
+ origin: segment.origin.type,
99
+ content: segment.content,
100
+ mime: segment.mime,
101
+ timestamp: segment.timestamp,
102
+ source: segment.source,
103
+ ...(segment.metadata && { metadata: { ...segment.metadata } }),
104
+ ...(segment.trustLevel && { trustLevel: segment.trustLevel.value }),
105
+ ...(segment.hash && {
106
+ hash: {
107
+ value: segment.hash.value,
108
+ algorithm: segment.hash.algorithm,
109
+ },
110
+ }),
111
+ ...(segment.anomalyScore && {
112
+ anomalyScore: {
113
+ score: segment.anomalyScore.score,
114
+ action: segment.anomalyScore.action,
115
+ },
116
+ }),
117
+ ...(segment.piDetection && {
118
+ piDetection: {
119
+ score: segment.piDetection.score,
120
+ detections: segment.piDetection.detections.map(detection => ({
121
+ pattern_type: detection.pattern_type,
122
+ confidence: detection.confidence,
123
+ ...(detection.position && {
124
+ position: {
125
+ start: detection.position.start,
126
+ end: detection.position.end,
127
+ },
128
+ }),
129
+ })),
130
+ action: segment.piDetection.action,
131
+ },
132
+ }),
133
+ ...(segment.lineage && segment.lineage.length > 0 && {
134
+ lineage: segment.lineage.map(entry => {
135
+ if (entry.hasNotes() && entry.notes) {
136
+ return {
137
+ step: entry.step,
138
+ timestamp: entry.timestamp,
139
+ notes: entry.notes,
140
+ }
141
+ }
142
+ return {
143
+ step: entry.step,
144
+ timestamp: entry.timestamp,
145
+ }
146
+ }),
147
+ }),
148
+ }
149
+
150
+ return Object.freeze(serialized)
151
+ }
152
+
153
+ /**
154
+ * Serializes an array of segments
155
+ *
156
+ * @param segments - Array of segments to serialize
157
+ * @returns Array of SerializedSegment objects
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * const serialized = SerializationService.serializeSegments(segments)
162
+ * ```
163
+ */
164
+ static serializeSegments(segments: readonly Segment[]): SerializedSegment[] {
165
+ if (!Array.isArray(segments)) {
166
+ throw new TypeError('SerializationService.serializeSegments: segments must be an array')
167
+ }
168
+
169
+ return segments.map(segment => this.serializeSegment(segment))
170
+ }
171
+
172
+ /**
173
+ * Serializes a LineageEntry to a plain object
174
+ *
175
+ * @param entry - The lineage entry to serialize
176
+ * @returns Plain object representation
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * const serialized = SerializationService.serializeLineageEntry(entry)
181
+ * ```
182
+ */
183
+ static serializeLineageEntry(entry: LineageEntry): {
184
+ readonly step: string
185
+ readonly timestamp: number
186
+ readonly notes?: string
187
+ } {
188
+ if (!(entry instanceof LineageEntry)) {
189
+ throw new TypeError('SerializationService.serializeLineageEntry: entry must be a LineageEntry instance')
190
+ }
191
+
192
+ if (entry.hasNotes() && entry.notes) {
193
+ return Object.freeze({
194
+ step: entry.step,
195
+ timestamp: entry.timestamp,
196
+ notes: entry.notes,
197
+ })
198
+ }
199
+ return Object.freeze({
200
+ step: entry.step,
201
+ timestamp: entry.timestamp,
202
+ })
203
+ }
204
+
205
+ /**
206
+ * Serializes an array of lineage entries
207
+ *
208
+ * @param entries - Array of lineage entries to serialize
209
+ * @returns Array of serialized lineage entry objects
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * const serialized = SerializationService.serializeLineageEntries(entries)
214
+ * ```
215
+ */
216
+ static serializeLineageEntries(
217
+ entries: readonly LineageEntry[]
218
+ ): Array<{
219
+ readonly step: string
220
+ readonly timestamp: number
221
+ readonly notes?: string
222
+ }> {
223
+ if (!Array.isArray(entries)) {
224
+ throw new TypeError('SerializationService.serializeLineageEntries: entries must be an array')
225
+ }
226
+
227
+ return entries.map(entry => this.serializeLineageEntry(entry))
228
+ }
229
+ }
@@ -0,0 +1,7 @@
1
+ export * from './OriginClassificationService';
2
+ export * from './PiDetectionService';
3
+ export * from './NormalizationService';
4
+ export * from './LineageService';
5
+ export * from './AnomalyService';
6
+ export * from './SerializationService';
7
+ export * from './PolicyService';
@@ -0,0 +1,23 @@
1
+ import type { AnomalyAction, RiskScore } from "../../types";
2
+
3
+
4
+ export class AnomalyScore {
5
+ readonly score: RiskScore
6
+ readonly action: AnomalyAction
7
+
8
+ constructor(score: RiskScore, action: AnomalyAction) {
9
+ if (score < 0 || score > 1) {
10
+ throw new Error('Anomaly score must be a value between 0 and 1')
11
+ }
12
+ this.score = score
13
+ this.action = action
14
+ }
15
+
16
+ isHighRisk(): boolean {
17
+ return this.action === 'BLOCK'
18
+ }
19
+ isWarnRisk(): boolean {
20
+ return this.action === 'WARN'
21
+ }
22
+
23
+ }