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 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
@@ -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 };
@@ -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":"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","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
+ }