@sigsentry/core 0.1.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.
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/index.d.ts +458 -0
- package/dist/index.js +193 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SigSentry
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @sigsentry/core
|
|
2
|
+
|
|
3
|
+
TypeScript API client and shared types for [SigSentry](https://sigsentry.dev) — AI-powered log analysis.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @sigsentry/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { SigSentryClient } from '@sigsentry/core';
|
|
15
|
+
|
|
16
|
+
const client = new SigSentryClient({
|
|
17
|
+
apiKey: 'your-api-key',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Create an analysis
|
|
21
|
+
const result = await client.createAnalysis({
|
|
22
|
+
description: 'Users getting 500 errors on checkout',
|
|
23
|
+
timeStart: new Date('2024-01-15T10:00:00Z'),
|
|
24
|
+
timeEnd: new Date('2024-01-15T11:00:00Z'),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Stream results in real-time
|
|
28
|
+
await client.createAnalysis(input, {
|
|
29
|
+
onStatus: (stage) => console.log(`Stage: ${stage}`),
|
|
30
|
+
onPartial: (partial) => console.log(`Severity: ${partial.severity}`),
|
|
31
|
+
onComplete: (id, result) => console.log(`Done: ${result.summary}`),
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## What's Included
|
|
36
|
+
|
|
37
|
+
- **SigSentryClient** — Framework-agnostic API client with SSE streaming
|
|
38
|
+
- **TypeScript types** — AnalysisResult, AnalysisInput, ApiResponse, and more
|
|
39
|
+
- **Result<T, E>** — Type-safe error handling without exceptions
|
|
40
|
+
- **ErrorCode** — Standardized error codes
|
|
41
|
+
|
|
42
|
+
## For React
|
|
43
|
+
|
|
44
|
+
See [@sigsentry/react](https://www.npmjs.com/package/@sigsentry/react) for drop-in React components.
|
|
45
|
+
|
|
46
|
+
## License
|
|
47
|
+
|
|
48
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
type AnalysisSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
2
|
+
type AnalysisStatus = 'pending' | 'processing' | 'complete' | 'partial' | 'failed';
|
|
3
|
+
interface AnalysisInput {
|
|
4
|
+
screenshot?: File | Buffer;
|
|
5
|
+
description: string;
|
|
6
|
+
timeStart: Date;
|
|
7
|
+
timeEnd: Date;
|
|
8
|
+
metadata?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
interface AnalysisResult {
|
|
11
|
+
id: string;
|
|
12
|
+
status: AnalysisStatus;
|
|
13
|
+
createdAt: Date;
|
|
14
|
+
summary: string;
|
|
15
|
+
severity: AnalysisSeverity;
|
|
16
|
+
confidence: number;
|
|
17
|
+
rootCause: {
|
|
18
|
+
description: string;
|
|
19
|
+
service: string;
|
|
20
|
+
errorType: string;
|
|
21
|
+
category: ErrorCategory;
|
|
22
|
+
};
|
|
23
|
+
affectedServices: ServiceImpact[];
|
|
24
|
+
timeline: TimelineEntry[];
|
|
25
|
+
logEvidence: LogEvidence[];
|
|
26
|
+
codeCorrelation?: {
|
|
27
|
+
available: boolean;
|
|
28
|
+
suspectedCode: {
|
|
29
|
+
repo: string;
|
|
30
|
+
filePath: string;
|
|
31
|
+
lineRange: [number, number];
|
|
32
|
+
functionName: string;
|
|
33
|
+
snippet: string;
|
|
34
|
+
};
|
|
35
|
+
causalPR?: {
|
|
36
|
+
id: string;
|
|
37
|
+
title: string;
|
|
38
|
+
author: {
|
|
39
|
+
name: string;
|
|
40
|
+
username: string;
|
|
41
|
+
};
|
|
42
|
+
mergedAt: Date;
|
|
43
|
+
url: string;
|
|
44
|
+
confidence: number;
|
|
45
|
+
explanation: string;
|
|
46
|
+
};
|
|
47
|
+
recentCommits: CommitRef[];
|
|
48
|
+
};
|
|
49
|
+
suggestedActions: SuggestedAction[];
|
|
50
|
+
relatedIncidents: string[];
|
|
51
|
+
logsScanned: number;
|
|
52
|
+
timeWindow: {
|
|
53
|
+
start: Date;
|
|
54
|
+
end: Date;
|
|
55
|
+
};
|
|
56
|
+
processingTimeMs: number;
|
|
57
|
+
}
|
|
58
|
+
type ErrorCategory = 'authentication' | 'authorization' | 'database' | 'network' | 'timeout' | 'rate_limiting' | 'validation' | 'null_reference' | 'configuration' | 'dependency' | 'memory' | 'disk' | 'unknown';
|
|
59
|
+
interface ServiceImpact {
|
|
60
|
+
serviceName: string;
|
|
61
|
+
role: 'origin' | 'propagator' | 'affected';
|
|
62
|
+
errorCount: number;
|
|
63
|
+
firstSeen: Date;
|
|
64
|
+
lastSeen: Date;
|
|
65
|
+
}
|
|
66
|
+
interface TimelineEntry {
|
|
67
|
+
timestamp: Date;
|
|
68
|
+
service: string;
|
|
69
|
+
level: 'error' | 'warn' | 'info';
|
|
70
|
+
message: string;
|
|
71
|
+
isRootCause: boolean;
|
|
72
|
+
}
|
|
73
|
+
interface LogEvidence {
|
|
74
|
+
timestamp: Date;
|
|
75
|
+
service: string;
|
|
76
|
+
level: string;
|
|
77
|
+
message: string;
|
|
78
|
+
raw: string;
|
|
79
|
+
relevanceScore: number;
|
|
80
|
+
}
|
|
81
|
+
interface SuggestedAction {
|
|
82
|
+
priority: number;
|
|
83
|
+
action: string;
|
|
84
|
+
rationale: string;
|
|
85
|
+
type: 'fix' | 'investigate' | 'mitigate' | 'escalate';
|
|
86
|
+
}
|
|
87
|
+
interface CommitRef {
|
|
88
|
+
sha: string;
|
|
89
|
+
message: string;
|
|
90
|
+
author: string;
|
|
91
|
+
date: Date;
|
|
92
|
+
filesChanged: string[];
|
|
93
|
+
}
|
|
94
|
+
interface FollowUpInput {
|
|
95
|
+
analysisId: string;
|
|
96
|
+
question: string;
|
|
97
|
+
}
|
|
98
|
+
interface FollowUpResult {
|
|
99
|
+
analysisId: string;
|
|
100
|
+
answer: string;
|
|
101
|
+
additionalEvidence?: LogEvidence[];
|
|
102
|
+
updatedSuggestedActions?: SuggestedAction[];
|
|
103
|
+
}
|
|
104
|
+
interface AnalysisFeedback {
|
|
105
|
+
analysisId: string;
|
|
106
|
+
accuracy: 'correct' | 'partially_correct' | 'incorrect';
|
|
107
|
+
comment?: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface LogSourceAdapter {
|
|
111
|
+
testConnection(config: LogSourceConfig): Promise<ConnectionResult>;
|
|
112
|
+
queryLogs(params: LogQuery): Promise<LogResult>;
|
|
113
|
+
listSources(config: LogSourceConfig): Promise<LogSourceInfo[]>;
|
|
114
|
+
metadata: AdapterMetadata;
|
|
115
|
+
}
|
|
116
|
+
interface LogSourceConfig {
|
|
117
|
+
type: LogSourceType;
|
|
118
|
+
credentials: Record<string, string>;
|
|
119
|
+
region?: string;
|
|
120
|
+
settings?: Record<string, unknown>;
|
|
121
|
+
}
|
|
122
|
+
type LogSourceType = 'cloudwatch' | 'datadog' | 'elastic' | 'loki' | 'splunk' | 'gcp_logging';
|
|
123
|
+
interface LogQuery {
|
|
124
|
+
timeRange: {
|
|
125
|
+
start: Date;
|
|
126
|
+
end: Date;
|
|
127
|
+
};
|
|
128
|
+
sources: string[];
|
|
129
|
+
filters?: LogFilter[];
|
|
130
|
+
limit?: number;
|
|
131
|
+
cursor?: string;
|
|
132
|
+
}
|
|
133
|
+
interface LogFilter {
|
|
134
|
+
field: string;
|
|
135
|
+
operator: 'eq' | 'contains' | 'regex' | 'gt' | 'lt';
|
|
136
|
+
value: string;
|
|
137
|
+
}
|
|
138
|
+
interface LogResult {
|
|
139
|
+
entries: LogEntry[];
|
|
140
|
+
totalCount: number;
|
|
141
|
+
nextCursor?: string;
|
|
142
|
+
truncated: boolean;
|
|
143
|
+
}
|
|
144
|
+
interface LogEntry {
|
|
145
|
+
timestamp: Date;
|
|
146
|
+
level: string;
|
|
147
|
+
service: string;
|
|
148
|
+
message: string;
|
|
149
|
+
raw: string;
|
|
150
|
+
metadata?: Record<string, string>;
|
|
151
|
+
}
|
|
152
|
+
interface LogSourceInfo {
|
|
153
|
+
id: string;
|
|
154
|
+
name: string;
|
|
155
|
+
type: string;
|
|
156
|
+
}
|
|
157
|
+
interface ConnectionResult {
|
|
158
|
+
success: boolean;
|
|
159
|
+
message: string;
|
|
160
|
+
details?: Record<string, unknown>;
|
|
161
|
+
}
|
|
162
|
+
interface AdapterMetadata {
|
|
163
|
+
type: LogSourceType;
|
|
164
|
+
displayName: string;
|
|
165
|
+
description: string;
|
|
166
|
+
requiredCredentials: CredentialField[];
|
|
167
|
+
supportedFeatures: string[];
|
|
168
|
+
}
|
|
169
|
+
interface CredentialField {
|
|
170
|
+
key: string;
|
|
171
|
+
label: string;
|
|
172
|
+
type: 'text' | 'password' | 'select';
|
|
173
|
+
required: boolean;
|
|
174
|
+
placeholder?: string;
|
|
175
|
+
options?: {
|
|
176
|
+
label: string;
|
|
177
|
+
value: string;
|
|
178
|
+
}[];
|
|
179
|
+
}
|
|
180
|
+
interface CodeRepoAdapter {
|
|
181
|
+
testConnection(config: RepoConfig): Promise<ConnectionResult>;
|
|
182
|
+
getFileContent(params: {
|
|
183
|
+
repo: string;
|
|
184
|
+
path: string;
|
|
185
|
+
ref?: string;
|
|
186
|
+
}): Promise<FileContent>;
|
|
187
|
+
getBlame(params: {
|
|
188
|
+
repo: string;
|
|
189
|
+
path: string;
|
|
190
|
+
ref?: string;
|
|
191
|
+
lineStart?: number;
|
|
192
|
+
lineEnd?: number;
|
|
193
|
+
}): Promise<BlameResult[]>;
|
|
194
|
+
findPullRequests(params: {
|
|
195
|
+
repo: string;
|
|
196
|
+
paths: string[];
|
|
197
|
+
mergedAfter: Date;
|
|
198
|
+
mergedBefore: Date;
|
|
199
|
+
}): Promise<PullRequestInfo[]>;
|
|
200
|
+
getPullRequestDiff(params: {
|
|
201
|
+
repo: string;
|
|
202
|
+
prId: string;
|
|
203
|
+
filePaths?: string[];
|
|
204
|
+
}): Promise<DiffResult>;
|
|
205
|
+
listRepositories(config: RepoConfig): Promise<RepositoryInfo[]>;
|
|
206
|
+
}
|
|
207
|
+
interface RepoConfig {
|
|
208
|
+
platform: RepoPlatform;
|
|
209
|
+
credentials: Record<string, string>;
|
|
210
|
+
baseUrl?: string;
|
|
211
|
+
}
|
|
212
|
+
type RepoPlatform = 'github' | 'gitlab' | 'bitbucket' | 'azure_devops';
|
|
213
|
+
interface FileContent {
|
|
214
|
+
path: string;
|
|
215
|
+
content: string;
|
|
216
|
+
encoding: 'utf8' | 'base64';
|
|
217
|
+
sha: string;
|
|
218
|
+
size: number;
|
|
219
|
+
}
|
|
220
|
+
interface BlameResult {
|
|
221
|
+
lineStart: number;
|
|
222
|
+
lineEnd: number;
|
|
223
|
+
commit: {
|
|
224
|
+
sha: string;
|
|
225
|
+
author: string;
|
|
226
|
+
date: Date;
|
|
227
|
+
message: string;
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
interface PullRequestInfo {
|
|
231
|
+
id: string;
|
|
232
|
+
title: string;
|
|
233
|
+
author: {
|
|
234
|
+
name: string;
|
|
235
|
+
username: string;
|
|
236
|
+
avatar?: string;
|
|
237
|
+
};
|
|
238
|
+
mergedAt: Date;
|
|
239
|
+
url: string;
|
|
240
|
+
filesChanged: string[];
|
|
241
|
+
additions: number;
|
|
242
|
+
deletions: number;
|
|
243
|
+
}
|
|
244
|
+
interface DiffResult {
|
|
245
|
+
prId: string;
|
|
246
|
+
files: FileDiff[];
|
|
247
|
+
}
|
|
248
|
+
interface FileDiff {
|
|
249
|
+
path: string;
|
|
250
|
+
additions: number;
|
|
251
|
+
deletions: number;
|
|
252
|
+
patch: string;
|
|
253
|
+
}
|
|
254
|
+
interface RepositoryInfo {
|
|
255
|
+
id: string;
|
|
256
|
+
name: string;
|
|
257
|
+
fullName: string;
|
|
258
|
+
defaultBranch: string;
|
|
259
|
+
url: string;
|
|
260
|
+
private: boolean;
|
|
261
|
+
}
|
|
262
|
+
interface ServiceRepoMapping {
|
|
263
|
+
serviceName: string;
|
|
264
|
+
repo: string;
|
|
265
|
+
pathPrefix: string;
|
|
266
|
+
defaultBranch: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
interface ApiResponse<T> {
|
|
270
|
+
success: boolean;
|
|
271
|
+
data?: T;
|
|
272
|
+
error?: ApiError;
|
|
273
|
+
}
|
|
274
|
+
interface ApiError {
|
|
275
|
+
code: string;
|
|
276
|
+
message: string;
|
|
277
|
+
details?: Record<string, unknown>;
|
|
278
|
+
}
|
|
279
|
+
interface CreateAnalysisRequest {
|
|
280
|
+
description: string;
|
|
281
|
+
timeStart: string;
|
|
282
|
+
timeEnd: string;
|
|
283
|
+
metadata?: Record<string, string>;
|
|
284
|
+
}
|
|
285
|
+
interface ListAnalysesQuery {
|
|
286
|
+
page?: number;
|
|
287
|
+
limit?: number;
|
|
288
|
+
status?: AnalysisStatus;
|
|
289
|
+
severity?: AnalysisSeverity;
|
|
290
|
+
fromDate?: string;
|
|
291
|
+
toDate?: string;
|
|
292
|
+
}
|
|
293
|
+
interface FollowUpRequest {
|
|
294
|
+
question: string;
|
|
295
|
+
}
|
|
296
|
+
interface FeedbackRequest {
|
|
297
|
+
accuracy: 'correct' | 'partially_correct' | 'incorrect';
|
|
298
|
+
comment?: string;
|
|
299
|
+
}
|
|
300
|
+
type SSEEvent = {
|
|
301
|
+
event: 'status';
|
|
302
|
+
data: {
|
|
303
|
+
stage: AnalysisStage;
|
|
304
|
+
detail?: string;
|
|
305
|
+
};
|
|
306
|
+
} | {
|
|
307
|
+
event: 'partial';
|
|
308
|
+
data: Partial<AnalysisResult>;
|
|
309
|
+
} | {
|
|
310
|
+
event: 'complete';
|
|
311
|
+
data: {
|
|
312
|
+
analysisId: string;
|
|
313
|
+
result: AnalysisResult;
|
|
314
|
+
};
|
|
315
|
+
} | {
|
|
316
|
+
event: 'error';
|
|
317
|
+
data: {
|
|
318
|
+
code: string;
|
|
319
|
+
message: string;
|
|
320
|
+
};
|
|
321
|
+
};
|
|
322
|
+
type AnalysisStage = 'input_received' | 'image_processing' | 'logs_fetching' | 'logs_preprocessing' | 'ai_analyzing' | 'code_correlating' | 'complete' | 'failed';
|
|
323
|
+
|
|
324
|
+
interface Tenant {
|
|
325
|
+
id: string;
|
|
326
|
+
name: string;
|
|
327
|
+
plan: PricingTier;
|
|
328
|
+
createdAt: Date;
|
|
329
|
+
settings: TenantSettings;
|
|
330
|
+
}
|
|
331
|
+
type PricingTier = 'starter' | 'team' | 'business' | 'enterprise';
|
|
332
|
+
interface TenantSettings {
|
|
333
|
+
timeBufferMinutes: number;
|
|
334
|
+
maxAnalysesPerMonth: number;
|
|
335
|
+
enabledFeatures: FeatureFlag[];
|
|
336
|
+
defaultLogSources: string[];
|
|
337
|
+
}
|
|
338
|
+
type FeatureFlag = 'code_correlation' | 'pattern_memory' | 'slack_integration' | 'teams_integration' | 'sso' | 'custom_llm' | 'self_hosted' | 'audit_logs';
|
|
339
|
+
interface ApiKeyRecord {
|
|
340
|
+
id: string;
|
|
341
|
+
tenantId: string;
|
|
342
|
+
keyHash: string;
|
|
343
|
+
prefix: string;
|
|
344
|
+
name: string;
|
|
345
|
+
permissions: ApiKeyPermission[];
|
|
346
|
+
createdAt: Date;
|
|
347
|
+
lastUsedAt?: Date;
|
|
348
|
+
expiresAt?: Date;
|
|
349
|
+
revoked: boolean;
|
|
350
|
+
}
|
|
351
|
+
type ApiKeyPermission = 'analysis:create' | 'analysis:read' | 'config:read' | 'config:write' | 'admin';
|
|
352
|
+
interface LogSourceConfigRecord {
|
|
353
|
+
id: string;
|
|
354
|
+
tenantId: string;
|
|
355
|
+
type: LogSourceType;
|
|
356
|
+
name: string;
|
|
357
|
+
credentials: string;
|
|
358
|
+
sources: string[];
|
|
359
|
+
isActive: boolean;
|
|
360
|
+
lastTestedAt?: Date;
|
|
361
|
+
lastTestResult?: ConnectionResult;
|
|
362
|
+
createdAt: Date;
|
|
363
|
+
}
|
|
364
|
+
interface RepoConfigRecord {
|
|
365
|
+
id: string;
|
|
366
|
+
tenantId: string;
|
|
367
|
+
platform: RepoPlatform;
|
|
368
|
+
credentials: string;
|
|
369
|
+
repositories: string[];
|
|
370
|
+
serviceMappings: ServiceRepoMapping[];
|
|
371
|
+
lookbackDays: number;
|
|
372
|
+
isActive: boolean;
|
|
373
|
+
createdAt: Date;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
type Result<T, E = Error> = {
|
|
377
|
+
ok: true;
|
|
378
|
+
value: T;
|
|
379
|
+
} | {
|
|
380
|
+
ok: false;
|
|
381
|
+
error: E;
|
|
382
|
+
};
|
|
383
|
+
declare function ok<T>(value: T): Result<T, never>;
|
|
384
|
+
declare function err<E>(error: E): Result<never, E>;
|
|
385
|
+
declare function isOk<T, E>(result: Result<T, E>): result is {
|
|
386
|
+
ok: true;
|
|
387
|
+
value: T;
|
|
388
|
+
};
|
|
389
|
+
declare function isErr<T, E>(result: Result<T, E>): result is {
|
|
390
|
+
ok: false;
|
|
391
|
+
error: E;
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
declare enum ErrorCode {
|
|
395
|
+
UNAUTHORIZED = "UNAUTHORIZED",
|
|
396
|
+
FORBIDDEN = "FORBIDDEN",
|
|
397
|
+
API_KEY_INVALID = "API_KEY_INVALID",
|
|
398
|
+
API_KEY_EXPIRED = "API_KEY_EXPIRED",
|
|
399
|
+
API_KEY_REVOKED = "API_KEY_REVOKED",
|
|
400
|
+
RATE_LIMIT_EXCEEDED = "RATE_LIMIT_EXCEEDED",
|
|
401
|
+
ANALYSIS_QUOTA_EXCEEDED = "ANALYSIS_QUOTA_EXCEEDED",
|
|
402
|
+
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
403
|
+
INVALID_TIME_RANGE = "INVALID_TIME_RANGE",
|
|
404
|
+
FILE_TOO_LARGE = "FILE_TOO_LARGE",
|
|
405
|
+
LOG_SOURCE_CONNECTION_FAILED = "LOG_SOURCE_CONNECTION_FAILED",
|
|
406
|
+
LOG_SOURCE_QUERY_FAILED = "LOG_SOURCE_QUERY_FAILED",
|
|
407
|
+
LOG_SOURCE_NOT_CONFIGURED = "LOG_SOURCE_NOT_CONFIGURED",
|
|
408
|
+
REPO_CONNECTION_FAILED = "REPO_CONNECTION_FAILED",
|
|
409
|
+
REPO_NOT_CONFIGURED = "REPO_NOT_CONFIGURED",
|
|
410
|
+
REPO_FILE_NOT_FOUND = "REPO_FILE_NOT_FOUND",
|
|
411
|
+
FEATURE_NOT_AVAILABLE = "FEATURE_NOT_AVAILABLE",
|
|
412
|
+
ANALYSIS_NOT_FOUND = "ANALYSIS_NOT_FOUND",
|
|
413
|
+
ANALYSIS_FAILED = "ANALYSIS_FAILED",
|
|
414
|
+
LLM_ERROR = "LLM_ERROR",
|
|
415
|
+
INTERNAL_ERROR = "INTERNAL_ERROR",
|
|
416
|
+
NOT_FOUND = "NOT_FOUND",
|
|
417
|
+
TENANT_NOT_FOUND = "TENANT_NOT_FOUND"
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
421
|
+
declare function createLogger(service: string, minLevel?: LogLevel): {
|
|
422
|
+
debug: (message: string, context?: Record<string, unknown>) => void;
|
|
423
|
+
info: (message: string, context?: Record<string, unknown>) => void;
|
|
424
|
+
warn: (message: string, context?: Record<string, unknown>) => void;
|
|
425
|
+
error: (message: string, context?: Record<string, unknown>) => void;
|
|
426
|
+
};
|
|
427
|
+
type Logger = ReturnType<typeof createLogger>;
|
|
428
|
+
|
|
429
|
+
interface SigSentryClientConfig {
|
|
430
|
+
apiKey: string;
|
|
431
|
+
baseUrl?: string;
|
|
432
|
+
}
|
|
433
|
+
interface AnalysisStreamCallbacks {
|
|
434
|
+
onStatus?: (stage: AnalysisStage, detail?: string) => void;
|
|
435
|
+
onPartial?: (partial: Partial<AnalysisResult>) => void;
|
|
436
|
+
onComplete?: (analysisId: string, result: AnalysisResult) => void;
|
|
437
|
+
onError?: (error: ApiError) => void;
|
|
438
|
+
}
|
|
439
|
+
declare class SigSentryClient {
|
|
440
|
+
private readonly apiKey;
|
|
441
|
+
private readonly baseUrl;
|
|
442
|
+
constructor(config: SigSentryClientConfig);
|
|
443
|
+
private headers;
|
|
444
|
+
private request;
|
|
445
|
+
createAnalysis(input: Omit<AnalysisInput, 'screenshot'> & {
|
|
446
|
+
screenshot?: File;
|
|
447
|
+
}, callbacks?: AnalysisStreamCallbacks): Promise<ApiResponse<{
|
|
448
|
+
analysisId: string;
|
|
449
|
+
result: AnalysisResult;
|
|
450
|
+
}>>;
|
|
451
|
+
private handleSSEStream;
|
|
452
|
+
getAnalysis(id: string): Promise<ApiResponse<AnalysisResult>>;
|
|
453
|
+
listAnalyses(query?: ListAnalysesQuery): Promise<ApiResponse<AnalysisResult[]>>;
|
|
454
|
+
askFollowUp(analysisId: string, question: string): Promise<ApiResponse<FollowUpResult>>;
|
|
455
|
+
submitFeedback(analysisId: string, feedback: Omit<AnalysisFeedback, 'analysisId'>): Promise<ApiResponse<void>>;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export { type AdapterMetadata, type AnalysisFeedback, type AnalysisInput, type AnalysisResult, type AnalysisSeverity, type AnalysisStage, type AnalysisStatus, type AnalysisStreamCallbacks, type ApiError, type ApiKeyPermission, type ApiKeyRecord, type ApiResponse, type BlameResult, type CodeRepoAdapter, type CommitRef, type ConnectionResult, type CreateAnalysisRequest, type CredentialField, type DiffResult, type ErrorCategory, ErrorCode, type FeatureFlag, type FeedbackRequest, type FileContent, type FileDiff, type FollowUpInput, type FollowUpRequest, type FollowUpResult, type ListAnalysesQuery, type LogEntry, type LogEvidence, type LogFilter, type LogQuery, type LogResult, type LogSourceAdapter, type LogSourceConfig, type LogSourceConfigRecord, type LogSourceInfo, type LogSourceType, type Logger, type PricingTier, type PullRequestInfo, type RepoConfig, type RepoConfigRecord, type RepoPlatform, type RepositoryInfo, type Result, type SSEEvent, type ServiceImpact, type ServiceRepoMapping, SigSentryClient, type SigSentryClientConfig, type SuggestedAction, type Tenant, type TenantSettings, type TimelineEntry, createLogger, err, isErr, isOk, ok };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// src/result.ts
|
|
2
|
+
function ok(value) {
|
|
3
|
+
return { ok: true, value };
|
|
4
|
+
}
|
|
5
|
+
function err(error) {
|
|
6
|
+
return { ok: false, error };
|
|
7
|
+
}
|
|
8
|
+
function isOk(result) {
|
|
9
|
+
return result.ok;
|
|
10
|
+
}
|
|
11
|
+
function isErr(result) {
|
|
12
|
+
return !result.ok;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// src/errors.ts
|
|
16
|
+
var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
17
|
+
ErrorCode2["UNAUTHORIZED"] = "UNAUTHORIZED";
|
|
18
|
+
ErrorCode2["FORBIDDEN"] = "FORBIDDEN";
|
|
19
|
+
ErrorCode2["API_KEY_INVALID"] = "API_KEY_INVALID";
|
|
20
|
+
ErrorCode2["API_KEY_EXPIRED"] = "API_KEY_EXPIRED";
|
|
21
|
+
ErrorCode2["API_KEY_REVOKED"] = "API_KEY_REVOKED";
|
|
22
|
+
ErrorCode2["RATE_LIMIT_EXCEEDED"] = "RATE_LIMIT_EXCEEDED";
|
|
23
|
+
ErrorCode2["ANALYSIS_QUOTA_EXCEEDED"] = "ANALYSIS_QUOTA_EXCEEDED";
|
|
24
|
+
ErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
|
|
25
|
+
ErrorCode2["INVALID_TIME_RANGE"] = "INVALID_TIME_RANGE";
|
|
26
|
+
ErrorCode2["FILE_TOO_LARGE"] = "FILE_TOO_LARGE";
|
|
27
|
+
ErrorCode2["LOG_SOURCE_CONNECTION_FAILED"] = "LOG_SOURCE_CONNECTION_FAILED";
|
|
28
|
+
ErrorCode2["LOG_SOURCE_QUERY_FAILED"] = "LOG_SOURCE_QUERY_FAILED";
|
|
29
|
+
ErrorCode2["LOG_SOURCE_NOT_CONFIGURED"] = "LOG_SOURCE_NOT_CONFIGURED";
|
|
30
|
+
ErrorCode2["REPO_CONNECTION_FAILED"] = "REPO_CONNECTION_FAILED";
|
|
31
|
+
ErrorCode2["REPO_NOT_CONFIGURED"] = "REPO_NOT_CONFIGURED";
|
|
32
|
+
ErrorCode2["REPO_FILE_NOT_FOUND"] = "REPO_FILE_NOT_FOUND";
|
|
33
|
+
ErrorCode2["FEATURE_NOT_AVAILABLE"] = "FEATURE_NOT_AVAILABLE";
|
|
34
|
+
ErrorCode2["ANALYSIS_NOT_FOUND"] = "ANALYSIS_NOT_FOUND";
|
|
35
|
+
ErrorCode2["ANALYSIS_FAILED"] = "ANALYSIS_FAILED";
|
|
36
|
+
ErrorCode2["LLM_ERROR"] = "LLM_ERROR";
|
|
37
|
+
ErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
38
|
+
ErrorCode2["NOT_FOUND"] = "NOT_FOUND";
|
|
39
|
+
ErrorCode2["TENANT_NOT_FOUND"] = "TENANT_NOT_FOUND";
|
|
40
|
+
return ErrorCode2;
|
|
41
|
+
})(ErrorCode || {});
|
|
42
|
+
|
|
43
|
+
// src/logger.ts
|
|
44
|
+
var LOG_LEVELS = {
|
|
45
|
+
debug: 0,
|
|
46
|
+
info: 1,
|
|
47
|
+
warn: 2,
|
|
48
|
+
error: 3
|
|
49
|
+
};
|
|
50
|
+
function createLogger(service, minLevel = "info") {
|
|
51
|
+
const minLevelNum = LOG_LEVELS[minLevel];
|
|
52
|
+
function log(level, message, context) {
|
|
53
|
+
if (LOG_LEVELS[level] < minLevelNum) return;
|
|
54
|
+
const entry = {
|
|
55
|
+
level,
|
|
56
|
+
message,
|
|
57
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
58
|
+
context: { service, ...context }
|
|
59
|
+
};
|
|
60
|
+
const output = JSON.stringify(entry);
|
|
61
|
+
if (level === "error") {
|
|
62
|
+
process.stderr.write(output + "\n");
|
|
63
|
+
} else {
|
|
64
|
+
process.stdout.write(output + "\n");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
debug: (message, context) => log("debug", message, context),
|
|
69
|
+
info: (message, context) => log("info", message, context),
|
|
70
|
+
warn: (message, context) => log("warn", message, context),
|
|
71
|
+
error: (message, context) => log("error", message, context)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/client/index.ts
|
|
76
|
+
var SigSentryClient = class {
|
|
77
|
+
apiKey;
|
|
78
|
+
baseUrl;
|
|
79
|
+
constructor(config) {
|
|
80
|
+
this.apiKey = config.apiKey;
|
|
81
|
+
this.baseUrl = (config.baseUrl ?? "https://api.sigsentry.dev").replace(/\/$/, "");
|
|
82
|
+
}
|
|
83
|
+
headers() {
|
|
84
|
+
return {
|
|
85
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
86
|
+
"Content-Type": "application/json"
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
async request(method, path, body) {
|
|
90
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
91
|
+
method,
|
|
92
|
+
headers: this.headers(),
|
|
93
|
+
body: body ? JSON.stringify(body) : void 0
|
|
94
|
+
});
|
|
95
|
+
return await response.json();
|
|
96
|
+
}
|
|
97
|
+
async createAnalysis(input, callbacks) {
|
|
98
|
+
const formData = new FormData();
|
|
99
|
+
formData.append("description", input.description);
|
|
100
|
+
formData.append("timeStart", input.timeStart.toISOString());
|
|
101
|
+
formData.append("timeEnd", input.timeEnd.toISOString());
|
|
102
|
+
if (input.metadata) {
|
|
103
|
+
formData.append("metadata", JSON.stringify(input.metadata));
|
|
104
|
+
}
|
|
105
|
+
if (input.screenshot) {
|
|
106
|
+
formData.append("screenshot", input.screenshot);
|
|
107
|
+
}
|
|
108
|
+
const response = await fetch(`${this.baseUrl}/v1/analyses`, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
111
|
+
body: formData
|
|
112
|
+
});
|
|
113
|
+
if (!callbacks) {
|
|
114
|
+
return await response.json();
|
|
115
|
+
}
|
|
116
|
+
return this.handleSSEStream(response, callbacks);
|
|
117
|
+
}
|
|
118
|
+
async handleSSEStream(response, callbacks) {
|
|
119
|
+
const reader = response.body?.getReader();
|
|
120
|
+
if (!reader) {
|
|
121
|
+
const error = { code: "STREAM_ERROR", message: "No response body" };
|
|
122
|
+
callbacks.onError?.(error);
|
|
123
|
+
return { success: false, error };
|
|
124
|
+
}
|
|
125
|
+
const decoder = new TextDecoder();
|
|
126
|
+
let buffer = "";
|
|
127
|
+
let finalResult;
|
|
128
|
+
while (true) {
|
|
129
|
+
const { done, value } = await reader.read();
|
|
130
|
+
if (done) break;
|
|
131
|
+
buffer += decoder.decode(value, { stream: true });
|
|
132
|
+
const lines = buffer.split("\n");
|
|
133
|
+
buffer = lines.pop() ?? "";
|
|
134
|
+
let currentEvent = "";
|
|
135
|
+
for (const line of lines) {
|
|
136
|
+
if (line.startsWith("event: ")) {
|
|
137
|
+
currentEvent = line.slice(7).trim();
|
|
138
|
+
} else if (line.startsWith("data: ") && currentEvent) {
|
|
139
|
+
const data = JSON.parse(line.slice(6));
|
|
140
|
+
const event = { event: currentEvent, data };
|
|
141
|
+
switch (event.event) {
|
|
142
|
+
case "status":
|
|
143
|
+
callbacks.onStatus?.(event.data.stage, event.data.detail);
|
|
144
|
+
break;
|
|
145
|
+
case "partial":
|
|
146
|
+
callbacks.onPartial?.(event.data);
|
|
147
|
+
break;
|
|
148
|
+
case "complete":
|
|
149
|
+
callbacks.onComplete?.(event.data.analysisId, event.data.result);
|
|
150
|
+
finalResult = { success: true, data: event.data };
|
|
151
|
+
break;
|
|
152
|
+
case "error":
|
|
153
|
+
callbacks.onError?.(event.data);
|
|
154
|
+
finalResult = { success: false, error: event.data };
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
currentEvent = "";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return finalResult ?? { success: false, error: { code: "STREAM_ERROR", message: "Stream ended without result" } };
|
|
162
|
+
}
|
|
163
|
+
async getAnalysis(id) {
|
|
164
|
+
return this.request("GET", `/v1/analyses/${id}`);
|
|
165
|
+
}
|
|
166
|
+
async listAnalyses(query) {
|
|
167
|
+
const params = new URLSearchParams();
|
|
168
|
+
if (query) {
|
|
169
|
+
for (const [key, value] of Object.entries(query)) {
|
|
170
|
+
if (value !== void 0) params.set(key, String(value));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const qs = params.toString();
|
|
174
|
+
return this.request("GET", `/v1/analyses${qs ? `?${qs}` : ""}`);
|
|
175
|
+
}
|
|
176
|
+
async askFollowUp(analysisId, question) {
|
|
177
|
+
return this.request("POST", `/v1/analyses/${analysisId}/followup`, {
|
|
178
|
+
question
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
async submitFeedback(analysisId, feedback) {
|
|
182
|
+
return this.request("POST", `/v1/analyses/${analysisId}/feedback`, feedback);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
export {
|
|
186
|
+
ErrorCode,
|
|
187
|
+
SigSentryClient,
|
|
188
|
+
createLogger,
|
|
189
|
+
err,
|
|
190
|
+
isErr,
|
|
191
|
+
isOk,
|
|
192
|
+
ok
|
|
193
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sigsentry/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SigSentry core SDK — TypeScript API client, types, and utilities for AI-powered log analysis",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"zod": "^3.24.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"tsup": "^8.4.0",
|
|
27
|
+
"typescript": "^5.7.0",
|
|
28
|
+
"vitest": "^3.0.0"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"sigsentry",
|
|
32
|
+
"traceback",
|
|
33
|
+
"log-analysis",
|
|
34
|
+
"ai",
|
|
35
|
+
"api-client",
|
|
36
|
+
"sdk"
|
|
37
|
+
],
|
|
38
|
+
"homepage": "https://sigsentry.dev",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/SigSentry/sdk",
|
|
42
|
+
"directory": "packages/core"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/SigSentry/sdk/issues"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
49
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"clean": "rm -rf dist"
|
|
53
|
+
}
|
|
54
|
+
}
|