@ga-components/logger 1.0.2 → 1.0.4
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/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +37 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +37 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -11,6 +11,7 @@ interface LogEntry {
|
|
|
11
11
|
stackTrace: string | null;
|
|
12
12
|
payload: Record<string, unknown>;
|
|
13
13
|
repo: string;
|
|
14
|
+
endpoint: string | null;
|
|
14
15
|
}
|
|
15
16
|
interface LoggerConfig {
|
|
16
17
|
env: LogEnv;
|
|
@@ -27,12 +28,14 @@ interface LoggerConfig {
|
|
|
27
28
|
declare class Logger {
|
|
28
29
|
private config;
|
|
29
30
|
private initialized;
|
|
31
|
+
private fetchIntercepted;
|
|
30
32
|
init(config: LoggerConfig): void;
|
|
31
33
|
setUserId(userId: string | null): void;
|
|
34
|
+
interceptFetch(): void;
|
|
32
35
|
private send;
|
|
33
|
-
info(message: string, payload?: Record<string, unknown
|
|
34
|
-
warn(message: string, payload?: Record<string, unknown
|
|
35
|
-
error(message: string, error?: Error, payload?: Record<string, unknown
|
|
36
|
+
info(message: string, payload?: Record<string, unknown>, endpoint?: string): Promise<void>;
|
|
37
|
+
warn(message: string, payload?: Record<string, unknown>, endpoint?: string): Promise<void>;
|
|
38
|
+
error(message: string, error?: Error, payload?: Record<string, unknown>, endpoint?: string): Promise<void>;
|
|
36
39
|
}
|
|
37
40
|
declare const logger: Logger;
|
|
38
41
|
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ interface LogEntry {
|
|
|
11
11
|
stackTrace: string | null;
|
|
12
12
|
payload: Record<string, unknown>;
|
|
13
13
|
repo: string;
|
|
14
|
+
endpoint: string | null;
|
|
14
15
|
}
|
|
15
16
|
interface LoggerConfig {
|
|
16
17
|
env: LogEnv;
|
|
@@ -27,12 +28,14 @@ interface LoggerConfig {
|
|
|
27
28
|
declare class Logger {
|
|
28
29
|
private config;
|
|
29
30
|
private initialized;
|
|
31
|
+
private fetchIntercepted;
|
|
30
32
|
init(config: LoggerConfig): void;
|
|
31
33
|
setUserId(userId: string | null): void;
|
|
34
|
+
interceptFetch(): void;
|
|
32
35
|
private send;
|
|
33
|
-
info(message: string, payload?: Record<string, unknown
|
|
34
|
-
warn(message: string, payload?: Record<string, unknown
|
|
35
|
-
error(message: string, error?: Error, payload?: Record<string, unknown
|
|
36
|
+
info(message: string, payload?: Record<string, unknown>, endpoint?: string): Promise<void>;
|
|
37
|
+
warn(message: string, payload?: Record<string, unknown>, endpoint?: string): Promise<void>;
|
|
38
|
+
error(message: string, error?: Error, payload?: Record<string, unknown>, endpoint?: string): Promise<void>;
|
|
36
39
|
}
|
|
37
40
|
declare const logger: Logger;
|
|
38
41
|
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ var Logger = class {
|
|
|
59
59
|
constructor() {
|
|
60
60
|
this.config = null;
|
|
61
61
|
this.initialized = false;
|
|
62
|
+
this.fetchIntercepted = false;
|
|
62
63
|
}
|
|
63
64
|
init(config) {
|
|
64
65
|
this.config = config;
|
|
@@ -73,7 +74,34 @@ var Logger = class {
|
|
|
73
74
|
}
|
|
74
75
|
this.config.userId = userId;
|
|
75
76
|
}
|
|
76
|
-
|
|
77
|
+
// Auto intercept semua fetch
|
|
78
|
+
interceptFetch() {
|
|
79
|
+
if (this.fetchIntercepted) return;
|
|
80
|
+
const originalFetch = window.fetch;
|
|
81
|
+
window.fetch = async (...args) => {
|
|
82
|
+
const url = typeof args[0] === "string" ? args[0] : args[0].url;
|
|
83
|
+
const method = (args[1]?.method ?? "GET").toUpperCase();
|
|
84
|
+
const endpoint = `${method} ${url}`;
|
|
85
|
+
try {
|
|
86
|
+
const response = await originalFetch(...args);
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
this.send("error", `HTTP ${response.status} ${endpoint}`, { endpoint, status: response.status });
|
|
89
|
+
}
|
|
90
|
+
return response;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
this.send(
|
|
93
|
+
"error",
|
|
94
|
+
`Network error ${endpoint}`,
|
|
95
|
+
{ endpoint },
|
|
96
|
+
error instanceof Error ? error : new Error(String(error))
|
|
97
|
+
);
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
this.fetchIntercepted = true;
|
|
102
|
+
console.info("[ga-logger] fetch intercepted \u2705");
|
|
103
|
+
}
|
|
104
|
+
async send(level, message, payload = {}, error, endpoint) {
|
|
77
105
|
if (!this.initialized || !this.config) {
|
|
78
106
|
console.warn("[ga-logger] not initialized. Call logger.init() first.");
|
|
79
107
|
return;
|
|
@@ -88,7 +116,8 @@ var Logger = class {
|
|
|
88
116
|
page: typeof window !== "undefined" ? window.location.pathname : "",
|
|
89
117
|
stackTrace: error?.stack ?? null,
|
|
90
118
|
payload,
|
|
91
|
-
repo: this.config.repo
|
|
119
|
+
repo: this.config.repo,
|
|
120
|
+
endpoint: endpoint ?? null
|
|
92
121
|
};
|
|
93
122
|
try {
|
|
94
123
|
const db2 = getDb();
|
|
@@ -100,14 +129,14 @@ var Logger = class {
|
|
|
100
129
|
console.error("[ga-logger] failed to send log:", e);
|
|
101
130
|
}
|
|
102
131
|
}
|
|
103
|
-
info(message, payload) {
|
|
104
|
-
return this.send("info", message, payload);
|
|
132
|
+
info(message, payload, endpoint) {
|
|
133
|
+
return this.send("info", message, payload, void 0, endpoint);
|
|
105
134
|
}
|
|
106
|
-
warn(message, payload) {
|
|
107
|
-
return this.send("warn", message, payload);
|
|
135
|
+
warn(message, payload, endpoint) {
|
|
136
|
+
return this.send("warn", message, payload, void 0, endpoint);
|
|
108
137
|
}
|
|
109
|
-
error(message, error, payload) {
|
|
110
|
-
return this.send("error", message, payload, error);
|
|
138
|
+
error(message, error, payload, endpoint) {
|
|
139
|
+
return this.send("error", message, payload, error, endpoint);
|
|
111
140
|
}
|
|
112
141
|
};
|
|
113
142
|
var logger = new Logger();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/logger.ts","../src/config/firebase.ts"],"sourcesContent":["export { logger } from \"./core/logger\";\nexport type { LogEntry, LoggerConfig, LogLevel, LogEnv } from \"./types\";\n","import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { LogEntry, LogLevel, LoggerConfig } from \"../types\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n private async send(level: LogLevel
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/logger.ts","../src/config/firebase.ts"],"sourcesContent":["export { logger } from \"./core/logger\";\nexport type { LogEntry, LoggerConfig, LogLevel, LogEnv } from \"./types\";\n","import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { LogEntry, LogLevel, LoggerConfig } from \"../types\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n private fetchIntercepted = false;\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n // Auto intercept semua fetch\n interceptFetch() {\n if (this.fetchIntercepted) return;\n const originalFetch = window.fetch;\n\n window.fetch = async (...args) => {\n const url = typeof args[0] === \"string\" ? args[0] : (args[0] as Request).url;\n const method = (args[1]?.method ?? \"GET\").toUpperCase();\n const endpoint = `${method} ${url}`;\n\n try {\n const response = await originalFetch(...args);\n\n // Auto log jika 4xx atau 5xx\n if (!response.ok) {\n this.send(\"error\", `HTTP ${response.status} ${endpoint}`, { endpoint, status: response.status });\n }\n\n return response;\n } catch (error) {\n // Network error / timeout\n this.send(\n \"error\",\n `Network error ${endpoint}`,\n { endpoint },\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n };\n\n this.fetchIntercepted = true;\n console.info(\"[ga-logger] fetch intercepted ✅\");\n }\n\n private async send(\n level: LogLevel,\n message: string,\n payload: Record<string, unknown> = {},\n error?: Error,\n endpoint?: string,\n ) {\n if (!this.initialized || !this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n message,\n env: this.config.env,\n userId: this.config.userId ?? null,\n sessionId,\n page: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n stackTrace: error?.stack ?? null,\n payload,\n repo: this.config.repo,\n endpoint: endpoint ?? null,\n };\n try {\n const db = getDb();\n await addDoc(collection(db, \"logs\"), {\n ...entry,\n timestamp: Timestamp.fromDate(entry.timestamp),\n });\n } catch (e) {\n console.error(\"[ga-logger] failed to send log:\", e);\n }\n }\n\n info(message: string, payload?: Record<string, unknown>, endpoint?: string) {\n return this.send(\"info\", message, payload, undefined, endpoint);\n }\n\n warn(message: string, payload?: Record<string, unknown>, endpoint?: string) {\n return this.send(\"warn\", message, payload, undefined, endpoint);\n }\n\n error(message: string, error?: Error, payload?: Record<string, unknown>, endpoint?: string) {\n return this.send(\"error\", message, payload, error, endpoint);\n }\n}\n\nexport const logger = new Logger();","import { initializeApp, getApps, FirebaseApp } from \"firebase/app\";\nimport { getFirestore, Firestore } from \"firebase/firestore\";\nimport { LoggerConfig } from \"../types\";\n\nlet app: FirebaseApp;\nlet db: Firestore;\n\nexport const initFirebase = (config: LoggerConfig) => {\n if (!getApps().length) {\n app = initializeApp(\n {\n apiKey: config.apiKey,\n authDomain: config.authDomain,\n projectId: config.projectId,\n storageBucket: config.storageBucket,\n messagingSenderId: config.messagingSenderId,\n appId: config.appId,\n },\n \"ga-logger\",\n );\n } else {\n app = getApps()[0];\n }\n\n db = getFirestore(app);\n return db;\n};\n\nexport const getDb = () => db;\n"],"mappings":"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","names":["import_firestore","db"]}
|
package/dist/index.mjs
CHANGED
|
@@ -33,6 +33,7 @@ var Logger = class {
|
|
|
33
33
|
constructor() {
|
|
34
34
|
this.config = null;
|
|
35
35
|
this.initialized = false;
|
|
36
|
+
this.fetchIntercepted = false;
|
|
36
37
|
}
|
|
37
38
|
init(config) {
|
|
38
39
|
this.config = config;
|
|
@@ -47,7 +48,34 @@ var Logger = class {
|
|
|
47
48
|
}
|
|
48
49
|
this.config.userId = userId;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
+
// Auto intercept semua fetch
|
|
52
|
+
interceptFetch() {
|
|
53
|
+
if (this.fetchIntercepted) return;
|
|
54
|
+
const originalFetch = window.fetch;
|
|
55
|
+
window.fetch = async (...args) => {
|
|
56
|
+
const url = typeof args[0] === "string" ? args[0] : args[0].url;
|
|
57
|
+
const method = (args[1]?.method ?? "GET").toUpperCase();
|
|
58
|
+
const endpoint = `${method} ${url}`;
|
|
59
|
+
try {
|
|
60
|
+
const response = await originalFetch(...args);
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
this.send("error", `HTTP ${response.status} ${endpoint}`, { endpoint, status: response.status });
|
|
63
|
+
}
|
|
64
|
+
return response;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
this.send(
|
|
67
|
+
"error",
|
|
68
|
+
`Network error ${endpoint}`,
|
|
69
|
+
{ endpoint },
|
|
70
|
+
error instanceof Error ? error : new Error(String(error))
|
|
71
|
+
);
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
this.fetchIntercepted = true;
|
|
76
|
+
console.info("[ga-logger] fetch intercepted \u2705");
|
|
77
|
+
}
|
|
78
|
+
async send(level, message, payload = {}, error, endpoint) {
|
|
51
79
|
if (!this.initialized || !this.config) {
|
|
52
80
|
console.warn("[ga-logger] not initialized. Call logger.init() first.");
|
|
53
81
|
return;
|
|
@@ -62,7 +90,8 @@ var Logger = class {
|
|
|
62
90
|
page: typeof window !== "undefined" ? window.location.pathname : "",
|
|
63
91
|
stackTrace: error?.stack ?? null,
|
|
64
92
|
payload,
|
|
65
|
-
repo: this.config.repo
|
|
93
|
+
repo: this.config.repo,
|
|
94
|
+
endpoint: endpoint ?? null
|
|
66
95
|
};
|
|
67
96
|
try {
|
|
68
97
|
const db2 = getDb();
|
|
@@ -74,14 +103,14 @@ var Logger = class {
|
|
|
74
103
|
console.error("[ga-logger] failed to send log:", e);
|
|
75
104
|
}
|
|
76
105
|
}
|
|
77
|
-
info(message, payload) {
|
|
78
|
-
return this.send("info", message, payload);
|
|
106
|
+
info(message, payload, endpoint) {
|
|
107
|
+
return this.send("info", message, payload, void 0, endpoint);
|
|
79
108
|
}
|
|
80
|
-
warn(message, payload) {
|
|
81
|
-
return this.send("warn", message, payload);
|
|
109
|
+
warn(message, payload, endpoint) {
|
|
110
|
+
return this.send("warn", message, payload, void 0, endpoint);
|
|
82
111
|
}
|
|
83
|
-
error(message, error, payload) {
|
|
84
|
-
return this.send("error", message, payload, error);
|
|
112
|
+
error(message, error, payload, endpoint) {
|
|
113
|
+
return this.send("error", message, payload, error, endpoint);
|
|
85
114
|
}
|
|
86
115
|
};
|
|
87
116
|
var logger = new Logger();
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/logger.ts","../src/config/firebase.ts"],"sourcesContent":["import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { LogEntry, LogLevel, LoggerConfig } from \"../types\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n private async send(level: LogLevel
|
|
1
|
+
{"version":3,"sources":["../src/core/logger.ts","../src/config/firebase.ts"],"sourcesContent":["import { collection, addDoc, Timestamp } from \"firebase/firestore\";\nimport { initFirebase, getDb } from \"../config/firebase\";\nimport type { LogEntry, LogLevel, LoggerConfig } from \"../types\";\n\nconst sessionId = `sess_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;\n\nclass Logger {\n private config: LoggerConfig | null = null;\n private initialized = false;\n private fetchIntercepted = false;\n\n init(config: LoggerConfig) {\n this.config = config;\n initFirebase(config);\n this.initialized = true;\n console.info(\"[ga-logger] initialized —\", config.env);\n }\n\n setUserId(userId: string | null) {\n if (!this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n this.config.userId = userId;\n }\n\n // Auto intercept semua fetch\n interceptFetch() {\n if (this.fetchIntercepted) return;\n const originalFetch = window.fetch;\n\n window.fetch = async (...args) => {\n const url = typeof args[0] === \"string\" ? args[0] : (args[0] as Request).url;\n const method = (args[1]?.method ?? \"GET\").toUpperCase();\n const endpoint = `${method} ${url}`;\n\n try {\n const response = await originalFetch(...args);\n\n // Auto log jika 4xx atau 5xx\n if (!response.ok) {\n this.send(\"error\", `HTTP ${response.status} ${endpoint}`, { endpoint, status: response.status });\n }\n\n return response;\n } catch (error) {\n // Network error / timeout\n this.send(\n \"error\",\n `Network error ${endpoint}`,\n { endpoint },\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n }\n };\n\n this.fetchIntercepted = true;\n console.info(\"[ga-logger] fetch intercepted ✅\");\n }\n\n private async send(\n level: LogLevel,\n message: string,\n payload: Record<string, unknown> = {},\n error?: Error,\n endpoint?: string,\n ) {\n if (!this.initialized || !this.config) {\n console.warn(\"[ga-logger] not initialized. Call logger.init() first.\");\n return;\n }\n\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n message,\n env: this.config.env,\n userId: this.config.userId ?? null,\n sessionId,\n page: typeof window !== \"undefined\" ? window.location.pathname : \"\",\n stackTrace: error?.stack ?? null,\n payload,\n repo: this.config.repo,\n endpoint: endpoint ?? null,\n };\n try {\n const db = getDb();\n await addDoc(collection(db, \"logs\"), {\n ...entry,\n timestamp: Timestamp.fromDate(entry.timestamp),\n });\n } catch (e) {\n console.error(\"[ga-logger] failed to send log:\", e);\n }\n }\n\n info(message: string, payload?: Record<string, unknown>, endpoint?: string) {\n return this.send(\"info\", message, payload, undefined, endpoint);\n }\n\n warn(message: string, payload?: Record<string, unknown>, endpoint?: string) {\n return this.send(\"warn\", message, payload, undefined, endpoint);\n }\n\n error(message: string, error?: Error, payload?: Record<string, unknown>, endpoint?: string) {\n return this.send(\"error\", message, payload, error, endpoint);\n }\n}\n\nexport const logger = new Logger();","import { initializeApp, getApps, FirebaseApp } from \"firebase/app\";\nimport { getFirestore, Firestore } from \"firebase/firestore\";\nimport { LoggerConfig } from \"../types\";\n\nlet app: FirebaseApp;\nlet db: Firestore;\n\nexport const initFirebase = (config: LoggerConfig) => {\n if (!getApps().length) {\n app = initializeApp(\n {\n apiKey: config.apiKey,\n authDomain: config.authDomain,\n projectId: config.projectId,\n storageBucket: config.storageBucket,\n messagingSenderId: config.messagingSenderId,\n appId: config.appId,\n },\n \"ga-logger\",\n );\n } else {\n app = getApps()[0];\n }\n\n db = getFirestore(app);\n return db;\n};\n\nexport const getDb = () => db;\n"],"mappings":"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","names":["db"]}
|