keystone-design-bootstrap 1.0.95 → 1.0.96
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/package.json +1 -1
- package/src/tracking/PostHogProvider.tsx +35 -0
- package/src/tracking/index.ts +2 -0
- package/src/tracking/logging.ts +123 -0
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import posthog from 'posthog-js';
|
|
|
4
4
|
import { PostHogProvider as PHProvider } from 'posthog-js/react';
|
|
5
5
|
import { useEffect, Suspense } from 'react';
|
|
6
6
|
import { usePathname, useSearchParams } from 'next/navigation';
|
|
7
|
+
import { error as logError } from './logging';
|
|
7
8
|
|
|
8
9
|
const DEFAULT_HOST = 'https://us.i.posthog.com';
|
|
9
10
|
|
|
@@ -125,6 +126,40 @@ export function PostHogProvider({ apiKey, apiHost, accountId, accountName, envir
|
|
|
125
126
|
});
|
|
126
127
|
}, [apiKey, apiHost, accountId, accountName, environment]);
|
|
127
128
|
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
const onWindowError = (event: ErrorEvent) => {
|
|
131
|
+
logError(
|
|
132
|
+
'global-client',
|
|
133
|
+
'WINDOW_ERROR',
|
|
134
|
+
{
|
|
135
|
+
message: event.message || 'unknown_error',
|
|
136
|
+
filename: event.filename || 'unknown_file',
|
|
137
|
+
lineno: event.lineno || 0,
|
|
138
|
+
colno: event.colno || 0,
|
|
139
|
+
stack: event.error instanceof Error ? event.error.stack || '' : '',
|
|
140
|
+
},
|
|
141
|
+
{ shipToPostHog: true },
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const onUnhandledRejection = (event: PromiseRejectionEvent) => {
|
|
146
|
+
const reason = event.reason;
|
|
147
|
+
const payload =
|
|
148
|
+
reason instanceof Error
|
|
149
|
+
? { message: reason.message, stack: reason.stack || '' }
|
|
150
|
+
: { message: String(reason), stack: '' };
|
|
151
|
+
|
|
152
|
+
logError('global-client', 'UNHANDLED_REJECTION', payload, { shipToPostHog: true });
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
window.addEventListener('error', onWindowError);
|
|
156
|
+
window.addEventListener('unhandledrejection', onUnhandledRejection);
|
|
157
|
+
return () => {
|
|
158
|
+
window.removeEventListener('error', onWindowError);
|
|
159
|
+
window.removeEventListener('unhandledrejection', onUnhandledRejection);
|
|
160
|
+
};
|
|
161
|
+
}, []);
|
|
162
|
+
|
|
128
163
|
return (
|
|
129
164
|
<PHProvider client={posthog}>
|
|
130
165
|
<Suspense fallback={null}>
|
package/src/tracking/index.ts
CHANGED
|
@@ -30,3 +30,5 @@ export { GoogleTagManager } from './GoogleTagManager';
|
|
|
30
30
|
export type { GoogleTagManagerProps } from './GoogleTagManager';
|
|
31
31
|
export { captureEvent, captureCustomEvent } from './captureEvent';
|
|
32
32
|
export type { KsEventName, KsEventProperties } from './captureEvent';
|
|
33
|
+
export { log, warn, error, CHANNEL_COLORS } from './logging';
|
|
34
|
+
export type { LogLevel, LogOptions } from './logging';
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { captureCustomEvent } from './captureEvent';
|
|
4
|
+
|
|
5
|
+
const BUILD_CONSOLE_DISABLED = process.env.NEXT_PUBLIC_LOGGING_DISABLED === '1';
|
|
6
|
+
const BUILD_POSTHOG_DISABLED = process.env.NEXT_PUBLIC_POSTHOG_LOGGING_DISABLED === '1';
|
|
7
|
+
const POSTHOG_LOG_EVENT = 'keystone_client_log';
|
|
8
|
+
|
|
9
|
+
interface LoggingWindow extends Window {
|
|
10
|
+
__loggingDisabled?: boolean;
|
|
11
|
+
__posthogLoggingDisabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type LogLevel = 'info' | 'warn' | 'error';
|
|
15
|
+
|
|
16
|
+
export type LogOptions = {
|
|
17
|
+
/** Send this log payload to PostHog (`keystone_client_log`). */
|
|
18
|
+
shipToPostHog?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Channel → accent colour. Unregistered channels fall through to gray.
|
|
23
|
+
*/
|
|
24
|
+
export const CHANNEL_COLORS: Record<string, string> = {
|
|
25
|
+
// Shared diagnostics
|
|
26
|
+
'global-client': '#d2a8ff',
|
|
27
|
+
|
|
28
|
+
// Section pins (desktop)
|
|
29
|
+
'every-channel-pin': '#9febd7',
|
|
30
|
+
'hero-pin': '#6ecc8b',
|
|
31
|
+
'pricing-pin': '#399587',
|
|
32
|
+
'product-screens-pin': '#4fafa0',
|
|
33
|
+
'social-proof-pin': '#ffbb8a',
|
|
34
|
+
'value-props-pin': '#e0a733',
|
|
35
|
+
'work-pin': '#f57e56',
|
|
36
|
+
|
|
37
|
+
// Section pins (mobile)
|
|
38
|
+
'mobile-every-channel-pin': '#7ed9c6',
|
|
39
|
+
'mobile-hero-pin': '#f0eee6',
|
|
40
|
+
'mobile-pricing-pin': '#80d4ff',
|
|
41
|
+
'mobile-product-screens-pin': '#3a9085',
|
|
42
|
+
'mobile-social-proof-pin': '#ffd580',
|
|
43
|
+
'mobile-value-props-pin': '#4fafa0',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function isConsoleEnabled(): boolean {
|
|
47
|
+
if (BUILD_CONSOLE_DISABLED) return false;
|
|
48
|
+
if (typeof window === 'undefined') return true;
|
|
49
|
+
return (window as LoggingWindow).__loggingDisabled !== true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isPostHogShippingEnabled(): boolean {
|
|
53
|
+
if (BUILD_POSTHOG_DISABLED) return false;
|
|
54
|
+
if (typeof window === 'undefined') return false;
|
|
55
|
+
return (window as LoggingWindow).__posthogLoggingDisabled !== true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function formatDetail(detail: Record<string, unknown>): string {
|
|
59
|
+
return Object.entries(detail)
|
|
60
|
+
.map(([k, v]) => `${k}=${typeof v === 'number' ? v.toFixed(4) : String(v)}`)
|
|
61
|
+
.join(' ');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function emitConsole(level: LogLevel, channel: string, event: string, detail: Record<string, unknown>): void {
|
|
65
|
+
const color = CHANNEL_COLORS[channel] ?? '#aaa';
|
|
66
|
+
const detailStr = formatDetail(detail);
|
|
67
|
+
const message = `%c[${channel}] %c${event}%c ${detailStr}`;
|
|
68
|
+
const channelStyle = `color:${color}; font-weight:bold`;
|
|
69
|
+
const eventStyle = level === 'error'
|
|
70
|
+
? 'color:#e94e4e; font-weight:bold'
|
|
71
|
+
: level === 'warn'
|
|
72
|
+
? 'color:#f5a623; font-weight:bold'
|
|
73
|
+
: 'color:#fff; font-weight:bold';
|
|
74
|
+
const detailStyle = 'color:#999; font-weight:normal';
|
|
75
|
+
|
|
76
|
+
if (level === 'error') {
|
|
77
|
+
console.error(message, channelStyle, eventStyle, detailStyle);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (level === 'warn') {
|
|
81
|
+
console.warn(message, channelStyle, eventStyle, detailStyle);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log(message, channelStyle, eventStyle, detailStyle);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function maybeShipToPostHog(
|
|
88
|
+
level: LogLevel,
|
|
89
|
+
channel: string,
|
|
90
|
+
event: string,
|
|
91
|
+
detail: Record<string, unknown>,
|
|
92
|
+
options?: LogOptions,
|
|
93
|
+
): void {
|
|
94
|
+
const shouldShip = options?.shipToPostHog ?? level !== 'info';
|
|
95
|
+
if (!shouldShip || !isPostHogShippingEnabled()) return;
|
|
96
|
+
|
|
97
|
+
captureCustomEvent(POSTHOG_LOG_EVENT, {
|
|
98
|
+
level,
|
|
99
|
+
channel,
|
|
100
|
+
event,
|
|
101
|
+
detail,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function emit(level: LogLevel, channel: string, event: string, detail: Record<string, unknown>, options?: LogOptions): void {
|
|
106
|
+
// Keep warn/error visible even when regular logs are muted.
|
|
107
|
+
if (level !== 'info' || isConsoleEnabled()) {
|
|
108
|
+
emitConsole(level, channel, event, detail);
|
|
109
|
+
}
|
|
110
|
+
maybeShipToPostHog(level, channel, event, detail, options);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function log(channel: string, event: string, detail: Record<string, unknown> = {}, options?: LogOptions): void {
|
|
114
|
+
emit('info', channel, event, detail, options);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function warn(channel: string, event: string, detail: Record<string, unknown> = {}, options?: LogOptions): void {
|
|
118
|
+
emit('warn', channel, event, detail, options);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function error(channel: string, event: string, detail: Record<string, unknown> = {}, options?: LogOptions): void {
|
|
122
|
+
emit('error', channel, event, detail, options);
|
|
123
|
+
}
|