@errio/core 1.0.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 (50) hide show
  1. package/dist/classify.d.ts +11 -0
  2. package/dist/classify.d.ts.map +1 -0
  3. package/dist/classify.js +102 -0
  4. package/dist/classify.js.map +1 -0
  5. package/dist/client.d.ts +42 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +223 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/context.d.ts +29 -0
  10. package/dist/context.d.ts.map +1 -0
  11. package/dist/context.js +60 -0
  12. package/dist/context.js.map +1 -0
  13. package/dist/deploy.d.ts +29 -0
  14. package/dist/deploy.d.ts.map +1 -0
  15. package/dist/deploy.js +50 -0
  16. package/dist/deploy.js.map +1 -0
  17. package/dist/fingerprint.d.ts +30 -0
  18. package/dist/fingerprint.d.ts.map +1 -0
  19. package/dist/fingerprint.js +74 -0
  20. package/dist/fingerprint.js.map +1 -0
  21. package/dist/git.d.ts +12 -0
  22. package/dist/git.d.ts.map +1 -0
  23. package/dist/git.js +60 -0
  24. package/dist/git.js.map +1 -0
  25. package/dist/index.d.ts +12 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +21 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/redact.d.ts +19 -0
  30. package/dist/redact.d.ts.map +1 -0
  31. package/dist/redact.js +86 -0
  32. package/dist/redact.js.map +1 -0
  33. package/dist/sampling.d.ts +13 -0
  34. package/dist/sampling.d.ts.map +1 -0
  35. package/dist/sampling.js +23 -0
  36. package/dist/sampling.js.map +1 -0
  37. package/dist/serializer.d.ts +16 -0
  38. package/dist/serializer.d.ts.map +1 -0
  39. package/dist/serializer.js +92 -0
  40. package/dist/serializer.js.map +1 -0
  41. package/dist/transport.d.ts +39 -0
  42. package/dist/transport.d.ts.map +1 -0
  43. package/dist/transport.js +138 -0
  44. package/dist/transport.js.map +1 -0
  45. package/dist/types.d.ts +148 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +2 -0
  48. package/dist/types.js.map +1 -0
  49. package/package.json +47 -0
  50. package/src/index.ts +53 -0
