sitepong 0.0.1
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/README.md +155 -0
- package/dist/index.d.mts +64 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +225 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +214 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# SitePong SDK
|
|
2
|
+
|
|
3
|
+
Official SDK for [SitePong](https://sitepong.com) error tracking and monitoring.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install sitepong
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import sitepong from 'sitepong';
|
|
15
|
+
|
|
16
|
+
sitepong.init({
|
|
17
|
+
apiKey: 'your-api-key',
|
|
18
|
+
environment: 'production',
|
|
19
|
+
release: '1.0.0',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Errors are automatically captured!
|
|
23
|
+
// Or capture manually:
|
|
24
|
+
sitepong.captureError(new Error('Something went wrong'));
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configuration
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
sitepong.init({
|
|
31
|
+
apiKey: 'your-api-key', // Required
|
|
32
|
+
endpoint: 'https://ingest.sitepong.com', // Optional
|
|
33
|
+
environment: 'production', // Optional
|
|
34
|
+
release: '1.0.0', // Optional
|
|
35
|
+
autoCapture: true, // Auto-capture uncaught errors (default: true)
|
|
36
|
+
maxBatchSize: 10, // Batch size before flush (default: 10)
|
|
37
|
+
flushInterval: 5000, // Flush interval in ms (default: 5000)
|
|
38
|
+
debug: false, // Enable debug logging (default: false)
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API
|
|
43
|
+
|
|
44
|
+
### `init(config)`
|
|
45
|
+
Initialize the SDK with your configuration.
|
|
46
|
+
|
|
47
|
+
### `captureError(error, context?)`
|
|
48
|
+
Manually capture an error.
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
try {
|
|
52
|
+
riskyOperation();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
sitepong.captureError(error, {
|
|
55
|
+
tags: { component: 'checkout' },
|
|
56
|
+
extra: { orderId: '12345' },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### `captureMessage(message, level?, context?)`
|
|
62
|
+
Capture a message (info, warning, or error).
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
sitepong.captureMessage('User signed up', 'info', {
|
|
66
|
+
user: { id: 'user-123' },
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `setUser(user)`
|
|
71
|
+
Set user context for all subsequent errors.
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
sitepong.setUser({
|
|
75
|
+
id: 'user-123',
|
|
76
|
+
email: 'user@example.com',
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### `setTags(tags)`
|
|
81
|
+
Set tags for all subsequent errors.
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
sitepong.setTags({
|
|
85
|
+
version: '2.0.0',
|
|
86
|
+
region: 'us-east',
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `setContext(context)`
|
|
91
|
+
Set additional context.
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
sitepong.setContext({
|
|
95
|
+
extra: { sessionId: 'abc123' },
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `flush()`
|
|
100
|
+
Manually flush the error queue.
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
await sitepong.flush();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Framework Integration
|
|
107
|
+
|
|
108
|
+
### React
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
import sitepong from 'sitepong';
|
|
112
|
+
import { useEffect } from 'react';
|
|
113
|
+
|
|
114
|
+
function App() {
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
sitepong.init({
|
|
117
|
+
apiKey: process.env.REACT_APP_SITEPONG_KEY,
|
|
118
|
+
environment: process.env.NODE_ENV,
|
|
119
|
+
});
|
|
120
|
+
}, []);
|
|
121
|
+
|
|
122
|
+
return <YourApp />;
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Next.js
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
// pages/_app.js or app/layout.js
|
|
130
|
+
import sitepong from 'sitepong';
|
|
131
|
+
|
|
132
|
+
if (typeof window !== 'undefined') {
|
|
133
|
+
sitepong.init({
|
|
134
|
+
apiKey: process.env.NEXT_PUBLIC_SITEPONG_KEY,
|
|
135
|
+
environment: process.env.NODE_ENV,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Node.js
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
import sitepong from 'sitepong';
|
|
144
|
+
|
|
145
|
+
sitepong.init({
|
|
146
|
+
apiKey: process.env.SITEPONG_KEY,
|
|
147
|
+
environment: process.env.NODE_ENV,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Uncaught exceptions and unhandled rejections are automatically captured
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
interface SitePongConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
environment?: string;
|
|
5
|
+
release?: string;
|
|
6
|
+
autoCapture?: boolean;
|
|
7
|
+
maxBatchSize?: number;
|
|
8
|
+
flushInterval?: number;
|
|
9
|
+
debug?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface ErrorContext {
|
|
12
|
+
user?: {
|
|
13
|
+
id?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
};
|
|
17
|
+
tags?: Record<string, string>;
|
|
18
|
+
extra?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
interface CapturedError {
|
|
21
|
+
message: string;
|
|
22
|
+
stack?: string;
|
|
23
|
+
type: string;
|
|
24
|
+
timestamp: string;
|
|
25
|
+
url?: string;
|
|
26
|
+
userAgent?: string;
|
|
27
|
+
environment?: string;
|
|
28
|
+
release?: string;
|
|
29
|
+
context?: ErrorContext;
|
|
30
|
+
fingerprint?: string;
|
|
31
|
+
}
|
|
32
|
+
declare class SitePongClient {
|
|
33
|
+
private config;
|
|
34
|
+
private errorQueue;
|
|
35
|
+
private flushTimer;
|
|
36
|
+
private context;
|
|
37
|
+
private initialized;
|
|
38
|
+
constructor();
|
|
39
|
+
init(config: SitePongConfig): void;
|
|
40
|
+
setContext(context: ErrorContext): void;
|
|
41
|
+
setUser(user: ErrorContext['user']): void;
|
|
42
|
+
setTags(tags: Record<string, string>): void;
|
|
43
|
+
captureError(error: Error | string, additionalContext?: ErrorContext): void;
|
|
44
|
+
captureMessage(message: string, level?: 'info' | 'warning' | 'error', additionalContext?: ErrorContext): void;
|
|
45
|
+
flush(): Promise<void>;
|
|
46
|
+
private formatError;
|
|
47
|
+
private generateFingerprint;
|
|
48
|
+
private setupAutoCapture;
|
|
49
|
+
private startFlushTimer;
|
|
50
|
+
private flushWithBeacon;
|
|
51
|
+
private getUrl;
|
|
52
|
+
private getUserAgent;
|
|
53
|
+
private log;
|
|
54
|
+
}
|
|
55
|
+
declare const sitepong: SitePongClient;
|
|
56
|
+
declare const init: (config: SitePongConfig) => void;
|
|
57
|
+
declare const captureError: (error: Error | string, additionalContext?: ErrorContext) => void;
|
|
58
|
+
declare const captureMessage: (message: string, level?: "info" | "warning" | "error", additionalContext?: ErrorContext) => void;
|
|
59
|
+
declare const setContext: (context: ErrorContext) => void;
|
|
60
|
+
declare const setUser: (user: ErrorContext["user"]) => void;
|
|
61
|
+
declare const setTags: (tags: Record<string, string>) => void;
|
|
62
|
+
declare const flush: () => Promise<void>;
|
|
63
|
+
|
|
64
|
+
export { type CapturedError, type ErrorContext, type SitePongConfig, captureError, captureMessage, sitepong as default, flush, init, setContext, setTags, setUser };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
interface SitePongConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
environment?: string;
|
|
5
|
+
release?: string;
|
|
6
|
+
autoCapture?: boolean;
|
|
7
|
+
maxBatchSize?: number;
|
|
8
|
+
flushInterval?: number;
|
|
9
|
+
debug?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface ErrorContext {
|
|
12
|
+
user?: {
|
|
13
|
+
id?: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
};
|
|
17
|
+
tags?: Record<string, string>;
|
|
18
|
+
extra?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
interface CapturedError {
|
|
21
|
+
message: string;
|
|
22
|
+
stack?: string;
|
|
23
|
+
type: string;
|
|
24
|
+
timestamp: string;
|
|
25
|
+
url?: string;
|
|
26
|
+
userAgent?: string;
|
|
27
|
+
environment?: string;
|
|
28
|
+
release?: string;
|
|
29
|
+
context?: ErrorContext;
|
|
30
|
+
fingerprint?: string;
|
|
31
|
+
}
|
|
32
|
+
declare class SitePongClient {
|
|
33
|
+
private config;
|
|
34
|
+
private errorQueue;
|
|
35
|
+
private flushTimer;
|
|
36
|
+
private context;
|
|
37
|
+
private initialized;
|
|
38
|
+
constructor();
|
|
39
|
+
init(config: SitePongConfig): void;
|
|
40
|
+
setContext(context: ErrorContext): void;
|
|
41
|
+
setUser(user: ErrorContext['user']): void;
|
|
42
|
+
setTags(tags: Record<string, string>): void;
|
|
43
|
+
captureError(error: Error | string, additionalContext?: ErrorContext): void;
|
|
44
|
+
captureMessage(message: string, level?: 'info' | 'warning' | 'error', additionalContext?: ErrorContext): void;
|
|
45
|
+
flush(): Promise<void>;
|
|
46
|
+
private formatError;
|
|
47
|
+
private generateFingerprint;
|
|
48
|
+
private setupAutoCapture;
|
|
49
|
+
private startFlushTimer;
|
|
50
|
+
private flushWithBeacon;
|
|
51
|
+
private getUrl;
|
|
52
|
+
private getUserAgent;
|
|
53
|
+
private log;
|
|
54
|
+
}
|
|
55
|
+
declare const sitepong: SitePongClient;
|
|
56
|
+
declare const init: (config: SitePongConfig) => void;
|
|
57
|
+
declare const captureError: (error: Error | string, additionalContext?: ErrorContext) => void;
|
|
58
|
+
declare const captureMessage: (message: string, level?: "info" | "warning" | "error", additionalContext?: ErrorContext) => void;
|
|
59
|
+
declare const setContext: (context: ErrorContext) => void;
|
|
60
|
+
declare const setUser: (user: ErrorContext["user"]) => void;
|
|
61
|
+
declare const setTags: (tags: Record<string, string>) => void;
|
|
62
|
+
declare const flush: () => Promise<void>;
|
|
63
|
+
|
|
64
|
+
export { type CapturedError, type ErrorContext, type SitePongConfig, captureError, captureMessage, sitepong as default, flush, init, setContext, setTags, setUser };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var DEFAULT_ENDPOINT = "https://ingest.sitepong.com";
|
|
7
|
+
var DEFAULT_BATCH_SIZE = 10;
|
|
8
|
+
var DEFAULT_FLUSH_INTERVAL = 5e3;
|
|
9
|
+
var SitePongClient = class {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.errorQueue = [];
|
|
12
|
+
this.flushTimer = null;
|
|
13
|
+
this.context = {};
|
|
14
|
+
this.initialized = false;
|
|
15
|
+
this.config = {
|
|
16
|
+
apiKey: "",
|
|
17
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
18
|
+
environment: "production",
|
|
19
|
+
release: "",
|
|
20
|
+
autoCapture: true,
|
|
21
|
+
maxBatchSize: DEFAULT_BATCH_SIZE,
|
|
22
|
+
flushInterval: DEFAULT_FLUSH_INTERVAL,
|
|
23
|
+
debug: false
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
init(config) {
|
|
27
|
+
if (!config.apiKey) {
|
|
28
|
+
console.error("[SitePong] API key is required");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.config = {
|
|
32
|
+
...this.config,
|
|
33
|
+
...config
|
|
34
|
+
};
|
|
35
|
+
this.initialized = true;
|
|
36
|
+
if (this.config.autoCapture) {
|
|
37
|
+
this.setupAutoCapture();
|
|
38
|
+
}
|
|
39
|
+
this.startFlushTimer();
|
|
40
|
+
this.log("Initialized with endpoint:", this.config.endpoint);
|
|
41
|
+
}
|
|
42
|
+
setContext(context) {
|
|
43
|
+
this.context = { ...this.context, ...context };
|
|
44
|
+
}
|
|
45
|
+
setUser(user) {
|
|
46
|
+
this.context.user = user;
|
|
47
|
+
}
|
|
48
|
+
setTags(tags) {
|
|
49
|
+
this.context.tags = { ...this.context.tags, ...tags };
|
|
50
|
+
}
|
|
51
|
+
captureError(error, additionalContext) {
|
|
52
|
+
if (!this.initialized) {
|
|
53
|
+
console.warn("[SitePong] SDK not initialized. Call init() first.");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const capturedError = this.formatError(error, additionalContext);
|
|
57
|
+
this.errorQueue.push(capturedError);
|
|
58
|
+
this.log("Captured error:", capturedError.message);
|
|
59
|
+
if (this.errorQueue.length >= this.config.maxBatchSize) {
|
|
60
|
+
this.flush();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
captureMessage(message, level = "info", additionalContext) {
|
|
64
|
+
if (!this.initialized) {
|
|
65
|
+
console.warn("[SitePong] SDK not initialized. Call init() first.");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const capturedError = {
|
|
69
|
+
message,
|
|
70
|
+
type: level,
|
|
71
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
72
|
+
url: this.getUrl(),
|
|
73
|
+
userAgent: this.getUserAgent(),
|
|
74
|
+
environment: this.config.environment,
|
|
75
|
+
release: this.config.release,
|
|
76
|
+
context: { ...this.context, ...additionalContext }
|
|
77
|
+
};
|
|
78
|
+
this.errorQueue.push(capturedError);
|
|
79
|
+
this.log("Captured message:", message);
|
|
80
|
+
if (this.errorQueue.length >= this.config.maxBatchSize) {
|
|
81
|
+
this.flush();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async flush() {
|
|
85
|
+
if (this.errorQueue.length === 0) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const errors = [...this.errorQueue];
|
|
89
|
+
this.errorQueue = [];
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(`${this.config.endpoint}/api/errors/batch`, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: {
|
|
94
|
+
"Content-Type": "application/json",
|
|
95
|
+
"X-API-Key": this.config.apiKey
|
|
96
|
+
},
|
|
97
|
+
body: JSON.stringify({ errors })
|
|
98
|
+
});
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
throw new Error(`HTTP ${response.status}`);
|
|
101
|
+
}
|
|
102
|
+
this.log(`Flushed ${errors.length} errors`);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
this.errorQueue.unshift(...errors);
|
|
105
|
+
this.log("Failed to flush errors:", err);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
formatError(error, additionalContext) {
|
|
109
|
+
const isError = error instanceof Error;
|
|
110
|
+
const message = isError ? error.message : String(error);
|
|
111
|
+
const stack = isError ? error.stack : void 0;
|
|
112
|
+
const type = isError ? error.name : "Error";
|
|
113
|
+
return {
|
|
114
|
+
message,
|
|
115
|
+
stack,
|
|
116
|
+
type,
|
|
117
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
118
|
+
url: this.getUrl(),
|
|
119
|
+
userAgent: this.getUserAgent(),
|
|
120
|
+
environment: this.config.environment,
|
|
121
|
+
release: this.config.release,
|
|
122
|
+
context: { ...this.context, ...additionalContext },
|
|
123
|
+
fingerprint: this.generateFingerprint(message, stack)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
generateFingerprint(message, stack) {
|
|
127
|
+
const input = stack ? stack.split("\n").slice(0, 3).join("\n") : message;
|
|
128
|
+
let hash = 0;
|
|
129
|
+
for (let i = 0; i < input.length; i++) {
|
|
130
|
+
const char = input.charCodeAt(i);
|
|
131
|
+
hash = (hash << 5) - hash + char;
|
|
132
|
+
hash = hash & hash;
|
|
133
|
+
}
|
|
134
|
+
return Math.abs(hash).toString(16);
|
|
135
|
+
}
|
|
136
|
+
setupAutoCapture() {
|
|
137
|
+
if (typeof window !== "undefined") {
|
|
138
|
+
window.addEventListener("error", (event) => {
|
|
139
|
+
this.captureError(event.error || event.message);
|
|
140
|
+
});
|
|
141
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
142
|
+
const error = event.reason instanceof Error ? event.reason : new Error(String(event.reason));
|
|
143
|
+
this.captureError(error);
|
|
144
|
+
});
|
|
145
|
+
this.log("Auto-capture enabled for browser");
|
|
146
|
+
} else if (typeof process !== "undefined") {
|
|
147
|
+
process.on("uncaughtException", (error) => {
|
|
148
|
+
this.captureError(error);
|
|
149
|
+
this.flush().finally(() => process.exit(1));
|
|
150
|
+
});
|
|
151
|
+
process.on("unhandledRejection", (reason) => {
|
|
152
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
153
|
+
this.captureError(error);
|
|
154
|
+
});
|
|
155
|
+
this.log("Auto-capture enabled for Node.js");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
startFlushTimer() {
|
|
159
|
+
if (this.flushTimer) {
|
|
160
|
+
clearInterval(this.flushTimer);
|
|
161
|
+
}
|
|
162
|
+
this.flushTimer = setInterval(() => {
|
|
163
|
+
this.flush();
|
|
164
|
+
}, this.config.flushInterval);
|
|
165
|
+
if (typeof window !== "undefined") {
|
|
166
|
+
window.addEventListener("beforeunload", () => {
|
|
167
|
+
this.flush();
|
|
168
|
+
});
|
|
169
|
+
window.addEventListener("visibilitychange", () => {
|
|
170
|
+
if (document.visibilityState === "hidden") {
|
|
171
|
+
this.flushWithBeacon();
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
flushWithBeacon() {
|
|
177
|
+
if (this.errorQueue.length === 0 || typeof navigator?.sendBeacon !== "function") {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const errors = [...this.errorQueue];
|
|
181
|
+
this.errorQueue = [];
|
|
182
|
+
const blob = new Blob([JSON.stringify({ errors, apiKey: this.config.apiKey })], {
|
|
183
|
+
type: "application/json"
|
|
184
|
+
});
|
|
185
|
+
navigator.sendBeacon(`${this.config.endpoint}/api/errors/batch`, blob);
|
|
186
|
+
this.log(`Flushed ${errors.length} errors via beacon`);
|
|
187
|
+
}
|
|
188
|
+
getUrl() {
|
|
189
|
+
if (typeof window !== "undefined") {
|
|
190
|
+
return window.location.href;
|
|
191
|
+
}
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
getUserAgent() {
|
|
195
|
+
if (typeof navigator !== "undefined") {
|
|
196
|
+
return navigator.userAgent;
|
|
197
|
+
}
|
|
198
|
+
return void 0;
|
|
199
|
+
}
|
|
200
|
+
log(...args) {
|
|
201
|
+
if (this.config.debug) {
|
|
202
|
+
console.log("[SitePong]", ...args);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
var sitepong = new SitePongClient();
|
|
207
|
+
var init = sitepong.init.bind(sitepong);
|
|
208
|
+
var captureError = sitepong.captureError.bind(sitepong);
|
|
209
|
+
var captureMessage = sitepong.captureMessage.bind(sitepong);
|
|
210
|
+
var setContext = sitepong.setContext.bind(sitepong);
|
|
211
|
+
var setUser = sitepong.setUser.bind(sitepong);
|
|
212
|
+
var setTags = sitepong.setTags.bind(sitepong);
|
|
213
|
+
var flush = sitepong.flush.bind(sitepong);
|
|
214
|
+
var index_default = sitepong;
|
|
215
|
+
|
|
216
|
+
exports.captureError = captureError;
|
|
217
|
+
exports.captureMessage = captureMessage;
|
|
218
|
+
exports.default = index_default;
|
|
219
|
+
exports.flush = flush;
|
|
220
|
+
exports.init = init;
|
|
221
|
+
exports.setContext = setContext;
|
|
222
|
+
exports.setTags = setTags;
|
|
223
|
+
exports.setUser = setUser;
|
|
224
|
+
//# sourceMappingURL=index.js.map
|
|
225
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export interface SitePongConfig {\n apiKey: string;\n endpoint?: string;\n environment?: string;\n release?: string;\n autoCapture?: boolean;\n maxBatchSize?: number;\n flushInterval?: number;\n debug?: boolean;\n}\n\nexport interface ErrorContext {\n user?: {\n id?: string;\n email?: string;\n [key: string]: unknown;\n };\n tags?: Record<string, string>;\n extra?: Record<string, unknown>;\n}\n\nexport interface CapturedError {\n message: string;\n stack?: string;\n type: string;\n timestamp: string;\n url?: string;\n userAgent?: string;\n environment?: string;\n release?: string;\n context?: ErrorContext;\n fingerprint?: string;\n}\n\nconst DEFAULT_ENDPOINT = 'https://ingest.sitepong.com';\nconst DEFAULT_BATCH_SIZE = 10;\nconst DEFAULT_FLUSH_INTERVAL = 5000;\n\nclass SitePongClient {\n private config: Required<Omit<SitePongConfig, 'apiKey'>> & { apiKey: string };\n private errorQueue: CapturedError[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private context: ErrorContext = {};\n private initialized = false;\n\n constructor() {\n this.config = {\n apiKey: '',\n endpoint: DEFAULT_ENDPOINT,\n environment: 'production',\n release: '',\n autoCapture: true,\n maxBatchSize: DEFAULT_BATCH_SIZE,\n flushInterval: DEFAULT_FLUSH_INTERVAL,\n debug: false,\n };\n }\n\n init(config: SitePongConfig): void {\n if (!config.apiKey) {\n console.error('[SitePong] API key is required');\n return;\n }\n\n this.config = {\n ...this.config,\n ...config,\n };\n\n this.initialized = true;\n\n if (this.config.autoCapture) {\n this.setupAutoCapture();\n }\n\n this.startFlushTimer();\n this.log('Initialized with endpoint:', this.config.endpoint);\n }\n\n setContext(context: ErrorContext): void {\n this.context = { ...this.context, ...context };\n }\n\n setUser(user: ErrorContext['user']): void {\n this.context.user = user;\n }\n\n setTags(tags: Record<string, string>): void {\n this.context.tags = { ...this.context.tags, ...tags };\n }\n\n captureError(error: Error | string, additionalContext?: ErrorContext): void {\n if (!this.initialized) {\n console.warn('[SitePong] SDK not initialized. Call init() first.');\n return;\n }\n\n const capturedError = this.formatError(error, additionalContext);\n this.errorQueue.push(capturedError);\n this.log('Captured error:', capturedError.message);\n\n if (this.errorQueue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n captureMessage(message: string, level: 'info' | 'warning' | 'error' = 'info', additionalContext?: ErrorContext): void {\n if (!this.initialized) {\n console.warn('[SitePong] SDK not initialized. Call init() first.');\n return;\n }\n\n const capturedError: CapturedError = {\n message,\n type: level,\n timestamp: new Date().toISOString(),\n url: this.getUrl(),\n userAgent: this.getUserAgent(),\n environment: this.config.environment,\n release: this.config.release,\n context: { ...this.context, ...additionalContext },\n };\n\n this.errorQueue.push(capturedError);\n this.log('Captured message:', message);\n\n if (this.errorQueue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.errorQueue.length === 0) {\n return;\n }\n\n const errors = [...this.errorQueue];\n this.errorQueue = [];\n\n try {\n const response = await fetch(`${this.config.endpoint}/api/errors/batch`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n },\n body: JSON.stringify({ errors }),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n this.log(`Flushed ${errors.length} errors`);\n } catch (err) {\n // Re-queue errors on failure\n this.errorQueue.unshift(...errors);\n this.log('Failed to flush errors:', err);\n }\n }\n\n private formatError(error: Error | string, additionalContext?: ErrorContext): CapturedError {\n const isError = error instanceof Error;\n const message = isError ? error.message : String(error);\n const stack = isError ? error.stack : undefined;\n const type = isError ? error.name : 'Error';\n\n return {\n message,\n stack,\n type,\n timestamp: new Date().toISOString(),\n url: this.getUrl(),\n userAgent: this.getUserAgent(),\n environment: this.config.environment,\n release: this.config.release,\n context: { ...this.context, ...additionalContext },\n fingerprint: this.generateFingerprint(message, stack),\n };\n }\n\n private generateFingerprint(message: string, stack?: string): string {\n const input = stack\n ? stack.split('\\n').slice(0, 3).join('\\n')\n : message;\n \n let hash = 0;\n for (let i = 0; i < input.length; i++) {\n const char = input.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(16);\n }\n\n private setupAutoCapture(): void {\n if (typeof window !== 'undefined') {\n // Browser environment\n window.addEventListener('error', (event) => {\n this.captureError(event.error || event.message);\n });\n\n window.addEventListener('unhandledrejection', (event) => {\n const error = event.reason instanceof Error\n ? event.reason\n : new Error(String(event.reason));\n this.captureError(error);\n });\n\n this.log('Auto-capture enabled for browser');\n } else if (typeof process !== 'undefined') {\n // Node.js environment\n process.on('uncaughtException', (error) => {\n this.captureError(error);\n this.flush().finally(() => process.exit(1));\n });\n\n process.on('unhandledRejection', (reason) => {\n const error = reason instanceof Error\n ? reason\n : new Error(String(reason));\n this.captureError(error);\n });\n\n this.log('Auto-capture enabled for Node.js');\n }\n }\n\n private startFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n\n this.flushTimer = setInterval(() => {\n this.flush();\n }, this.config.flushInterval);\n\n // Flush on page unload in browser\n if (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => {\n this.flush();\n });\n\n // Use sendBeacon for more reliable delivery on unload\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n this.flushWithBeacon();\n }\n });\n }\n }\n\n private flushWithBeacon(): void {\n if (this.errorQueue.length === 0 || typeof navigator?.sendBeacon !== 'function') {\n return;\n }\n\n const errors = [...this.errorQueue];\n this.errorQueue = [];\n\n const blob = new Blob([JSON.stringify({ errors, apiKey: this.config.apiKey })], {\n type: 'application/json',\n });\n\n navigator.sendBeacon(`${this.config.endpoint}/api/errors/batch`, blob);\n this.log(`Flushed ${errors.length} errors via beacon`);\n }\n\n private getUrl(): string | undefined {\n if (typeof window !== 'undefined') {\n return window.location.href;\n }\n return undefined;\n }\n\n private getUserAgent(): string | undefined {\n if (typeof navigator !== 'undefined') {\n return navigator.userAgent;\n }\n return undefined;\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[SitePong]', ...args);\n }\n }\n}\n\n// Singleton instance\nconst sitepong = new SitePongClient();\n\n// Named exports\nexport const init = sitepong.init.bind(sitepong);\nexport const captureError = sitepong.captureError.bind(sitepong);\nexport const captureMessage = sitepong.captureMessage.bind(sitepong);\nexport const setContext = sitepong.setContext.bind(sitepong);\nexport const setUser = sitepong.setUser.bind(sitepong);\nexport const setTags = sitepong.setTags.bind(sitepong);\nexport const flush = sitepong.flush.bind(sitepong);\n\n// Default export\nexport default sitepong;\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var DEFAULT_ENDPOINT = "https://ingest.sitepong.com";
|
|
3
|
+
var DEFAULT_BATCH_SIZE = 10;
|
|
4
|
+
var DEFAULT_FLUSH_INTERVAL = 5e3;
|
|
5
|
+
var SitePongClient = class {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.errorQueue = [];
|
|
8
|
+
this.flushTimer = null;
|
|
9
|
+
this.context = {};
|
|
10
|
+
this.initialized = false;
|
|
11
|
+
this.config = {
|
|
12
|
+
apiKey: "",
|
|
13
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
14
|
+
environment: "production",
|
|
15
|
+
release: "",
|
|
16
|
+
autoCapture: true,
|
|
17
|
+
maxBatchSize: DEFAULT_BATCH_SIZE,
|
|
18
|
+
flushInterval: DEFAULT_FLUSH_INTERVAL,
|
|
19
|
+
debug: false
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
init(config) {
|
|
23
|
+
if (!config.apiKey) {
|
|
24
|
+
console.error("[SitePong] API key is required");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.config = {
|
|
28
|
+
...this.config,
|
|
29
|
+
...config
|
|
30
|
+
};
|
|
31
|
+
this.initialized = true;
|
|
32
|
+
if (this.config.autoCapture) {
|
|
33
|
+
this.setupAutoCapture();
|
|
34
|
+
}
|
|
35
|
+
this.startFlushTimer();
|
|
36
|
+
this.log("Initialized with endpoint:", this.config.endpoint);
|
|
37
|
+
}
|
|
38
|
+
setContext(context) {
|
|
39
|
+
this.context = { ...this.context, ...context };
|
|
40
|
+
}
|
|
41
|
+
setUser(user) {
|
|
42
|
+
this.context.user = user;
|
|
43
|
+
}
|
|
44
|
+
setTags(tags) {
|
|
45
|
+
this.context.tags = { ...this.context.tags, ...tags };
|
|
46
|
+
}
|
|
47
|
+
captureError(error, additionalContext) {
|
|
48
|
+
if (!this.initialized) {
|
|
49
|
+
console.warn("[SitePong] SDK not initialized. Call init() first.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const capturedError = this.formatError(error, additionalContext);
|
|
53
|
+
this.errorQueue.push(capturedError);
|
|
54
|
+
this.log("Captured error:", capturedError.message);
|
|
55
|
+
if (this.errorQueue.length >= this.config.maxBatchSize) {
|
|
56
|
+
this.flush();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
captureMessage(message, level = "info", additionalContext) {
|
|
60
|
+
if (!this.initialized) {
|
|
61
|
+
console.warn("[SitePong] SDK not initialized. Call init() first.");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const capturedError = {
|
|
65
|
+
message,
|
|
66
|
+
type: level,
|
|
67
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
68
|
+
url: this.getUrl(),
|
|
69
|
+
userAgent: this.getUserAgent(),
|
|
70
|
+
environment: this.config.environment,
|
|
71
|
+
release: this.config.release,
|
|
72
|
+
context: { ...this.context, ...additionalContext }
|
|
73
|
+
};
|
|
74
|
+
this.errorQueue.push(capturedError);
|
|
75
|
+
this.log("Captured message:", message);
|
|
76
|
+
if (this.errorQueue.length >= this.config.maxBatchSize) {
|
|
77
|
+
this.flush();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async flush() {
|
|
81
|
+
if (this.errorQueue.length === 0) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const errors = [...this.errorQueue];
|
|
85
|
+
this.errorQueue = [];
|
|
86
|
+
try {
|
|
87
|
+
const response = await fetch(`${this.config.endpoint}/api/errors/batch`, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "application/json",
|
|
91
|
+
"X-API-Key": this.config.apiKey
|
|
92
|
+
},
|
|
93
|
+
body: JSON.stringify({ errors })
|
|
94
|
+
});
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
throw new Error(`HTTP ${response.status}`);
|
|
97
|
+
}
|
|
98
|
+
this.log(`Flushed ${errors.length} errors`);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
this.errorQueue.unshift(...errors);
|
|
101
|
+
this.log("Failed to flush errors:", err);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
formatError(error, additionalContext) {
|
|
105
|
+
const isError = error instanceof Error;
|
|
106
|
+
const message = isError ? error.message : String(error);
|
|
107
|
+
const stack = isError ? error.stack : void 0;
|
|
108
|
+
const type = isError ? error.name : "Error";
|
|
109
|
+
return {
|
|
110
|
+
message,
|
|
111
|
+
stack,
|
|
112
|
+
type,
|
|
113
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
114
|
+
url: this.getUrl(),
|
|
115
|
+
userAgent: this.getUserAgent(),
|
|
116
|
+
environment: this.config.environment,
|
|
117
|
+
release: this.config.release,
|
|
118
|
+
context: { ...this.context, ...additionalContext },
|
|
119
|
+
fingerprint: this.generateFingerprint(message, stack)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
generateFingerprint(message, stack) {
|
|
123
|
+
const input = stack ? stack.split("\n").slice(0, 3).join("\n") : message;
|
|
124
|
+
let hash = 0;
|
|
125
|
+
for (let i = 0; i < input.length; i++) {
|
|
126
|
+
const char = input.charCodeAt(i);
|
|
127
|
+
hash = (hash << 5) - hash + char;
|
|
128
|
+
hash = hash & hash;
|
|
129
|
+
}
|
|
130
|
+
return Math.abs(hash).toString(16);
|
|
131
|
+
}
|
|
132
|
+
setupAutoCapture() {
|
|
133
|
+
if (typeof window !== "undefined") {
|
|
134
|
+
window.addEventListener("error", (event) => {
|
|
135
|
+
this.captureError(event.error || event.message);
|
|
136
|
+
});
|
|
137
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
138
|
+
const error = event.reason instanceof Error ? event.reason : new Error(String(event.reason));
|
|
139
|
+
this.captureError(error);
|
|
140
|
+
});
|
|
141
|
+
this.log("Auto-capture enabled for browser");
|
|
142
|
+
} else if (typeof process !== "undefined") {
|
|
143
|
+
process.on("uncaughtException", (error) => {
|
|
144
|
+
this.captureError(error);
|
|
145
|
+
this.flush().finally(() => process.exit(1));
|
|
146
|
+
});
|
|
147
|
+
process.on("unhandledRejection", (reason) => {
|
|
148
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
149
|
+
this.captureError(error);
|
|
150
|
+
});
|
|
151
|
+
this.log("Auto-capture enabled for Node.js");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
startFlushTimer() {
|
|
155
|
+
if (this.flushTimer) {
|
|
156
|
+
clearInterval(this.flushTimer);
|
|
157
|
+
}
|
|
158
|
+
this.flushTimer = setInterval(() => {
|
|
159
|
+
this.flush();
|
|
160
|
+
}, this.config.flushInterval);
|
|
161
|
+
if (typeof window !== "undefined") {
|
|
162
|
+
window.addEventListener("beforeunload", () => {
|
|
163
|
+
this.flush();
|
|
164
|
+
});
|
|
165
|
+
window.addEventListener("visibilitychange", () => {
|
|
166
|
+
if (document.visibilityState === "hidden") {
|
|
167
|
+
this.flushWithBeacon();
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
flushWithBeacon() {
|
|
173
|
+
if (this.errorQueue.length === 0 || typeof navigator?.sendBeacon !== "function") {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const errors = [...this.errorQueue];
|
|
177
|
+
this.errorQueue = [];
|
|
178
|
+
const blob = new Blob([JSON.stringify({ errors, apiKey: this.config.apiKey })], {
|
|
179
|
+
type: "application/json"
|
|
180
|
+
});
|
|
181
|
+
navigator.sendBeacon(`${this.config.endpoint}/api/errors/batch`, blob);
|
|
182
|
+
this.log(`Flushed ${errors.length} errors via beacon`);
|
|
183
|
+
}
|
|
184
|
+
getUrl() {
|
|
185
|
+
if (typeof window !== "undefined") {
|
|
186
|
+
return window.location.href;
|
|
187
|
+
}
|
|
188
|
+
return void 0;
|
|
189
|
+
}
|
|
190
|
+
getUserAgent() {
|
|
191
|
+
if (typeof navigator !== "undefined") {
|
|
192
|
+
return navigator.userAgent;
|
|
193
|
+
}
|
|
194
|
+
return void 0;
|
|
195
|
+
}
|
|
196
|
+
log(...args) {
|
|
197
|
+
if (this.config.debug) {
|
|
198
|
+
console.log("[SitePong]", ...args);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
var sitepong = new SitePongClient();
|
|
203
|
+
var init = sitepong.init.bind(sitepong);
|
|
204
|
+
var captureError = sitepong.captureError.bind(sitepong);
|
|
205
|
+
var captureMessage = sitepong.captureMessage.bind(sitepong);
|
|
206
|
+
var setContext = sitepong.setContext.bind(sitepong);
|
|
207
|
+
var setUser = sitepong.setUser.bind(sitepong);
|
|
208
|
+
var setTags = sitepong.setTags.bind(sitepong);
|
|
209
|
+
var flush = sitepong.flush.bind(sitepong);
|
|
210
|
+
var index_default = sitepong;
|
|
211
|
+
|
|
212
|
+
export { captureError, captureMessage, index_default as default, flush, init, setContext, setTags, setUser };
|
|
213
|
+
//# sourceMappingURL=index.mjs.map
|
|
214
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";AAkCA,IAAM,gBAAA,GAAmB,6BAAA;AACzB,IAAM,kBAAA,GAAqB,EAAA;AAC3B,IAAM,sBAAA,GAAyB,GAAA;AAE/B,IAAM,iBAAN,MAAqB;AAAA,EAOnB,WAAA,GAAc;AALd,IAAA,IAAA,CAAQ,aAA8B,EAAC;AACvC,IAAA,IAAA,CAAQ,UAAA,GAAmD,IAAA;AAC3D,IAAA,IAAA,CAAQ,UAAwB,EAAC;AACjC,IAAA,IAAA,CAAQ,WAAA,GAAc,KAAA;AAGpB,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,MAAA,EAAQ,EAAA;AAAA,MACR,QAAA,EAAU,gBAAA;AAAA,MACV,WAAA,EAAa,YAAA;AAAA,MACb,OAAA,EAAS,EAAA;AAAA,MACT,WAAA,EAAa,IAAA;AAAA,MACb,YAAA,EAAc,kBAAA;AAAA,MACd,aAAA,EAAe,sBAAA;AAAA,MACf,KAAA,EAAO;AAAA,KACT;AAAA,EACF;AAAA,EAEA,KAAK,MAAA,EAA8B;AACjC,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,OAAA,CAAQ,MAAM,gCAAgC,CAAA;AAC9C,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,GAAG,IAAA,CAAK,MAAA;AAAA,MACR,GAAG;AAAA,KACL;AAEA,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAEnB,IAAA,IAAI,IAAA,CAAK,OAAO,WAAA,EAAa;AAC3B,MAAA,IAAA,CAAK,gBAAA,EAAiB;AAAA,IACxB;AAEA,IAAA,IAAA,CAAK,eAAA,EAAgB;AACrB,IAAA,IAAA,CAAK,GAAA,CAAI,4BAAA,EAA8B,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA;AAAA,EAC7D;AAAA,EAEA,WAAW,OAAA,EAA6B;AACtC,IAAA,IAAA,CAAK,UAAU,EAAE,GAAG,IAAA,CAAK,OAAA,EAAS,GAAG,OAAA,EAAQ;AAAA,EAC/C;AAAA,EAEA,QAAQ,IAAA,EAAkC;AACxC,IAAA,IAAA,CAAK,QAAQ,IAAA,GAAO,IAAA;AAAA,EACtB;AAAA,EAEA,QAAQ,IAAA,EAAoC;AAC1C,IAAA,IAAA,CAAK,OAAA,CAAQ,OAAO,EAAE,GAAG,KAAK,OAAA,CAAQ,IAAA,EAAM,GAAG,IAAA,EAAK;AAAA,EACtD;AAAA,EAEA,YAAA,CAAa,OAAuB,iBAAA,EAAwC;AAC1E,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACrB,MAAA,OAAA,CAAQ,KAAK,oDAAoD,CAAA;AACjE,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,WAAA,CAAY,KAAA,EAAO,iBAAiB,CAAA;AAC/D,IAAA,IAAA,CAAK,UAAA,CAAW,KAAK,aAAa,CAAA;AAClC,IAAA,IAAA,CAAK,GAAA,CAAI,iBAAA,EAAmB,aAAA,CAAc,OAAO,CAAA;AAEjD,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,MAAA,IAAU,IAAA,CAAK,OAAO,YAAA,EAAc;AACtD,MAAA,IAAA,CAAK,KAAA,EAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,cAAA,CAAe,OAAA,EAAiB,KAAA,GAAsC,MAAA,EAAQ,iBAAA,EAAwC;AACpH,IAAA,IAAI,CAAC,KAAK,WAAA,EAAa;AACrB,MAAA,OAAA,CAAQ,KAAK,oDAAoD,CAAA;AACjE,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAA+B;AAAA,MACnC,OAAA;AAAA,MACA,IAAA,EAAM,KAAA;AAAA,MACN,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,GAAA,EAAK,KAAK,MAAA,EAAO;AAAA,MACjB,SAAA,EAAW,KAAK,YAAA,EAAa;AAAA,MAC7B,WAAA,EAAa,KAAK,MAAA,CAAO,WAAA;AAAA,MACzB,OAAA,EAAS,KAAK,MAAA,CAAO,OAAA;AAAA,MACrB,SAAS,EAAE,GAAG,IAAA,CAAK,OAAA,EAAS,GAAG,iBAAA;AAAkB,KACnD;AAEA,IAAA,IAAA,CAAK,UAAA,CAAW,KAAK,aAAa,CAAA;AAClC,IAAA,IAAA,CAAK,GAAA,CAAI,qBAAqB,OAAO,CAAA;AAErC,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,MAAA,IAAU,IAAA,CAAK,OAAO,YAAA,EAAc;AACtD,MAAA,IAAA,CAAK,KAAA,EAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,MAAA,KAAW,CAAA,EAAG;AAChC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,CAAC,GAAG,IAAA,CAAK,UAAU,CAAA;AAClC,IAAA,IAAA,CAAK,aAAa,EAAC;AAEnB,IAAA,IAAI;AACF,MAAA,MAAM,WAAW,MAAM,KAAA,CAAM,GAAG,IAAA,CAAK,MAAA,CAAO,QAAQ,CAAA,iBAAA,CAAA,EAAqB;AAAA,QACvE,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB,kBAAA;AAAA,UAChB,WAAA,EAAa,KAAK,MAAA,CAAO;AAAA,SAC3B;AAAA,QACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,QAAQ;AAAA,OAChC,CAAA;AAED,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,MAC3C;AAEA,MAAA,IAAA,CAAK,GAAA,CAAI,CAAA,QAAA,EAAW,MAAA,CAAO,MAAM,CAAA,OAAA,CAAS,CAAA;AAAA,IAC5C,SAAS,GAAA,EAAK;AAEZ,MAAA,IAAA,CAAK,UAAA,CAAW,OAAA,CAAQ,GAAG,MAAM,CAAA;AACjC,MAAA,IAAA,CAAK,GAAA,CAAI,2BAA2B,GAAG,CAAA;AAAA,IACzC;AAAA,EACF;AAAA,EAEQ,WAAA,CAAY,OAAuB,iBAAA,EAAiD;AAC1F,IAAA,MAAM,UAAU,KAAA,YAAiB,KAAA;AACjC,IAAA,MAAM,OAAA,GAAU,OAAA,GAAU,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACtD,IAAA,MAAM,KAAA,GAAQ,OAAA,GAAU,KAAA,CAAM,KAAA,GAAQ,MAAA;AACtC,IAAA,MAAM,IAAA,GAAO,OAAA,GAAU,KAAA,CAAM,IAAA,GAAO,OAAA;AAEpC,IAAA,OAAO;AAAA,MACL,OAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,MAClC,GAAA,EAAK,KAAK,MAAA,EAAO;AAAA,MACjB,SAAA,EAAW,KAAK,YAAA,EAAa;AAAA,MAC7B,WAAA,EAAa,KAAK,MAAA,CAAO,WAAA;AAAA,MACzB,OAAA,EAAS,KAAK,MAAA,CAAO,OAAA;AAAA,MACrB,SAAS,EAAE,GAAG,IAAA,CAAK,OAAA,EAAS,GAAG,iBAAA,EAAkB;AAAA,MACjD,WAAA,EAAa,IAAA,CAAK,mBAAA,CAAoB,OAAA,EAAS,KAAK;AAAA,KACtD;AAAA,EACF;AAAA,EAEQ,mBAAA,CAAoB,SAAiB,KAAA,EAAwB;AACnE,IAAA,MAAM,KAAA,GAAQ,KAAA,GACV,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,GACvC,OAAA;AAEJ,IAAA,IAAI,IAAA,GAAO,CAAA;AACX,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,MAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,CAAW,CAAC,CAAA;AAC/B,MAAA,IAAA,GAAA,CAAS,IAAA,IAAQ,KAAK,IAAA,GAAQ,IAAA;AAC9B,MAAA,IAAA,GAAO,IAAA,GAAO,IAAA;AAAA,IAChB;AACA,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,CAAE,SAAS,EAAE,CAAA;AAAA,EACnC;AAAA,EAEQ,gBAAA,GAAyB;AAC/B,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAEjC,MAAA,MAAA,CAAO,gBAAA,CAAiB,OAAA,EAAS,CAAC,KAAA,KAAU;AAC1C,QAAA,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM,KAAA,IAAS,KAAA,CAAM,OAAO,CAAA;AAAA,MAChD,CAAC,CAAA;AAED,MAAA,MAAA,CAAO,gBAAA,CAAiB,oBAAA,EAAsB,CAAC,KAAA,KAAU;AACvD,QAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,YAAkB,KAAA,GAClC,KAAA,CAAM,MAAA,GACN,IAAI,KAAA,CAAM,MAAA,CAAO,KAAA,CAAM,MAAM,CAAC,CAAA;AAClC,QAAA,IAAA,CAAK,aAAa,KAAK,CAAA;AAAA,MACzB,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,IAAI,kCAAkC,CAAA;AAAA,IAC7C,CAAA,MAAA,IAAW,OAAO,OAAA,KAAY,WAAA,EAAa;AAEzC,MAAA,OAAA,CAAQ,EAAA,CAAG,mBAAA,EAAqB,CAAC,KAAA,KAAU;AACzC,QAAA,IAAA,CAAK,aAAa,KAAK,CAAA;AACvB,QAAA,IAAA,CAAK,OAAM,CAAE,OAAA,CAAQ,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA,MAC5C,CAAC,CAAA;AAED,MAAA,OAAA,CAAQ,EAAA,CAAG,oBAAA,EAAsB,CAAC,MAAA,KAAW;AAC3C,QAAA,MAAM,KAAA,GAAQ,kBAAkB,KAAA,GAC5B,MAAA,GACA,IAAI,KAAA,CAAM,MAAA,CAAO,MAAM,CAAC,CAAA;AAC5B,QAAA,IAAA,CAAK,aAAa,KAAK,CAAA;AAAA,MACzB,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,IAAI,kCAAkC,CAAA;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,eAAA,GAAwB;AAC9B,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,aAAA,CAAc,KAAK,UAAU,CAAA;AAAA,IAC/B;AAEA,IAAA,IAAA,CAAK,UAAA,GAAa,YAAY,MAAM;AAClC,MAAA,IAAA,CAAK,KAAA,EAAM;AAAA,IACb,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,aAAa,CAAA;AAG5B,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,MAAA,CAAO,gBAAA,CAAiB,gBAAgB,MAAM;AAC5C,QAAA,IAAA,CAAK,KAAA,EAAM;AAAA,MACb,CAAC,CAAA;AAGD,MAAA,MAAA,CAAO,gBAAA,CAAiB,oBAAoB,MAAM;AAChD,QAAA,IAAI,QAAA,CAAS,oBAAoB,QAAA,EAAU;AACzC,UAAA,IAAA,CAAK,eAAA,EAAgB;AAAA,QACvB;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,eAAA,GAAwB;AAC9B,IAAA,IAAI,KAAK,UAAA,CAAW,MAAA,KAAW,KAAK,OAAO,SAAA,EAAW,eAAe,UAAA,EAAY;AAC/E,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,CAAC,GAAG,IAAA,CAAK,UAAU,CAAA;AAClC,IAAA,IAAA,CAAK,aAAa,EAAC;AAEnB,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,KAAK,SAAA,CAAU,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,CAAC,CAAA,EAAG;AAAA,MAC9E,IAAA,EAAM;AAAA,KACP,CAAA;AAED,IAAA,SAAA,CAAU,WAAW,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,QAAQ,qBAAqB,IAAI,CAAA;AACrE,IAAA,IAAA,CAAK,GAAA,CAAI,CAAA,QAAA,EAAW,MAAA,CAAO,MAAM,CAAA,kBAAA,CAAoB,CAAA;AAAA,EACvD;AAAA,EAEQ,MAAA,GAA6B;AACnC,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,MAAA,OAAO,OAAO,QAAA,CAAS,IAAA;AAAA,IACzB;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEQ,YAAA,GAAmC;AACzC,IAAA,IAAI,OAAO,cAAc,WAAA,EAAa;AACpC,MAAA,OAAO,SAAA,CAAU,SAAA;AAAA,IACnB;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEQ,OAAO,IAAA,EAAuB;AACpC,IAAA,IAAI,IAAA,CAAK,OAAO,KAAA,EAAO;AACrB,MAAA,OAAA,CAAQ,GAAA,CAAI,YAAA,EAAc,GAAG,IAAI,CAAA;AAAA,IACnC;AAAA,EACF;AACF,CAAA;AAGA,IAAM,QAAA,GAAW,IAAI,cAAA,EAAe;AAG7B,IAAM,IAAA,GAAO,QAAA,CAAS,IAAA,CAAK,IAAA,CAAK,QAAQ;AACxC,IAAM,YAAA,GAAe,QAAA,CAAS,YAAA,CAAa,IAAA,CAAK,QAAQ;AACxD,IAAM,cAAA,GAAiB,QAAA,CAAS,cAAA,CAAe,IAAA,CAAK,QAAQ;AAC5D,IAAM,UAAA,GAAa,QAAA,CAAS,UAAA,CAAW,IAAA,CAAK,QAAQ;AACpD,IAAM,OAAA,GAAU,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,QAAQ;AAC9C,IAAM,OAAA,GAAU,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,QAAQ;AAC9C,IAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,IAAA,CAAK,QAAQ;AAGjD,IAAO,aAAA,GAAQ","file":"index.mjs","sourcesContent":["export interface SitePongConfig {\n apiKey: string;\n endpoint?: string;\n environment?: string;\n release?: string;\n autoCapture?: boolean;\n maxBatchSize?: number;\n flushInterval?: number;\n debug?: boolean;\n}\n\nexport interface ErrorContext {\n user?: {\n id?: string;\n email?: string;\n [key: string]: unknown;\n };\n tags?: Record<string, string>;\n extra?: Record<string, unknown>;\n}\n\nexport interface CapturedError {\n message: string;\n stack?: string;\n type: string;\n timestamp: string;\n url?: string;\n userAgent?: string;\n environment?: string;\n release?: string;\n context?: ErrorContext;\n fingerprint?: string;\n}\n\nconst DEFAULT_ENDPOINT = 'https://ingest.sitepong.com';\nconst DEFAULT_BATCH_SIZE = 10;\nconst DEFAULT_FLUSH_INTERVAL = 5000;\n\nclass SitePongClient {\n private config: Required<Omit<SitePongConfig, 'apiKey'>> & { apiKey: string };\n private errorQueue: CapturedError[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private context: ErrorContext = {};\n private initialized = false;\n\n constructor() {\n this.config = {\n apiKey: '',\n endpoint: DEFAULT_ENDPOINT,\n environment: 'production',\n release: '',\n autoCapture: true,\n maxBatchSize: DEFAULT_BATCH_SIZE,\n flushInterval: DEFAULT_FLUSH_INTERVAL,\n debug: false,\n };\n }\n\n init(config: SitePongConfig): void {\n if (!config.apiKey) {\n console.error('[SitePong] API key is required');\n return;\n }\n\n this.config = {\n ...this.config,\n ...config,\n };\n\n this.initialized = true;\n\n if (this.config.autoCapture) {\n this.setupAutoCapture();\n }\n\n this.startFlushTimer();\n this.log('Initialized with endpoint:', this.config.endpoint);\n }\n\n setContext(context: ErrorContext): void {\n this.context = { ...this.context, ...context };\n }\n\n setUser(user: ErrorContext['user']): void {\n this.context.user = user;\n }\n\n setTags(tags: Record<string, string>): void {\n this.context.tags = { ...this.context.tags, ...tags };\n }\n\n captureError(error: Error | string, additionalContext?: ErrorContext): void {\n if (!this.initialized) {\n console.warn('[SitePong] SDK not initialized. Call init() first.');\n return;\n }\n\n const capturedError = this.formatError(error, additionalContext);\n this.errorQueue.push(capturedError);\n this.log('Captured error:', capturedError.message);\n\n if (this.errorQueue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n captureMessage(message: string, level: 'info' | 'warning' | 'error' = 'info', additionalContext?: ErrorContext): void {\n if (!this.initialized) {\n console.warn('[SitePong] SDK not initialized. Call init() first.');\n return;\n }\n\n const capturedError: CapturedError = {\n message,\n type: level,\n timestamp: new Date().toISOString(),\n url: this.getUrl(),\n userAgent: this.getUserAgent(),\n environment: this.config.environment,\n release: this.config.release,\n context: { ...this.context, ...additionalContext },\n };\n\n this.errorQueue.push(capturedError);\n this.log('Captured message:', message);\n\n if (this.errorQueue.length >= this.config.maxBatchSize) {\n this.flush();\n }\n }\n\n async flush(): Promise<void> {\n if (this.errorQueue.length === 0) {\n return;\n }\n\n const errors = [...this.errorQueue];\n this.errorQueue = [];\n\n try {\n const response = await fetch(`${this.config.endpoint}/api/errors/batch`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.config.apiKey,\n },\n body: JSON.stringify({ errors }),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}`);\n }\n\n this.log(`Flushed ${errors.length} errors`);\n } catch (err) {\n // Re-queue errors on failure\n this.errorQueue.unshift(...errors);\n this.log('Failed to flush errors:', err);\n }\n }\n\n private formatError(error: Error | string, additionalContext?: ErrorContext): CapturedError {\n const isError = error instanceof Error;\n const message = isError ? error.message : String(error);\n const stack = isError ? error.stack : undefined;\n const type = isError ? error.name : 'Error';\n\n return {\n message,\n stack,\n type,\n timestamp: new Date().toISOString(),\n url: this.getUrl(),\n userAgent: this.getUserAgent(),\n environment: this.config.environment,\n release: this.config.release,\n context: { ...this.context, ...additionalContext },\n fingerprint: this.generateFingerprint(message, stack),\n };\n }\n\n private generateFingerprint(message: string, stack?: string): string {\n const input = stack\n ? stack.split('\\n').slice(0, 3).join('\\n')\n : message;\n \n let hash = 0;\n for (let i = 0; i < input.length; i++) {\n const char = input.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(16);\n }\n\n private setupAutoCapture(): void {\n if (typeof window !== 'undefined') {\n // Browser environment\n window.addEventListener('error', (event) => {\n this.captureError(event.error || event.message);\n });\n\n window.addEventListener('unhandledrejection', (event) => {\n const error = event.reason instanceof Error\n ? event.reason\n : new Error(String(event.reason));\n this.captureError(error);\n });\n\n this.log('Auto-capture enabled for browser');\n } else if (typeof process !== 'undefined') {\n // Node.js environment\n process.on('uncaughtException', (error) => {\n this.captureError(error);\n this.flush().finally(() => process.exit(1));\n });\n\n process.on('unhandledRejection', (reason) => {\n const error = reason instanceof Error\n ? reason\n : new Error(String(reason));\n this.captureError(error);\n });\n\n this.log('Auto-capture enabled for Node.js');\n }\n }\n\n private startFlushTimer(): void {\n if (this.flushTimer) {\n clearInterval(this.flushTimer);\n }\n\n this.flushTimer = setInterval(() => {\n this.flush();\n }, this.config.flushInterval);\n\n // Flush on page unload in browser\n if (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => {\n this.flush();\n });\n\n // Use sendBeacon for more reliable delivery on unload\n window.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n this.flushWithBeacon();\n }\n });\n }\n }\n\n private flushWithBeacon(): void {\n if (this.errorQueue.length === 0 || typeof navigator?.sendBeacon !== 'function') {\n return;\n }\n\n const errors = [...this.errorQueue];\n this.errorQueue = [];\n\n const blob = new Blob([JSON.stringify({ errors, apiKey: this.config.apiKey })], {\n type: 'application/json',\n });\n\n navigator.sendBeacon(`${this.config.endpoint}/api/errors/batch`, blob);\n this.log(`Flushed ${errors.length} errors via beacon`);\n }\n\n private getUrl(): string | undefined {\n if (typeof window !== 'undefined') {\n return window.location.href;\n }\n return undefined;\n }\n\n private getUserAgent(): string | undefined {\n if (typeof navigator !== 'undefined') {\n return navigator.userAgent;\n }\n return undefined;\n }\n\n private log(...args: unknown[]): void {\n if (this.config.debug) {\n console.log('[SitePong]', ...args);\n }\n }\n}\n\n// Singleton instance\nconst sitepong = new SitePongClient();\n\n// Named exports\nexport const init = sitepong.init.bind(sitepong);\nexport const captureError = sitepong.captureError.bind(sitepong);\nexport const captureMessage = sitepong.captureMessage.bind(sitepong);\nexport const setContext = sitepong.setContext.bind(sitepong);\nexport const setUser = sitepong.setUser.bind(sitepong);\nexport const setTags = sitepong.setTags.bind(sitepong);\nexport const flush = sitepong.flush.bind(sitepong);\n\n// Default export\nexport default sitepong;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sitepong",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Official SitePong SDK for error tracking and monitoring",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
20
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
21
|
+
"lint": "eslint src/",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"error-tracking",
|
|
28
|
+
"monitoring",
|
|
29
|
+
"sitepong",
|
|
30
|
+
"error-reporting",
|
|
31
|
+
"crash-reporting"
|
|
32
|
+
],
|
|
33
|
+
"author": "SitePong",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/programmrz/sitepong.git",
|
|
38
|
+
"directory": "packages/sdk"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://sitepong.com",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/programmrz/sitepong/issues"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.10.0",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
47
|
+
"@typescript-eslint/parser": "^6.13.0",
|
|
48
|
+
"eslint": "^8.55.0",
|
|
49
|
+
"tsup": "^8.0.1",
|
|
50
|
+
"typescript": "^5.3.0",
|
|
51
|
+
"vitest": "^1.0.0"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=16.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|