@clienwork/errors 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.
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @clienwork/errors
2
+
3
+ Clienwork 에러 수집 SDK
4
+
5
+ ## 설치
6
+
7
+ ```bash
8
+ npm install @clienwork/errors
9
+ # or
10
+ yarn add @clienwork/errors
11
+ # or
12
+ pnpm add @clienwork/errors
13
+ ```
14
+
15
+ ## 프론트엔드 사용법
16
+
17
+ ### 초기화
18
+
19
+ ```typescript
20
+ import { init } from '@clienwork/errors'
21
+
22
+ init({
23
+ apiToken: 'clw_err_xxx', // 프로젝트 설정에서 발급받은 토큰
24
+ source: 'frontend', // 기본값
25
+ })
26
+ ```
27
+
28
+ ### 수동 에러 리포트
29
+
30
+ ```typescript
31
+ import { report } from '@clienwork/errors'
32
+
33
+ try {
34
+ // 위험한 작업
35
+ } catch (error) {
36
+ report(error, { context: 'checkout' })
37
+ }
38
+ ```
39
+
40
+ ### 사용자 식별
41
+
42
+ ```typescript
43
+ import { setUser, clearUser } from '@clienwork/errors'
44
+
45
+ // 로그인 시
46
+ setUser('user-123')
47
+
48
+ // 로그아웃 시
49
+ clearUser()
50
+ ```
51
+
52
+ ## React 사용법
53
+
54
+ ### Error Boundary
55
+
56
+ ```tsx
57
+ import { ClienworkErrorBoundary } from '@clienwork/errors/react'
58
+
59
+ function App() {
60
+ return (
61
+ <ClienworkErrorBoundary
62
+ fallback={<div>오류가 발생했습니다.</div>}
63
+ >
64
+ <MyComponent />
65
+ </ClienworkErrorBoundary>
66
+ )
67
+ }
68
+ ```
69
+
70
+ ### useErrorReporter Hook
71
+
72
+ ```tsx
73
+ import { useErrorReporter } from '@clienwork/errors/react'
74
+
75
+ function MyComponent() {
76
+ const { report } = useErrorReporter()
77
+
78
+ const handleClick = async () => {
79
+ try {
80
+ await riskyOperation()
81
+ } catch (error) {
82
+ report(error, { action: 'button-click' })
83
+ }
84
+ }
85
+
86
+ return <button onClick={handleClick}>Click</button>
87
+ }
88
+ ```
89
+
90
+ ### HOC
91
+
92
+ ```tsx
93
+ import { withErrorBoundary } from '@clienwork/errors/react'
94
+
95
+ const SafeComponent = withErrorBoundary(MyComponent, <div>오류 발생</div>)
96
+ ```
97
+
98
+ ## 백엔드 사용법 (Node.js)
99
+
100
+ ### 기본 사용법
101
+
102
+ ```typescript
103
+ import { createBackendReporter } from '@clienwork/errors'
104
+
105
+ const errorReporter = createBackendReporter({
106
+ apiToken: process.env.CLIENWORK_ERROR_TOKEN!,
107
+ })
108
+
109
+ try {
110
+ // 위험한 작업
111
+ } catch (error) {
112
+ await errorReporter.report(error, { endpoint: '/api/users' })
113
+ }
114
+ ```
115
+
116
+ ### Express 미들웨어
117
+
118
+ ```typescript
119
+ import { createBackendReporter, expressErrorHandler } from '@clienwork/errors'
120
+
121
+ const errorReporter = createBackendReporter({
122
+ apiToken: process.env.CLIENWORK_ERROR_TOKEN!,
123
+ })
124
+
125
+ app.use(expressErrorHandler(errorReporter))
126
+ ```
127
+
128
+ ### Next.js API Routes
129
+
130
+ ```typescript
131
+ import { createBackendReporter } from '@clienwork/errors'
132
+
133
+ const errorReporter = createBackendReporter({
134
+ apiToken: process.env.CLIENWORK_ERROR_TOKEN!,
135
+ })
136
+
137
+ export async function GET(request: Request) {
138
+ try {
139
+ // ...
140
+ } catch (error) {
141
+ await errorReporter.report(error as Error)
142
+ return new Response('Error', { status: 500 })
143
+ }
144
+ }
145
+ ```
146
+
147
+ ## 설정 옵션
148
+
149
+ ```typescript
150
+ init({
151
+ apiToken: 'clw_err_xxx', // 필수: API 토큰
152
+ endpoint: 'https://...', // 선택: 커스텀 엔드포인트
153
+ source: 'frontend', // 선택: 'frontend' | 'backend'
154
+ enabled: true, // 선택: 활성화 여부 (개발 환경에서 비활성화 가능)
155
+ defaultMetadata: {}, // 선택: 모든 에러에 포함될 기본 메타데이터
156
+ beforeSend: (error) => { // 선택: 전송 전 에러 수정/필터링
157
+ // null 반환 시 전송 취소
158
+ return error
159
+ },
160
+ })
161
+ ```
162
+
163
+ ## 라이선스
164
+
165
+ MIT
@@ -0,0 +1,143 @@
1
+ // src/reporter.ts
2
+ var DEFAULT_ENDPOINT = "https://app.clienwork.com/api/errors";
3
+ var ErrorReporter = class {
4
+ constructor(config) {
5
+ this.userId = null;
6
+ this.metadata = {};
7
+ this.config = {
8
+ apiToken: config.apiToken,
9
+ endpoint: config.endpoint || DEFAULT_ENDPOINT,
10
+ source: config.source || "frontend",
11
+ defaultMetadata: config.defaultMetadata || {},
12
+ enabled: config.enabled ?? true,
13
+ beforeSend: config.beforeSend
14
+ };
15
+ if (typeof window !== "undefined" && this.config.source === "frontend") {
16
+ this.setupGlobalHandlers();
17
+ }
18
+ }
19
+ setupGlobalHandlers() {
20
+ window.addEventListener("error", (event) => {
21
+ this.report({
22
+ message: event.message,
23
+ stack: event.error?.stack,
24
+ url: event.filename,
25
+ metadata: {
26
+ lineno: event.lineno,
27
+ colno: event.colno
28
+ }
29
+ });
30
+ });
31
+ window.addEventListener("unhandledrejection", (event) => {
32
+ const error = event.reason;
33
+ if (error instanceof Error) {
34
+ this.report(error);
35
+ } else {
36
+ this.report({
37
+ message: String(error),
38
+ metadata: { type: "unhandledrejection" }
39
+ });
40
+ }
41
+ });
42
+ }
43
+ setUser(userId) {
44
+ this.userId = userId;
45
+ }
46
+ clearUser() {
47
+ this.userId = null;
48
+ }
49
+ setMetadata(metadata) {
50
+ this.metadata = { ...this.metadata, ...metadata };
51
+ }
52
+ async report(error, additionalMetadata) {
53
+ if (!this.config.enabled) return;
54
+ let reportData;
55
+ if (error instanceof Error) {
56
+ reportData = {
57
+ message: error.message,
58
+ stack: error.stack,
59
+ source: this.config.source
60
+ };
61
+ } else {
62
+ reportData = {
63
+ ...error,
64
+ source: error.source || this.config.source
65
+ };
66
+ }
67
+ reportData.metadata = {
68
+ ...this.config.defaultMetadata,
69
+ ...this.metadata,
70
+ ...reportData.metadata,
71
+ ...additionalMetadata
72
+ };
73
+ if (this.userId) {
74
+ reportData.userId = this.userId;
75
+ }
76
+ if (typeof window !== "undefined") {
77
+ reportData.url = reportData.url || window.location.href;
78
+ reportData.userAgent = reportData.userAgent || navigator.userAgent;
79
+ }
80
+ if (this.config.beforeSend) {
81
+ const modified = this.config.beforeSend(reportData);
82
+ if (modified === null) return;
83
+ reportData = modified;
84
+ }
85
+ try {
86
+ await fetch(this.config.endpoint, {
87
+ method: "POST",
88
+ headers: {
89
+ "Content-Type": "application/json",
90
+ Authorization: `Bearer ${this.config.apiToken}`
91
+ },
92
+ body: JSON.stringify(reportData)
93
+ });
94
+ } catch (e) {
95
+ console.warn("[ClienworkErrors] Failed to report error:", e);
96
+ }
97
+ }
98
+ };
99
+ var instance = null;
100
+ function init(config) {
101
+ instance = new ErrorReporter(config);
102
+ return instance;
103
+ }
104
+ function getReporter() {
105
+ return instance;
106
+ }
107
+ function report(error, metadata) {
108
+ if (!instance) {
109
+ console.warn("[ClienworkErrors] Not initialized. Call init() first.");
110
+ return Promise.resolve();
111
+ }
112
+ return instance.report(error, metadata);
113
+ }
114
+ function setUser(userId) {
115
+ instance?.setUser(userId);
116
+ }
117
+ function clearUser() {
118
+ instance?.clearUser();
119
+ }
120
+ function createBackendReporter(config) {
121
+ return new ErrorReporter({ ...config, source: "backend" });
122
+ }
123
+ function expressErrorHandler(reporter) {
124
+ return (err, req, res, next) => {
125
+ reporter.report(err, {
126
+ path: req.path,
127
+ method: req.method,
128
+ userAgent: req.headers?.["user-agent"]
129
+ });
130
+ next();
131
+ };
132
+ }
133
+
134
+ export {
135
+ ErrorReporter,
136
+ init,
137
+ getReporter,
138
+ report,
139
+ setUser,
140
+ clearUser,
141
+ createBackendReporter,
142
+ expressErrorHandler
143
+ };
@@ -0,0 +1,56 @@
1
+ type ErrorSource = 'frontend' | 'backend';
2
+ type ErrorLevel = 'error' | 'warning';
3
+ interface ErrorReportOptions {
4
+ message: string;
5
+ stack?: string;
6
+ level?: ErrorLevel;
7
+ source?: ErrorSource;
8
+ url?: string;
9
+ userAgent?: string;
10
+ userId?: string;
11
+ metadata?: Record<string, unknown>;
12
+ fingerprint?: string;
13
+ }
14
+ interface ClienworkErrorConfig {
15
+ apiToken: string;
16
+ endpoint?: string;
17
+ source?: ErrorSource;
18
+ defaultMetadata?: Record<string, unknown>;
19
+ enabled?: boolean;
20
+ beforeSend?: (error: ErrorReportOptions) => ErrorReportOptions | null;
21
+ }
22
+ interface ErrorReporterInstance {
23
+ report: (error: Error | ErrorReportOptions, metadata?: Record<string, unknown>) => Promise<void>;
24
+ setUser: (userId: string) => void;
25
+ clearUser: () => void;
26
+ setMetadata: (metadata: Record<string, unknown>) => void;
27
+ }
28
+
29
+ declare class ErrorReporter implements ErrorReporterInstance {
30
+ private config;
31
+ private userId;
32
+ private metadata;
33
+ constructor(config: ClienworkErrorConfig);
34
+ private setupGlobalHandlers;
35
+ setUser(userId: string): void;
36
+ clearUser(): void;
37
+ setMetadata(metadata: Record<string, unknown>): void;
38
+ report(error: Error | ErrorReportOptions, additionalMetadata?: Record<string, unknown>): Promise<void>;
39
+ }
40
+ declare function init(config: ClienworkErrorConfig): ErrorReporter;
41
+ declare function getReporter(): ErrorReporter | null;
42
+ declare function report(error: Error | ErrorReportOptions, metadata?: Record<string, unknown>): Promise<void>;
43
+ declare function setUser(userId: string): void;
44
+ declare function clearUser(): void;
45
+ declare function createBackendReporter(config: Omit<ClienworkErrorConfig, 'source'>): ErrorReporter;
46
+ declare function expressErrorHandler(reporter: ErrorReporter): (err: Error, req: {
47
+ path?: string;
48
+ method?: string;
49
+ headers?: Record<string, string>;
50
+ }, res: {
51
+ status: (code: number) => {
52
+ json: (data: unknown) => void;
53
+ };
54
+ }, next: () => void) => void;
55
+
56
+ export { type ClienworkErrorConfig, type ErrorLevel, type ErrorReportOptions, ErrorReporter, type ErrorReporterInstance, type ErrorSource, clearUser, createBackendReporter, expressErrorHandler, getReporter, init, report, setUser };
@@ -0,0 +1,56 @@
1
+ type ErrorSource = 'frontend' | 'backend';
2
+ type ErrorLevel = 'error' | 'warning';
3
+ interface ErrorReportOptions {
4
+ message: string;
5
+ stack?: string;
6
+ level?: ErrorLevel;
7
+ source?: ErrorSource;
8
+ url?: string;
9
+ userAgent?: string;
10
+ userId?: string;
11
+ metadata?: Record<string, unknown>;
12
+ fingerprint?: string;
13
+ }
14
+ interface ClienworkErrorConfig {
15
+ apiToken: string;
16
+ endpoint?: string;
17
+ source?: ErrorSource;
18
+ defaultMetadata?: Record<string, unknown>;
19
+ enabled?: boolean;
20
+ beforeSend?: (error: ErrorReportOptions) => ErrorReportOptions | null;
21
+ }
22
+ interface ErrorReporterInstance {
23
+ report: (error: Error | ErrorReportOptions, metadata?: Record<string, unknown>) => Promise<void>;
24
+ setUser: (userId: string) => void;
25
+ clearUser: () => void;
26
+ setMetadata: (metadata: Record<string, unknown>) => void;
27
+ }
28
+
29
+ declare class ErrorReporter implements ErrorReporterInstance {
30
+ private config;
31
+ private userId;
32
+ private metadata;
33
+ constructor(config: ClienworkErrorConfig);
34
+ private setupGlobalHandlers;
35
+ setUser(userId: string): void;
36
+ clearUser(): void;
37
+ setMetadata(metadata: Record<string, unknown>): void;
38
+ report(error: Error | ErrorReportOptions, additionalMetadata?: Record<string, unknown>): Promise<void>;
39
+ }
40
+ declare function init(config: ClienworkErrorConfig): ErrorReporter;
41
+ declare function getReporter(): ErrorReporter | null;
42
+ declare function report(error: Error | ErrorReportOptions, metadata?: Record<string, unknown>): Promise<void>;
43
+ declare function setUser(userId: string): void;
44
+ declare function clearUser(): void;
45
+ declare function createBackendReporter(config: Omit<ClienworkErrorConfig, 'source'>): ErrorReporter;
46
+ declare function expressErrorHandler(reporter: ErrorReporter): (err: Error, req: {
47
+ path?: string;
48
+ method?: string;
49
+ headers?: Record<string, string>;
50
+ }, res: {
51
+ status: (code: number) => {
52
+ json: (data: unknown) => void;
53
+ };
54
+ }, next: () => void) => void;
55
+
56
+ export { type ClienworkErrorConfig, type ErrorLevel, type ErrorReportOptions, ErrorReporter, type ErrorReporterInstance, type ErrorSource, clearUser, createBackendReporter, expressErrorHandler, getReporter, init, report, setUser };
package/dist/index.js ADDED
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ErrorReporter: () => ErrorReporter,
24
+ clearUser: () => clearUser,
25
+ createBackendReporter: () => createBackendReporter,
26
+ expressErrorHandler: () => expressErrorHandler,
27
+ getReporter: () => getReporter,
28
+ init: () => init,
29
+ report: () => report,
30
+ setUser: () => setUser
31
+ });
32
+ module.exports = __toCommonJS(index_exports);
33
+
34
+ // src/reporter.ts
35
+ var DEFAULT_ENDPOINT = "https://app.clienwork.com/api/errors";
36
+ var ErrorReporter = class {
37
+ constructor(config) {
38
+ this.userId = null;
39
+ this.metadata = {};
40
+ this.config = {
41
+ apiToken: config.apiToken,
42
+ endpoint: config.endpoint || DEFAULT_ENDPOINT,
43
+ source: config.source || "frontend",
44
+ defaultMetadata: config.defaultMetadata || {},
45
+ enabled: config.enabled ?? true,
46
+ beforeSend: config.beforeSend
47
+ };
48
+ if (typeof window !== "undefined" && this.config.source === "frontend") {
49
+ this.setupGlobalHandlers();
50
+ }
51
+ }
52
+ setupGlobalHandlers() {
53
+ window.addEventListener("error", (event) => {
54
+ this.report({
55
+ message: event.message,
56
+ stack: event.error?.stack,
57
+ url: event.filename,
58
+ metadata: {
59
+ lineno: event.lineno,
60
+ colno: event.colno
61
+ }
62
+ });
63
+ });
64
+ window.addEventListener("unhandledrejection", (event) => {
65
+ const error = event.reason;
66
+ if (error instanceof Error) {
67
+ this.report(error);
68
+ } else {
69
+ this.report({
70
+ message: String(error),
71
+ metadata: { type: "unhandledrejection" }
72
+ });
73
+ }
74
+ });
75
+ }
76
+ setUser(userId) {
77
+ this.userId = userId;
78
+ }
79
+ clearUser() {
80
+ this.userId = null;
81
+ }
82
+ setMetadata(metadata) {
83
+ this.metadata = { ...this.metadata, ...metadata };
84
+ }
85
+ async report(error, additionalMetadata) {
86
+ if (!this.config.enabled) return;
87
+ let reportData;
88
+ if (error instanceof Error) {
89
+ reportData = {
90
+ message: error.message,
91
+ stack: error.stack,
92
+ source: this.config.source
93
+ };
94
+ } else {
95
+ reportData = {
96
+ ...error,
97
+ source: error.source || this.config.source
98
+ };
99
+ }
100
+ reportData.metadata = {
101
+ ...this.config.defaultMetadata,
102
+ ...this.metadata,
103
+ ...reportData.metadata,
104
+ ...additionalMetadata
105
+ };
106
+ if (this.userId) {
107
+ reportData.userId = this.userId;
108
+ }
109
+ if (typeof window !== "undefined") {
110
+ reportData.url = reportData.url || window.location.href;
111
+ reportData.userAgent = reportData.userAgent || navigator.userAgent;
112
+ }
113
+ if (this.config.beforeSend) {
114
+ const modified = this.config.beforeSend(reportData);
115
+ if (modified === null) return;
116
+ reportData = modified;
117
+ }
118
+ try {
119
+ await fetch(this.config.endpoint, {
120
+ method: "POST",
121
+ headers: {
122
+ "Content-Type": "application/json",
123
+ Authorization: `Bearer ${this.config.apiToken}`
124
+ },
125
+ body: JSON.stringify(reportData)
126
+ });
127
+ } catch (e) {
128
+ console.warn("[ClienworkErrors] Failed to report error:", e);
129
+ }
130
+ }
131
+ };
132
+ var instance = null;
133
+ function init(config) {
134
+ instance = new ErrorReporter(config);
135
+ return instance;
136
+ }
137
+ function getReporter() {
138
+ return instance;
139
+ }
140
+ function report(error, metadata) {
141
+ if (!instance) {
142
+ console.warn("[ClienworkErrors] Not initialized. Call init() first.");
143
+ return Promise.resolve();
144
+ }
145
+ return instance.report(error, metadata);
146
+ }
147
+ function setUser(userId) {
148
+ instance?.setUser(userId);
149
+ }
150
+ function clearUser() {
151
+ instance?.clearUser();
152
+ }
153
+ function createBackendReporter(config) {
154
+ return new ErrorReporter({ ...config, source: "backend" });
155
+ }
156
+ function expressErrorHandler(reporter) {
157
+ return (err, req, res, next) => {
158
+ reporter.report(err, {
159
+ path: req.path,
160
+ method: req.method,
161
+ userAgent: req.headers?.["user-agent"]
162
+ });
163
+ next();
164
+ };
165
+ }
166
+ // Annotate the CommonJS export names for ESM import in node:
167
+ 0 && (module.exports = {
168
+ ErrorReporter,
169
+ clearUser,
170
+ createBackendReporter,
171
+ expressErrorHandler,
172
+ getReporter,
173
+ init,
174
+ report,
175
+ setUser
176
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,20 @@
1
+ import {
2
+ ErrorReporter,
3
+ clearUser,
4
+ createBackendReporter,
5
+ expressErrorHandler,
6
+ getReporter,
7
+ init,
8
+ report,
9
+ setUser
10
+ } from "./chunk-HLDC7IDZ.mjs";
11
+ export {
12
+ ErrorReporter,
13
+ clearUser,
14
+ createBackendReporter,
15
+ expressErrorHandler,
16
+ getReporter,
17
+ init,
18
+ report,
19
+ setUser
20
+ };
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { ErrorReportOptions } from './index.mjs';
3
+ export { ClienworkErrorConfig, clearUser, getReporter, init, report, setUser } from './index.mjs';
4
+
5
+ interface ErrorBoundaryProps {
6
+ children: React.ReactNode;
7
+ fallback?: React.ReactNode | ((error: Error) => React.ReactNode);
8
+ onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
9
+ }
10
+ interface ErrorBoundaryState {
11
+ hasError: boolean;
12
+ error: Error | null;
13
+ }
14
+ declare class ClienworkErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
15
+ constructor(props: ErrorBoundaryProps);
16
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
17
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
18
+ render(): React.ReactNode;
19
+ }
20
+ declare function useErrorReporter(): {
21
+ report: (error: Error | ErrorReportOptions, metadata?: Record<string, unknown>) => Promise<void>;
22
+ };
23
+ declare function withErrorBoundary<P extends object>(Component: React.ComponentType<P>, fallback?: ErrorBoundaryProps['fallback']): React.FC<P>;
24
+
25
+ export { ClienworkErrorBoundary, ErrorReportOptions, useErrorReporter, withErrorBoundary };
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import { ErrorReportOptions } from './index.js';
3
+ export { ClienworkErrorConfig, clearUser, getReporter, init, report, setUser } from './index.js';
4
+
5
+ interface ErrorBoundaryProps {
6
+ children: React.ReactNode;
7
+ fallback?: React.ReactNode | ((error: Error) => React.ReactNode);
8
+ onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
9
+ }
10
+ interface ErrorBoundaryState {
11
+ hasError: boolean;
12
+ error: Error | null;
13
+ }
14
+ declare class ClienworkErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
15
+ constructor(props: ErrorBoundaryProps);
16
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
17
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;
18
+ render(): React.ReactNode;
19
+ }
20
+ declare function useErrorReporter(): {
21
+ report: (error: Error | ErrorReportOptions, metadata?: Record<string, unknown>) => Promise<void>;
22
+ };
23
+ declare function withErrorBoundary<P extends object>(Component: React.ComponentType<P>, fallback?: ErrorBoundaryProps['fallback']): React.FC<P>;
24
+
25
+ export { ClienworkErrorBoundary, ErrorReportOptions, useErrorReporter, withErrorBoundary };
package/dist/react.js ADDED
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/react.ts
31
+ var react_exports = {};
32
+ __export(react_exports, {
33
+ ClienworkErrorBoundary: () => ClienworkErrorBoundary,
34
+ clearUser: () => clearUser,
35
+ getReporter: () => getReporter,
36
+ init: () => init,
37
+ report: () => report,
38
+ setUser: () => setUser,
39
+ useErrorReporter: () => useErrorReporter,
40
+ withErrorBoundary: () => withErrorBoundary
41
+ });
42
+ module.exports = __toCommonJS(react_exports);
43
+ var React = __toESM(require("react"));
44
+
45
+ // src/reporter.ts
46
+ var DEFAULT_ENDPOINT = "https://app.clienwork.com/api/errors";
47
+ var ErrorReporter = class {
48
+ constructor(config) {
49
+ this.userId = null;
50
+ this.metadata = {};
51
+ this.config = {
52
+ apiToken: config.apiToken,
53
+ endpoint: config.endpoint || DEFAULT_ENDPOINT,
54
+ source: config.source || "frontend",
55
+ defaultMetadata: config.defaultMetadata || {},
56
+ enabled: config.enabled ?? true,
57
+ beforeSend: config.beforeSend
58
+ };
59
+ if (typeof window !== "undefined" && this.config.source === "frontend") {
60
+ this.setupGlobalHandlers();
61
+ }
62
+ }
63
+ setupGlobalHandlers() {
64
+ window.addEventListener("error", (event) => {
65
+ this.report({
66
+ message: event.message,
67
+ stack: event.error?.stack,
68
+ url: event.filename,
69
+ metadata: {
70
+ lineno: event.lineno,
71
+ colno: event.colno
72
+ }
73
+ });
74
+ });
75
+ window.addEventListener("unhandledrejection", (event) => {
76
+ const error = event.reason;
77
+ if (error instanceof Error) {
78
+ this.report(error);
79
+ } else {
80
+ this.report({
81
+ message: String(error),
82
+ metadata: { type: "unhandledrejection" }
83
+ });
84
+ }
85
+ });
86
+ }
87
+ setUser(userId) {
88
+ this.userId = userId;
89
+ }
90
+ clearUser() {
91
+ this.userId = null;
92
+ }
93
+ setMetadata(metadata) {
94
+ this.metadata = { ...this.metadata, ...metadata };
95
+ }
96
+ async report(error, additionalMetadata) {
97
+ if (!this.config.enabled) return;
98
+ let reportData;
99
+ if (error instanceof Error) {
100
+ reportData = {
101
+ message: error.message,
102
+ stack: error.stack,
103
+ source: this.config.source
104
+ };
105
+ } else {
106
+ reportData = {
107
+ ...error,
108
+ source: error.source || this.config.source
109
+ };
110
+ }
111
+ reportData.metadata = {
112
+ ...this.config.defaultMetadata,
113
+ ...this.metadata,
114
+ ...reportData.metadata,
115
+ ...additionalMetadata
116
+ };
117
+ if (this.userId) {
118
+ reportData.userId = this.userId;
119
+ }
120
+ if (typeof window !== "undefined") {
121
+ reportData.url = reportData.url || window.location.href;
122
+ reportData.userAgent = reportData.userAgent || navigator.userAgent;
123
+ }
124
+ if (this.config.beforeSend) {
125
+ const modified = this.config.beforeSend(reportData);
126
+ if (modified === null) return;
127
+ reportData = modified;
128
+ }
129
+ try {
130
+ await fetch(this.config.endpoint, {
131
+ method: "POST",
132
+ headers: {
133
+ "Content-Type": "application/json",
134
+ Authorization: `Bearer ${this.config.apiToken}`
135
+ },
136
+ body: JSON.stringify(reportData)
137
+ });
138
+ } catch (e) {
139
+ console.warn("[ClienworkErrors] Failed to report error:", e);
140
+ }
141
+ }
142
+ };
143
+ var instance = null;
144
+ function init(config) {
145
+ instance = new ErrorReporter(config);
146
+ return instance;
147
+ }
148
+ function getReporter() {
149
+ return instance;
150
+ }
151
+ function report(error, metadata) {
152
+ if (!instance) {
153
+ console.warn("[ClienworkErrors] Not initialized. Call init() first.");
154
+ return Promise.resolve();
155
+ }
156
+ return instance.report(error, metadata);
157
+ }
158
+ function setUser(userId) {
159
+ instance?.setUser(userId);
160
+ }
161
+ function clearUser() {
162
+ instance?.clearUser();
163
+ }
164
+
165
+ // src/react.ts
166
+ var ClienworkErrorBoundary = class extends React.Component {
167
+ constructor(props) {
168
+ super(props);
169
+ this.state = { hasError: false, error: null };
170
+ }
171
+ static getDerivedStateFromError(error) {
172
+ return { hasError: true, error };
173
+ }
174
+ componentDidCatch(error, errorInfo) {
175
+ const reporter = getReporter();
176
+ if (reporter) {
177
+ reporter.report(error, {
178
+ componentStack: errorInfo.componentStack,
179
+ type: "react-error-boundary"
180
+ });
181
+ }
182
+ this.props.onError?.(error, errorInfo);
183
+ }
184
+ render() {
185
+ if (this.state.hasError && this.state.error) {
186
+ if (typeof this.props.fallback === "function") {
187
+ return this.props.fallback(this.state.error);
188
+ }
189
+ return this.props.fallback ?? null;
190
+ }
191
+ return this.props.children;
192
+ }
193
+ };
194
+ function useErrorReporter() {
195
+ const report2 = React.useCallback(
196
+ (error, metadata) => {
197
+ const reporter = getReporter();
198
+ if (reporter) {
199
+ return reporter.report(error, metadata);
200
+ }
201
+ console.warn("[ClienworkErrors] Not initialized. Call init() first.");
202
+ return Promise.resolve();
203
+ },
204
+ []
205
+ );
206
+ return { report: report2 };
207
+ }
208
+ function withErrorBoundary(Component2, fallback) {
209
+ const WrappedComponent = (props) => {
210
+ return React.createElement(
211
+ ClienworkErrorBoundary,
212
+ { fallback, children: React.createElement(Component2, props) }
213
+ );
214
+ };
215
+ WrappedComponent.displayName = `withErrorBoundary(${Component2.displayName || Component2.name || "Component"})`;
216
+ return WrappedComponent;
217
+ }
218
+ // Annotate the CommonJS export names for ESM import in node:
219
+ 0 && (module.exports = {
220
+ ClienworkErrorBoundary,
221
+ clearUser,
222
+ getReporter,
223
+ init,
224
+ report,
225
+ setUser,
226
+ useErrorReporter,
227
+ withErrorBoundary
228
+ });
package/dist/react.mjs ADDED
@@ -0,0 +1,72 @@
1
+ import {
2
+ clearUser,
3
+ getReporter,
4
+ init,
5
+ report,
6
+ setUser
7
+ } from "./chunk-HLDC7IDZ.mjs";
8
+
9
+ // src/react.ts
10
+ import * as React from "react";
11
+ var ClienworkErrorBoundary = class extends React.Component {
12
+ constructor(props) {
13
+ super(props);
14
+ this.state = { hasError: false, error: null };
15
+ }
16
+ static getDerivedStateFromError(error) {
17
+ return { hasError: true, error };
18
+ }
19
+ componentDidCatch(error, errorInfo) {
20
+ const reporter = getReporter();
21
+ if (reporter) {
22
+ reporter.report(error, {
23
+ componentStack: errorInfo.componentStack,
24
+ type: "react-error-boundary"
25
+ });
26
+ }
27
+ this.props.onError?.(error, errorInfo);
28
+ }
29
+ render() {
30
+ if (this.state.hasError && this.state.error) {
31
+ if (typeof this.props.fallback === "function") {
32
+ return this.props.fallback(this.state.error);
33
+ }
34
+ return this.props.fallback ?? null;
35
+ }
36
+ return this.props.children;
37
+ }
38
+ };
39
+ function useErrorReporter() {
40
+ const report2 = React.useCallback(
41
+ (error, metadata) => {
42
+ const reporter = getReporter();
43
+ if (reporter) {
44
+ return reporter.report(error, metadata);
45
+ }
46
+ console.warn("[ClienworkErrors] Not initialized. Call init() first.");
47
+ return Promise.resolve();
48
+ },
49
+ []
50
+ );
51
+ return { report: report2 };
52
+ }
53
+ function withErrorBoundary(Component2, fallback) {
54
+ const WrappedComponent = (props) => {
55
+ return React.createElement(
56
+ ClienworkErrorBoundary,
57
+ { fallback, children: React.createElement(Component2, props) }
58
+ );
59
+ };
60
+ WrappedComponent.displayName = `withErrorBoundary(${Component2.displayName || Component2.name || "Component"})`;
61
+ return WrappedComponent;
62
+ }
63
+ export {
64
+ ClienworkErrorBoundary,
65
+ clearUser,
66
+ getReporter,
67
+ init,
68
+ report,
69
+ setUser,
70
+ useErrorReporter,
71
+ withErrorBoundary
72
+ };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@clienwork/errors",
3
+ "version": "1.0.0",
4
+ "description": "Error collection SDK for Clienwork",
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
+ "./react": {
15
+ "types": "./dist/react.d.ts",
16
+ "import": "./dist/react.mjs",
17
+ "require": "./dist/react.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsup src/index.ts src/react.ts --format cjs,esm --dts --clean",
25
+ "dev": "tsup src/index.ts src/react.ts --format cjs,esm --dts --watch",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "peerDependencies": {
29
+ "react": ">=16.8.0"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "react": {
33
+ "optional": true
34
+ }
35
+ },
36
+ "devDependencies": {
37
+ "react": "^18.0.0",
38
+ "tsup": "^8.0.0",
39
+ "typescript": "^5.0.0"
40
+ },
41
+ "keywords": [
42
+ "error",
43
+ "tracking",
44
+ "monitoring",
45
+ "clienwork"
46
+ ],
47
+ "license": "MIT",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/clienwork/clienwork"
51
+ }
52
+ }