@@ -0,0 +1,11 @@
1
+ import type { ErrorType, Severity } from './types.js';
2
+ /**
3
+ * Classify an error by type based on its name and message.
4
+ * Uses a priority-ordered rule set: test > build > type > dependency > runtime.
5
+ */
6
+ export declare function classifyError(error: Error): ErrorType;
7
+ /**
8
+ * Determine default severity based on how the error was captured.
9
+ */
10
+ export declare function defaultSeverity(captureSource: 'uncaughtException' | 'unhandledRejection' | 'manual'): Severity;
11
+ //# sourceMappingURL=classify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../src/classify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CA0BrD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,aAAa,EAAE,mBAAmB,GAAG,oBAAoB,GAAG,QAAQ,GACnE,QAAQ,CASV"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Classify an error by type based on its name and message.
3
+ * Uses a priority-ordered rule set: test > build > type > dependency > runtime.
4
+ */
5
+ export function classifyError(error) {
6
+ // Fast path: check error.name
7
+ const name = error.name?.toLowerCase() ?? '';
8
+ if (name === 'typeerror')
9
+ return 'type_error';
10
+ if (name === 'referenceerror' || name === 'rangeerror' || name === 'syntaxerror') {
11
+ return 'runtime_error';
12
+ }
13
+ const message = `${error.name ?? ''}: ${error.message ?? ''}`.toLowerCase();
14
+ // Test failures (highest priority)
15
+ if (TEST_PATTERNS.some((p) => p.test(message)))
16
+ return 'test_failure';
17
+ // Build failures
18
+ if (BUILD_PATTERNS.some((p) => p.test(message)))
19
+ return 'build_failure';
20
+ // Type errors
21
+ if (TYPE_PATTERNS.some((p) => p.test(message)))
22
+ return 'type_error';
23
+ // Dependency issues
24
+ if (DEP_PATTERNS.some((p) => p.test(message)))
25
+ return 'dependency_issue';
26
+ // Runtime errors
27
+ if (RUNTIME_PATTERNS.some((p) => p.test(message)))
28
+ return 'runtime_error';
29
+ return 'unknown';
30
+ }
31
+ /**
32
+ * Determine default severity based on how the error was captured.
33
+ */
34
+ export function defaultSeverity(captureSource) {
35
+ switch (captureSource) {
36
+ case 'uncaughtException':
37
+ return 'critical';
38
+ case 'unhandledRejection':
39
+ return 'high';
40
+ case 'manual':
41
+ return 'medium';
42
+ }
43
+ }
44
+ // ---------------------------------------------------------------------------
45
+ // Pattern sets
46
+ // ---------------------------------------------------------------------------
47
+ const TEST_PATTERNS = [
48
+ /\bexpect\b.*\b(to\s+equal|to\s+be|received|to\s+match)\b/,
49
+ /\bassert(ion|ed|\.)\b/,
50
+ /\btest\s+(failed|failure)\b/,
51
+ /\bfailing\s+tests?\b/,
52
+ /\b\d+\s+failing\b/,
53
+ /\bFAIL\b.*\.test\./,
54
+ /\bdescribe\b.*\bit\b/,
55
+ /\b(?:jest|vitest|mocha|cypress|playwright|pytest|rspec|junit|testng)\b/,
56
+ /\bava\b/,
57
+ ];
58
+ const BUILD_PATTERNS = [
59
+ /\bwebpack|esbuild|vite|rollup|parcel|turbopack\b/,
60
+ /\berror\s+ts\d{4}\b/,
61
+ /\btsc\b.*\berror\b/,
62
+ /\bcompilation\s+failed\b/,
63
+ /\bbuild\s+(failed|error)\b/,
64
+ /\bsyntax\s+error\b/,
65
+ /\bexit\s+code\s+[1-9]\b/,
66
+ /\bdocker\s+build\b/,
67
+ /\bmake\s*:.*error\b/,
68
+ /\bgcc|g\+\+|clang|javac|rustc|cargo\s+build|go\s+build\b/,
69
+ ];
70
+ const TYPE_PATTERNS = [
71
+ /\bnot\s+assignable\s+to\b/,
72
+ /\bcannot\s+read\s+propert(y|ies)\s+of\s+(null|undefined)\b/,
73
+ /\bis\s+not\s+a\s+function\b/,
74
+ /\bis\s+not\s+a\s+constructor\b/,
75
+ /\binvalid\s+type\b/,
76
+ /\bhas\s+no\s+(method|property)\b/,
77
+ /\btype\s+'[\w]+'\s+is\s+not\b/,
78
+ ];
79
+ const DEP_PATTERNS = [
80
+ /\bmodule\s+not\s+found\b/,
81
+ /\bcannot\s+(find|resolve)\s+(module|dependency|package)\b/,
82
+ /\bno\s+such\s+module\b/,
83
+ /\bpeer\s+dep(endenc(y|ies))?\b/,
84
+ /\bnpm\s+err|yarn\s+err|pnpm\s+err\b/,
85
+ /\bmodulenotfounderror\b/,
86
+ /\bclassnotfoundexception\b/,
87
+ /\bloaderror\b/,
88
+ /\bnomodulenamed\b/,
89
+ ];
90
+ const RUNTIME_PATTERNS = [
91
+ /\buncaught\s+(exception|error)\b/,
92
+ /\bunhandled\s+(rejection|exception|promise)\b/,
93
+ /\bsegmentation\s+fault\b/,
94
+ /\bstack\s+overflow\b/,
95
+ /\bout\s+of\s+memory\b/,
96
+ /\bsigkill|sigterm|sigsegv|sigabrt\b/,
97
+ /\beconnrefused|econnreset|etimedout|enotfound|epipe\b/,
98
+ /\bpanic\b/,
99
+ /\bfatal\s+error\b/,
100
+ /\bnullpointerexception|arrayindexoutofboundsexception|stackoverflowerror\b/,
101
+ ];
102
+ //# sourceMappingURL=classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../src/classify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { ErrioConfig, ResolvedConfig, ErrioPlugin, ErrioClientInterface, CaptureOptions, Breadcrumb, RequestContext } from './types.js';
2
+ /**
3
+ * Core Errio client. Manages configuration, plugins, transport, and
4
+ * error capture lifecycle. This is the central orchestrator of the SDK.
5
+ */
6
+ export declare class ErrioClient implements ErrioClientInterface {
7
+ private config;
8
+ private transport;
9
+ private dedup;
10
+ private plugins;
11
+ private gitInfo;
12
+ private initialized;
13
+ constructor(userConfig: ErrioConfig);
14
+ /**
15
+ * Register and initialize a plugin.
16
+ */
17
+ use(plugin: ErrioPlugin): Promise<void>;
18
+ /**
19
+ * Capture and send an error event.
20
+ */
21
+ captureError(error: Error, options?: CaptureOptions): void;
22
+ /**
23
+ * Capture an error from a global handler (uncaughtException/unhandledRejection).
24
+ * Used internally by the hooks module.
25
+ */
26
+ captureFromHandler(error: Error, source: 'uncaughtException' | 'unhandledRejection'): void;
27
+ /**
28
+ * Flush all pending events and shut down the client.
29
+ */
30
+ shutdown(): Promise<void>;
31
+ /**
32
+ * Force-flush any buffered events. Useful before process exit.
33
+ */
34
+ flush(): Promise<void>;
35
+ getConfig(): Readonly<ResolvedConfig>;
36
+ addBreadcrumb(breadcrumb: Omit<Breadcrumb, 'timestamp'>): void;
37
+ setContext(ctx: Partial<RequestContext>): void;
38
+ getContext(): RequestContext | undefined;
39
+ runWithContext<T>(ctx: RequestContext, fn: () => T): T;
40
+ private buildEvent;
41
+ }
42
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,WAAW,EACX,oBAAoB,EAEpB,cAAc,EACd,UAAU,EACV,cAAc,EACf,MAAM,YAAY,CAAC;AAqBpB;;;GAGG;AACH,qBAAa,WAAY,YAAW,oBAAoB;IACtD,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,WAAW,CAAS;gBAEhB,UAAU,EAAE,WAAW;IA2BnC;;OAEG;IACG,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI;IAY1D;;;OAGG;IACH,kBAAkB,CAChB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,mBAAmB,GAAG,oBAAoB,GACjD,IAAI;IAaP;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAa/B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,SAAS,IAAI,QAAQ,CAAC,cAAc,CAAC;IAIrC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI;IAI9D,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI;IAI9C,UAAU,IAAI,cAAc,GAAG,SAAS;IAIxC,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAQtD,OAAO,CAAC,UAAU;CAsGnB"}
package/dist/client.js ADDED
@@ -0,0 +1,223 @@
1
+ import { BatchTransport } from './transport.js';
2
+ import { DedupCache, generateFingerprint, normalizeMessage } from './fingerprint.js';
3
+ import { classifyError, defaultSeverity } from './classify.js';
4
+ import { serializeCauseChain, extractFilePaths } from './serializer.js';
5
+ import { redactString } from './redact.js';
6
+ import { shouldSample } from './sampling.js';
7
+ import { detectGitInfo } from './git.js';
8
+ import { getContext, setContext, runWithContext, addBreadcrumb as addBreadcrumbToStore, getBreadcrumbs, } from './context.js';
9
+ const DEFAULT_ENDPOINT = 'https://errio.mosaicwellness.in';
10
+ const DEFAULT_BATCH_SIZE = 10;
11
+ const DEFAULT_FLUSH_INTERVAL_MS = 5000;
12
+ const DEFAULT_SAMPLE_RATE = 1.0;
13
+ /**
14
+ * Core Errio client. Manages configuration, plugins, transport, and
15
+ * error capture lifecycle. This is the central orchestrator of the SDK.
16
+ */
17
+ export class ErrioClient {
18
+ config;
19
+ transport;
20
+ dedup;
21
+ plugins = [];
22
+ gitInfo = detectGitInfo();
23
+ initialized = false;
24
+ constructor(userConfig) {
25
+ if (!userConfig.apiKey || !userConfig.apiKey.startsWith('ak_')) {
26
+ throw new Error('[errio] Invalid API key. Must start with "ak_".');
27
+ }
28
+ this.config = {
29
+ apiKey: userConfig.apiKey,
30
+ endpoint: userConfig.endpoint ?? DEFAULT_ENDPOINT,
31
+ environment: userConfig.environment ?? process.env.NODE_ENV ?? 'production',
32
+ serviceName: userConfig.serviceName ?? '',
33
+ sampleRate: clamp(userConfig.sampleRate ?? DEFAULT_SAMPLE_RATE, 0, 1),
34
+ batchSize: userConfig.batchSize ?? DEFAULT_BATCH_SIZE,
35
+ flushIntervalMs: userConfig.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS,
36
+ beforeSend: userConfig.beforeSend ?? null,
37
+ debug: userConfig.debug ?? false,
38
+ };
39
+ this.transport = new BatchTransport(this.config);
40
+ this.dedup = new DedupCache();
41
+ if (userConfig.plugins) {
42
+ for (const plugin of userConfig.plugins) {
43
+ this.use(plugin);
44
+ }
45
+ }
46
+ }
47
+ /**
48
+ * Register and initialize a plugin.
49
+ */
50
+ async use(plugin) {
51
+ if (this.plugins.some((p) => p.name === plugin.name)) {
52
+ if (this.config.debug) {
53
+ console.warn(`[errio] Plugin "${plugin.name}" already registered, skipping.`);
54
+ }
55
+ return;
56
+ }
57
+ this.plugins.push(plugin);
58
+ await plugin.setup(this);
59
+ if (this.config.debug) {
60
+ console.log(`[errio] Plugin "${plugin.name}" initialized.`);
61
+ }
62
+ }
63
+ /**
64
+ * Capture and send an error event.
65
+ */
66
+ captureError(error, options) {
67
+ try {
68
+ const event = this.buildEvent(error, options, 'manual');
69
+ if (!event)
70
+ return;
71
+ this.transport.enqueue(event);
72
+ }
73
+ catch (err) {
74
+ if (this.config.debug) {
75
+ console.error('[errio] Failed to capture error:', err);
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Capture an error from a global handler (uncaughtException/unhandledRejection).
81
+ * Used internally by the hooks module.
82
+ */
83
+ captureFromHandler(error, source) {
84
+ try {
85
+ const severity = defaultSeverity(source);
86
+ const event = this.buildEvent(error, { severity }, source);
87
+ if (!event)
88
+ return;
89
+ this.transport.enqueue(event);
90
+ }
91
+ catch (err) {
92
+ if (this.config.debug) {
93
+ console.error('[errio] Failed to capture handler error:', err);
94
+ }
95
+ }
96
+ }
97
+ /**
98
+ * Flush all pending events and shut down the client.
99
+ */
100
+ async shutdown() {
101
+ for (const plugin of this.plugins) {
102
+ try {
103
+ await plugin.teardown?.();
104
+ }
105
+ catch (err) {
106
+ if (this.config.debug) {
107
+ console.error(`[errio] Plugin "${plugin.name}" teardown failed:`, err);
108
+ }
109
+ }
110
+ }
111
+ await this.transport.shutdown();
112
+ }
113
+ /**
114
+ * Force-flush any buffered events. Useful before process exit.
115
+ */
116
+ async flush() {
117
+ await this.transport.flush();
118
+ }
119
+ // -- ErrioClientInterface --
120
+ getConfig() {
121
+ return this.config;
122
+ }
123
+ addBreadcrumb(breadcrumb) {
124
+ addBreadcrumbToStore(breadcrumb);
125
+ }
126
+ setContext(ctx) {
127
+ setContext(ctx);
128
+ }
129
+ getContext() {
130
+ return getContext();
131
+ }
132
+ runWithContext(ctx, fn) {
133
+ return runWithContext(ctx, fn);
134
+ }
135
+ // ---------------------------------------------------------------------------
136
+ // Private
137
+ // ---------------------------------------------------------------------------
138
+ buildEvent(error, options, source) {
139
+ const errorType = classifyError(error);
140
+ const message = error.message || String(error);
141
+ const normalized = normalizeMessage(message);
142
+ // Fingerprinting
143
+ const fp = options?.fingerprint ??
144
+ generateFingerprint(this.gitInfo.repoFullName ?? 'unknown', errorType, normalized);
145
+ // Sampling
146
+ if (!shouldSample(fp, this.config.sampleRate)) {
147
+ return null;
148
+ }
149
+ // Dedup
150
+ if (this.dedup.has(fp)) {
151
+ if (this.config.debug) {
152
+ console.log(`[errio] Deduplicated event: ${fp.slice(0, 12)}...`);
153
+ }
154
+ return null;
155
+ }
156
+ this.dedup.add(fp);
157
+ // Severity
158
+ const severity = options?.severity ?? defaultSeverity(source);
159
+ // Redact sensitive content
160
+ const safeMessage = redactString(message).slice(0, 2000);
161
+ const safeStack = error.stack ? redactString(error.stack).slice(0, 10000) : null;
162
+ // Context from AsyncLocalStorage
163
+ const ctx = getContext();
164
+ const breadcrumbs = getBreadcrumbs();
165
+ // Build the event
166
+ let event = {
167
+ source: 'api',
168
+ error_type: errorType,
169
+ error_message: safeMessage,
170
+ stack_trace: safeStack,
171
+ repo_full_name: this.gitInfo.repoFullName ?? 'unknown/unknown',
172
+ commit_sha: this.gitInfo.commitSha,
173
+ branch: this.gitInfo.branch,
174
+ file_paths: error.stack ? extractFilePaths(error.stack) : [],
175
+ severity,
176
+ raw_payload: {
177
+ name: error.name,
178
+ message: error.message,
179
+ stack: error.stack,
180
+ },
181
+ metadata: {
182
+ triggered_by: source,
183
+ environment: this.config.environment,
184
+ service_name: this.config.serviceName,
185
+ ...(options?.tags && { tags: options.tags }),
186
+ ...(options?.extra && { extra: options.extra }),
187
+ },
188
+ fingerprint: fp,
189
+ timestamp: Date.now(),
190
+ };
191
+ // Attach cause chain if present
192
+ if (error.cause) {
193
+ event.cause_chain = serializeCauseChain(error);
194
+ }
195
+ // Attach breadcrumbs
196
+ if (breadcrumbs.length > 0) {
197
+ event.breadcrumbs = breadcrumbs;
198
+ }
199
+ // Attach request context
200
+ if (ctx) {
201
+ event.context = ctx;
202
+ if (ctx.requestId) {
203
+ event.correlation_id = ctx.requestId;
204
+ }
205
+ }
206
+ // beforeSend hook — allows users to modify or drop events
207
+ if (this.config.beforeSend) {
208
+ const modified = this.config.beforeSend(event);
209
+ if (modified === null) {
210
+ if (this.config.debug) {
211
+ console.log('[errio] Event dropped by beforeSend hook.');
212
+ }
213
+ return null;
214
+ }
215
+ event = modified;
216
+ }
217
+ return event;
218
+ }
219
+ }
220
+ function clamp(value, min, max) {
221
+ return Math.max(min, Math.min(max, value));
222
+ }
223
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { RequestContext, Breadcrumb } from './types.js';
2
+ /**
3
+ * Run a function within a new async context scope.
4
+ * Context is automatically propagated through all async operations within fn.
5
+ */
6
+ export declare function runWithContext<T>(ctx: RequestContext, fn: () => T): T;
7
+ /**
8
+ * Get the current request context, or undefined if none is set.
9
+ */
10
+ export declare function getContext(): RequestContext | undefined;
11
+ /**
12
+ * Merge additional fields into the current request context.
13
+ * No-op if called outside a context scope.
14
+ */
15
+ export declare function setContext(ctx: Partial<RequestContext>): void;
16
+ /**
17
+ * Add a breadcrumb to the current context's ring buffer.
18
+ * Oldest entries are evicted when the buffer is full.
19
+ */
20
+ export declare function addBreadcrumb(crumb: Omit<Breadcrumb, 'timestamp'>): void;
21
+ /**
22
+ * Get a snapshot of the current breadcrumbs (oldest first).
23
+ */
24
+ export declare function getBreadcrumbs(): Breadcrumb[];
25
+ /**
26
+ * Clear all breadcrumbs in the current context.
27
+ */
28
+ export declare function clearBreadcrumbs(): void;
29
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgB7D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAKrE;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,cAAc,GAAG,SAAS,CAEvD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAK7D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI,CAexE;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,UAAU,EAAE,CAE7C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC"}
@@ -0,0 +1,60 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ const storage = new AsyncLocalStorage();
3
+ const MAX_BREADCRUMBS = 30;
4
+ /**
5
+ * Run a function within a new async context scope.
6
+ * Context is automatically propagated through all async operations within fn.
7
+ */
8
+ export function runWithContext(ctx, fn) {
9
+ return storage.run({ requestContext: { ...ctx }, breadcrumbs: [] }, fn);
10
+ }
11
+ /**
12
+ * Get the current request context, or undefined if none is set.
13
+ */
14
+ export function getContext() {
15
+ return storage.getStore()?.requestContext;
16
+ }
17
+ /**
18
+ * Merge additional fields into the current request context.
19
+ * No-op if called outside a context scope.
20
+ */
21
+ export function setContext(ctx) {
22
+ const store = storage.getStore();
23
+ if (store) {
24
+ Object.assign(store.requestContext, ctx);
25
+ }
26
+ }
27
+ /**
28
+ * Add a breadcrumb to the current context's ring buffer.
29
+ * Oldest entries are evicted when the buffer is full.
30
+ */
31
+ export function addBreadcrumb(crumb) {
32
+ const store = storage.getStore();
33
+ if (!store)
34
+ return;
35
+ const entry = {
36
+ ...crumb,
37
+ timestamp: Date.now(),
38
+ };
39
+ store.breadcrumbs.push(entry);
40
+ // Ring buffer: evict oldest when over limit
41
+ if (store.breadcrumbs.length > MAX_BREADCRUMBS) {
42
+ store.breadcrumbs.splice(0, store.breadcrumbs.length - MAX_BREADCRUMBS);
43
+ }
44
+ }
45
+ /**
46
+ * Get a snapshot of the current breadcrumbs (oldest first).
47
+ */
48
+ export function getBreadcrumbs() {
49
+ return storage.getStore()?.breadcrumbs.slice() ?? [];
50
+ }
51
+ /**
52
+ * Clear all breadcrumbs in the current context.
53
+ */
54
+ export function clearBreadcrumbs() {
55
+ const store = storage.getStore();
56
+ if (store) {
57
+ store.breadcrumbs.length = 0;
58
+ }
59
+ }
60
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAarD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAgB,CAAC;AAEtD,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAI,GAAmB,EAAE,EAAW;IAChE,OAAO,OAAO,CAAC,GAAG,CAChB,EAAE,cAAc,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,EAC/C,EAAE,CACH,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC,QAAQ,EAAE,EAAE,cAAc,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,GAA4B;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAoC;IAChE,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,MAAM,KAAK,GAAe;QACxB,GAAG,KAAK;QACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;IAEF,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAE9B,4CAA4C;IAC5C,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QAC/C,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,QAAQ,EAAE,EAAE,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IACjC,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { ResolvedConfig } from './types.js';
2
+ export interface DeployInfo {
3
+ /** Deployment version (e.g., "v1.2.3", "abc123") */
4
+ version?: string;
5
+ /** Git commit SHA for this deploy */
6
+ commitSha?: string;
7
+ /** Branch name */
8
+ branch?: string;
9
+ /** Environment name (e.g., "production", "staging") */
10
+ environment: string;
11
+ /** Who triggered the deploy */
12
+ deployedBy?: string;
13
+ /** When the deploy happened (ISO string or Date). Defaults to now. */
14
+ deployedAt?: string | Date;
15
+ /** Additional metadata */
16
+ metadata?: Record<string, unknown>;
17
+ }
18
+ /**
19
+ * Report a deployment event to the Errio API.
20
+ * This enables deploy correlation — linking errors to the deploy that introduced them.
21
+ *
22
+ * Usage:
23
+ * import { reportDeploy } from '@errio/core';
24
+ * await reportDeploy(config, { environment: 'production', version: 'v1.2.3' });
25
+ */
26
+ export declare function reportDeploy(config: ResolvedConfig, deploy: DeployInfo): Promise<{
27
+ deploy_id: string;
28
+ } | null>;
29
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA0CvC"}
package/dist/deploy.js ADDED
@@ -0,0 +1,50 @@
1
+ import { detectGitInfo } from './git.js';
2
+ /**
3
+ * Report a deployment event to the Errio API.
4
+ * This enables deploy correlation — linking errors to the deploy that introduced them.
5
+ *
6
+ * Usage:
7
+ * import { reportDeploy } from '@errio/core';
8
+ * await reportDeploy(config, { environment: 'production', version: 'v1.2.3' });
9
+ */
10
+ export async function reportDeploy(config, deploy) {
11
+ const git = detectGitInfo();
12
+ const payload = {
13
+ repo_full_name: git.repoFullName ?? 'unknown/unknown',
14
+ environment: deploy.environment,
15
+ version: deploy.version,
16
+ commit_sha: deploy.commitSha ?? git.commitSha,
17
+ branch: deploy.branch ?? git.branch,
18
+ deployed_by: deploy.deployedBy,
19
+ deployed_at: deploy.deployedAt
20
+ ? typeof deploy.deployedAt === 'string'
21
+ ? deploy.deployedAt
22
+ : deploy.deployedAt.toISOString()
23
+ : new Date().toISOString(),
24
+ metadata: deploy.metadata,
25
+ };
26
+ try {
27
+ const response = await fetch(`${config.endpoint}/api/v1/deploys`, {
28
+ method: 'POST',
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ 'Authorization': `Bearer ${config.apiKey}`,
32
+ },
33
+ body: JSON.stringify(payload),
34
+ });
35
+ if (!response.ok) {
36
+ if (config.debug) {
37
+ console.error(`[errio] Failed to report deploy: HTTP ${response.status}`);
38
+ }
39
+ return null;
40
+ }
41
+ return (await response.json());
42
+ }
43
+ catch (err) {
44
+ if (config.debug) {
45
+ console.error('[errio] Failed to report deploy:', err);
46
+ }
47
+ return null;
48
+ }
49
+ }
50
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../src/deploy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAmBzC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAsB,EACtB,MAAkB;IAElB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAE5B,MAAM,OAAO,GAAG;QACd,cAAc,EAAE,GAAG,CAAC,YAAY,IAAI,iBAAiB;QACrD,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS;QAC7C,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM;QACnC,WAAW,EAAE,MAAM,CAAC,UAAU;QAC9B,WAAW,EAAE,MAAM,CAAC,UAAU;YAC5B,CAAC,CAAC,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ;gBACrC,CAAC,CAAC,MAAM,CAAC,UAAU;gBACnB,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE;YACnC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,QAAQ,iBAAiB,EAAE;YAChE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;aAC3C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,OAAO,CAAC,KAAK,CAAC,yCAAyC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5E,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA0B,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Normalize an error message by stripping variable content.
3
+ * This improves dedup accuracy by removing noise like timestamps,
4
+ * line numbers, memory addresses, UUIDs, and temp paths.
5
+ */
6
+ export declare function normalizeMessage(message: string): string;
7
+ /**
8
+ * Generate a stable fingerprint for dedup and issue grouping.
9
+ *
10
+ * @param components - Strings to include in the fingerprint (e.g., errorType, normalizedMessage)
11
+ * @returns SHA-256 hex hash
12
+ */
13
+ export declare function generateFingerprint(...components: string[]): string;
14
+ /**
15
+ * In-memory dedup cache with TTL-based expiry.
16
+ * Prevents the same error from being sent multiple times within a short window.
17
+ */
18
+ export declare class DedupCache {
19
+ private cache;
20
+ private ttlMs;
21
+ constructor(ttlMs?: number);
22
+ /** Returns true if the fingerprint was recently seen (within TTL). */
23
+ has(fingerprint: string): boolean;
24
+ /** Record a fingerprint with the current timestamp. */
25
+ add(fingerprint: string): void;
26
+ /** Remove expired entries. */
27
+ cleanup(): void;
28
+ get size(): number;
29
+ }
30
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBxD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAGnE;AAED;;;GAGG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,KAAK,CAAS;gBAEV,KAAK,SAAgB;IAIjC,sEAAsE;IACtE,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAYjC,uDAAuD;IACvD,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAK9B,8BAA8B;IAC9B,OAAO,IAAI,IAAI;IASf,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}