datadog-frontend-toolkit 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.
Files changed (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +486 -0
  3. package/dist/cjs/context/ContextManager.js +197 -0
  4. package/dist/cjs/context/ContextManager.js.map +1 -0
  5. package/dist/cjs/core/BootstrapGuard.js +81 -0
  6. package/dist/cjs/core/BootstrapGuard.js.map +1 -0
  7. package/dist/cjs/core/ConfigManager.js +133 -0
  8. package/dist/cjs/core/ConfigManager.js.map +1 -0
  9. package/dist/cjs/core/ObservabilitySDK.js +355 -0
  10. package/dist/cjs/core/ObservabilitySDK.js.map +1 -0
  11. package/dist/cjs/errors/ErrorBoundary.js +187 -0
  12. package/dist/cjs/errors/ErrorBoundary.js.map +1 -0
  13. package/dist/cjs/index.js +110 -0
  14. package/dist/cjs/index.js.map +1 -0
  15. package/dist/cjs/logger/LoggerService.js +256 -0
  16. package/dist/cjs/logger/LoggerService.js.map +1 -0
  17. package/dist/cjs/logs/LogsManager.js +112 -0
  18. package/dist/cjs/logs/LogsManager.js.map +1 -0
  19. package/dist/cjs/network/NetworkInterceptor.js +185 -0
  20. package/dist/cjs/network/NetworkInterceptor.js.map +1 -0
  21. package/dist/cjs/performance/PerformanceMonitor.js +290 -0
  22. package/dist/cjs/performance/PerformanceMonitor.js.map +1 -0
  23. package/dist/cjs/resources/ResourceProvisioner.js +210 -0
  24. package/dist/cjs/resources/ResourceProvisioner.js.map +1 -0
  25. package/dist/cjs/resources/templates/dashboard.js +333 -0
  26. package/dist/cjs/resources/templates/dashboard.js.map +1 -0
  27. package/dist/cjs/resources/templates/monitors.js +120 -0
  28. package/dist/cjs/resources/templates/monitors.js.map +1 -0
  29. package/dist/cjs/resources/templates/slos.js +79 -0
  30. package/dist/cjs/resources/templates/slos.js.map +1 -0
  31. package/dist/cjs/rum/RumManager.js +164 -0
  32. package/dist/cjs/rum/RumManager.js.map +1 -0
  33. package/dist/cjs/types/config.js +13 -0
  34. package/dist/cjs/types/config.js.map +1 -0
  35. package/dist/cjs/types/events.js +26 -0
  36. package/dist/cjs/types/events.js.map +1 -0
  37. package/dist/cjs/types/index.js +20 -0
  38. package/dist/cjs/types/index.js.map +1 -0
  39. package/dist/cjs/types/logger.js +13 -0
  40. package/dist/cjs/types/logger.js.map +1 -0
  41. package/dist/cjs/utils/EventEmitter.js +49 -0
  42. package/dist/cjs/utils/EventEmitter.js.map +1 -0
  43. package/dist/cjs/utils/fingerprint.js +48 -0
  44. package/dist/cjs/utils/fingerprint.js.map +1 -0
  45. package/dist/cjs/utils/retry.js +35 -0
  46. package/dist/cjs/utils/retry.js.map +1 -0
  47. package/dist/cjs/utils/sanitizer.js +106 -0
  48. package/dist/cjs/utils/sanitizer.js.map +1 -0
  49. package/dist/cjs/utils/storage.js +99 -0
  50. package/dist/cjs/utils/storage.js.map +1 -0
  51. package/dist/cli/commands/setup.js +178 -0
  52. package/dist/cli/commands/setup.js.map +1 -0
  53. package/dist/cli/commands/status.js +103 -0
  54. package/dist/cli/commands/status.js.map +1 -0
  55. package/dist/cli/index.js +111 -0
  56. package/dist/cli/index.js.map +1 -0
  57. package/dist/cli/prompt.js +140 -0
  58. package/dist/cli/prompt.js.map +1 -0
  59. package/dist/esm/context/ContextManager.js +193 -0
  60. package/dist/esm/context/ContextManager.js.map +1 -0
  61. package/dist/esm/core/BootstrapGuard.js +77 -0
  62. package/dist/esm/core/BootstrapGuard.js.map +1 -0
  63. package/dist/esm/core/ConfigManager.js +129 -0
  64. package/dist/esm/core/ConfigManager.js.map +1 -0
  65. package/dist/esm/core/ObservabilitySDK.js +351 -0
  66. package/dist/esm/core/ObservabilitySDK.js.map +1 -0
  67. package/dist/esm/errors/ErrorBoundary.js +183 -0
  68. package/dist/esm/errors/ErrorBoundary.js.map +1 -0
  69. package/dist/esm/index.js +87 -0
  70. package/dist/esm/index.js.map +1 -0
  71. package/dist/esm/logger/LoggerService.js +251 -0
  72. package/dist/esm/logger/LoggerService.js.map +1 -0
  73. package/dist/esm/logs/LogsManager.js +108 -0
  74. package/dist/esm/logs/LogsManager.js.map +1 -0
  75. package/dist/esm/network/NetworkInterceptor.js +181 -0
  76. package/dist/esm/network/NetworkInterceptor.js.map +1 -0
  77. package/dist/esm/performance/PerformanceMonitor.js +286 -0
  78. package/dist/esm/performance/PerformanceMonitor.js.map +1 -0
  79. package/dist/esm/resources/ResourceProvisioner.js +206 -0
  80. package/dist/esm/resources/ResourceProvisioner.js.map +1 -0
  81. package/dist/esm/resources/templates/dashboard.js +330 -0
  82. package/dist/esm/resources/templates/dashboard.js.map +1 -0
  83. package/dist/esm/resources/templates/monitors.js +117 -0
  84. package/dist/esm/resources/templates/monitors.js.map +1 -0
  85. package/dist/esm/resources/templates/slos.js +76 -0
  86. package/dist/esm/resources/templates/slos.js.map +1 -0
  87. package/dist/esm/rum/RumManager.js +160 -0
  88. package/dist/esm/rum/RumManager.js.map +1 -0
  89. package/dist/esm/types/config.js +10 -0
  90. package/dist/esm/types/config.js.map +1 -0
  91. package/dist/esm/types/events.js +23 -0
  92. package/dist/esm/types/events.js.map +1 -0
  93. package/dist/esm/types/index.js +4 -0
  94. package/dist/esm/types/index.js.map +1 -0
  95. package/dist/esm/types/logger.js +10 -0
  96. package/dist/esm/types/logger.js.map +1 -0
  97. package/dist/esm/utils/EventEmitter.js +45 -0
  98. package/dist/esm/utils/EventEmitter.js.map +1 -0
  99. package/dist/esm/utils/fingerprint.js +44 -0
  100. package/dist/esm/utils/fingerprint.js.map +1 -0
  101. package/dist/esm/utils/retry.js +32 -0
  102. package/dist/esm/utils/retry.js.map +1 -0
  103. package/dist/esm/utils/sanitizer.js +102 -0
  104. package/dist/esm/utils/sanitizer.js.map +1 -0
  105. package/dist/esm/utils/storage.js +95 -0
  106. package/dist/esm/utils/storage.js.map +1 -0
  107. package/dist/resources/ResourceProvisioner.js +207 -0
  108. package/dist/resources/ResourceProvisioner.js.map +1 -0
  109. package/dist/resources/templates/dashboard.js +333 -0
  110. package/dist/resources/templates/dashboard.js.map +1 -0
  111. package/dist/resources/templates/monitors.js +120 -0
  112. package/dist/resources/templates/monitors.js.map +1 -0
  113. package/dist/resources/templates/slos.js +79 -0
  114. package/dist/resources/templates/slos.js.map +1 -0
  115. package/dist/types/config.js +13 -0
  116. package/dist/types/config.js.map +1 -0
  117. package/dist/types/context/ContextManager.d.ts +63 -0
  118. package/dist/types/context/ContextManager.d.ts.map +1 -0
  119. package/dist/types/core/BootstrapGuard.d.ts +46 -0
  120. package/dist/types/core/BootstrapGuard.d.ts.map +1 -0
  121. package/dist/types/core/ConfigManager.d.ts +13 -0
  122. package/dist/types/core/ConfigManager.d.ts.map +1 -0
  123. package/dist/types/core/ObservabilitySDK.d.ts +141 -0
  124. package/dist/types/core/ObservabilitySDK.d.ts.map +1 -0
  125. package/dist/types/errors/ErrorBoundary.d.ts +55 -0
  126. package/dist/types/errors/ErrorBoundary.d.ts.map +1 -0
  127. package/dist/types/events.js +26 -0
  128. package/dist/types/events.js.map +1 -0
  129. package/dist/types/index.d.ts +75 -0
  130. package/dist/types/index.d.ts.map +1 -0
  131. package/dist/types/index.js +20 -0
  132. package/dist/types/index.js.map +1 -0
  133. package/dist/types/logger/LoggerService.d.ts +104 -0
  134. package/dist/types/logger/LoggerService.d.ts.map +1 -0
  135. package/dist/types/logger.js +13 -0
  136. package/dist/types/logger.js.map +1 -0
  137. package/dist/types/logs/LogsManager.d.ts +41 -0
  138. package/dist/types/logs/LogsManager.d.ts.map +1 -0
  139. package/dist/types/network/NetworkInterceptor.d.ts +35 -0
  140. package/dist/types/network/NetworkInterceptor.d.ts.map +1 -0
  141. package/dist/types/performance/PerformanceMonitor.d.ts +44 -0
  142. package/dist/types/performance/PerformanceMonitor.d.ts.map +1 -0
  143. package/dist/types/resources/ResourceProvisioner.d.ts +46 -0
  144. package/dist/types/resources/ResourceProvisioner.d.ts.map +1 -0
  145. package/dist/types/resources/templates/dashboard.d.ts +6 -0
  146. package/dist/types/resources/templates/dashboard.d.ts.map +1 -0
  147. package/dist/types/resources/templates/monitors.d.ts +11 -0
  148. package/dist/types/resources/templates/monitors.d.ts.map +1 -0
  149. package/dist/types/resources/templates/slos.d.ts +18 -0
  150. package/dist/types/resources/templates/slos.d.ts.map +1 -0
  151. package/dist/types/rum/RumManager.d.ts +70 -0
  152. package/dist/types/rum/RumManager.d.ts.map +1 -0
  153. package/dist/types/types/config.d.ts +271 -0
  154. package/dist/types/types/config.d.ts.map +1 -0
  155. package/dist/types/types/events.d.ts +71 -0
  156. package/dist/types/types/events.d.ts.map +1 -0
  157. package/dist/types/types/index.d.ts +4 -0
  158. package/dist/types/types/index.d.ts.map +1 -0
  159. package/dist/types/types/logger.d.ts +102 -0
  160. package/dist/types/types/logger.d.ts.map +1 -0
  161. package/dist/types/utils/EventEmitter.d.ts +14 -0
  162. package/dist/types/utils/EventEmitter.d.ts.map +1 -0
  163. package/dist/types/utils/fingerprint.d.ts +10 -0
  164. package/dist/types/utils/fingerprint.d.ts.map +1 -0
  165. package/dist/types/utils/retry.d.ts +9 -0
  166. package/dist/types/utils/retry.d.ts.map +1 -0
  167. package/dist/types/utils/sanitizer.d.ts +14 -0
  168. package/dist/types/utils/sanitizer.d.ts.map +1 -0
  169. package/dist/types/utils/storage.d.ts +17 -0
  170. package/dist/types/utils/storage.d.ts.map +1 -0
  171. package/dist/utils/retry.js +35 -0
  172. package/dist/utils/retry.js.map +1 -0
  173. package/package.json +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,486 @@
1
+ # datadog-frontend-toolkit
2
+
3
+ > Enterprise-grade, framework-agnostic frontend observability toolkit for Datadog.
4
+
5
+ One `init()` call to auto-instrument **RUM**, **Logs**, **Error Tracking**, **Performance Monitoring**, and auto-provision **Dashboards**, **Monitors** & **SLOs** in Datadog.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - **Zero-config observability** — single `init()` bootstraps everything
12
+ - **Framework agnostic** — works with React, Vue, Angular, Svelte, vanilla JS
13
+ - **Full TypeScript support** — complete type declarations and IntelliSense
14
+ - **Structured LoggerService** — `debug`, `info`, `warn`, `error`, `critical` with auto-forwarding to Datadog
15
+ - **Global Error Boundary** — catches unhandled errors + promise rejections automatically
16
+ - **Web Vitals tracking** — LCP, CLS, FID, INP, FCP, TTFB with threshold alerts
17
+ - **Network interception** — monitors XHR/Fetch for failures and slow requests
18
+ - **PII sanitization** — auto-redacts emails, credit cards, passwords from logs
19
+ - **Resource provisioning CLI** — auto-creates Dashboards, Monitors, and SLOs
20
+ - **Plugin system** — extend with custom integrations
21
+ - **Lifecycle hooks** — `beforeInit`, `afterInit`, `beforeLog`, `beforeError`
22
+ - **Child loggers** — scoped context for module-specific logging
23
+ - **Session replay** — configurable recording with privacy controls
24
+ - **Consent mode** — GDPR-friendly opt-in tracking
25
+ - **Retry with backoff** — resilient API communication
26
+ - **Throttling** — prevents log flooding during error storms
27
+
28
+ ---
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ npm install datadog-frontend-toolkit
34
+ ```
35
+
36
+ > `@datadog/browser-rum` and `@datadog/browser-logs` are included as dependencies — no need to install them separately.
37
+
38
+ ---
39
+
40
+ ## Quick Start
41
+
42
+ ```typescript
43
+ import { init } from 'datadog-frontend-toolkit';
44
+
45
+ const observatory = init({
46
+ clientToken: 'pub-xxxxxxxxxxxxxxxxxxxx',
47
+ applicationId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
48
+ service: 'my-frontend-app',
49
+ env: 'production',
50
+ version: '1.2.3',
51
+ });
52
+
53
+ // That's it! RUM, Logs, Error Tracking, and Performance Monitoring are now active.
54
+
55
+ // Use the logger anywhere
56
+ observatory.logger.info('Application started');
57
+ observatory.logger.error('Payment failed', new Error('timeout'), { orderId: 'abc-123' });
58
+ ```
59
+
60
+ ---
61
+
62
+ ## API Reference
63
+
64
+ ### `init(config): ObservabilitySDK`
65
+
66
+ Initializes the SDK. Call once at application bootstrap.
67
+
68
+ ```typescript
69
+ import { init } from 'datadog-frontend-toolkit';
70
+
71
+ const observatory = init({
72
+ // Required
73
+ clientToken: 'pub-xxx',
74
+ applicationId: 'xxx-xxx',
75
+ service: 'my-app',
76
+ env: 'production',
77
+
78
+ // Optional
79
+ version: '1.0.0',
80
+ site: 'datadoghq.com',
81
+ debug: false,
82
+ logLevel: 'warn',
83
+
84
+ // Sampling
85
+ sampling: {
86
+ sessionSampleRate: 100,
87
+ sessionReplaySampleRate: 20,
88
+ traceSampleRate: 100,
89
+ },
90
+
91
+ // Error tracking
92
+ errorTracking: {
93
+ enabled: true,
94
+ unhandledRejections: true,
95
+ consoleErrors: true,
96
+ ignorePatterns: ['ResizeObserver loop'],
97
+ maxErrorsPerMinute: 100,
98
+ },
99
+
100
+ // Performance
101
+ performance: {
102
+ webVitals: true,
103
+ longTasks: true,
104
+ resourceTiming: true,
105
+ },
106
+
107
+ // Network
108
+ network: {
109
+ enabled: true,
110
+ excludeUrls: [/analytics/, 'hotjar.com'],
111
+ failedOnly: false,
112
+ },
113
+
114
+ // Privacy
115
+ privacy: {
116
+ defaultPrivacyLevel: 'mask-user-input',
117
+ piiFields: ['ssn', 'dob'],
118
+ requireConsent: false,
119
+ },
120
+
121
+ // User context
122
+ user: {
123
+ id: 'user-123',
124
+ name: 'John Doe',
125
+ email: 'john@example.com',
126
+ plan: 'enterprise',
127
+ },
128
+
129
+ // Global context for all events
130
+ globalContext: {
131
+ team: 'frontend',
132
+ region: 'us-east-1',
133
+ },
134
+
135
+ tags: ['team:frontend', 'product:checkout'],
136
+
137
+ // APM correlation
138
+ allowedTracingUrls: ['https://api.myapp.com'],
139
+
140
+ // Lifecycle hooks
141
+ hooks: {
142
+ beforeLog: (level, message) => {
143
+ // Return false to skip this log
144
+ return !message.includes('noisy-module');
145
+ },
146
+ afterInit: () => {
147
+ console.log('Observability ready!');
148
+ },
149
+ },
150
+ });
151
+ ```
152
+
153
+ ### Logger
154
+
155
+ ```typescript
156
+ const logger = observatory.logger;
157
+
158
+ // Standard levels
159
+ logger.debug('Detailed info for development');
160
+ logger.info('User signed in', { userId: '123' });
161
+ logger.warn('Deprecation notice', { feature: 'old-api' });
162
+ logger.error('Request failed', new Error('500'), { endpoint: '/api/users' });
163
+ logger.critical('Database unreachable', new Error('ECONNREFUSED'));
164
+
165
+ // Timed operations
166
+ const result = await logger.time('fetchUsers', async () => {
167
+ return await fetch('/api/users');
168
+ });
169
+
170
+ // Child loggers with scoped context
171
+ const authLogger = logger.child({ module: 'auth' });
172
+ authLogger.info('Login attempt'); // includes { module: 'auth' } in every log
173
+
174
+ // Scoped context
175
+ logger.setContext({ requestId: 'req-456' });
176
+ logger.info('Processing'); // includes requestId in context
177
+ logger.clearContext();
178
+ ```
179
+
180
+ ### User Context
181
+
182
+ ```typescript
183
+ // Set user after login
184
+ observatory.setUser({
185
+ id: 'user-123',
186
+ name: 'Jane Doe',
187
+ email: 'jane@example.com',
188
+ plan: 'enterprise',
189
+ });
190
+
191
+ // Clear on logout
192
+ observatory.clearUser();
193
+ ```
194
+
195
+ ### SPA View Tracking
196
+
197
+ ```typescript
198
+ // Call on route change
199
+ observatory.setView('/dashboard');
200
+ observatory.setView('/settings/profile');
201
+ ```
202
+
203
+ ### Custom Actions
204
+
205
+ ```typescript
206
+ observatory.trackAction('add_to_cart', {
207
+ productId: 'prod-456',
208
+ price: 29.99,
209
+ currency: 'USD',
210
+ });
211
+ ```
212
+
213
+ ### Error Capture
214
+
215
+ ```typescript
216
+ try {
217
+ await riskyOperation();
218
+ } catch (error) {
219
+ observatory.captureError(error, {
220
+ operation: 'riskyOperation',
221
+ userId: 'user-123',
222
+ });
223
+ }
224
+
225
+ // Capture a message
226
+ observatory.captureMessage('Feature flag evaluation failed', {
227
+ flag: 'new-checkout',
228
+ });
229
+ ```
230
+
231
+ ### Performance Marks
232
+
233
+ ```typescript
234
+ observatory.mark('checkout-start');
235
+ // ... checkout logic ...
236
+ observatory.mark('checkout-end');
237
+ const duration = observatory.measure('checkout', 'checkout-start', 'checkout-end');
238
+ ```
239
+
240
+ ### Session Replay
241
+
242
+ ```typescript
243
+ observatory.startSessionReplay();
244
+ observatory.stopSessionReplay();
245
+ ```
246
+
247
+ ### Global Context
248
+
249
+ ```typescript
250
+ observatory.addGlobalContext('tenant', 'acme-corp');
251
+ observatory.removeGlobalContext('tenant');
252
+ ```
253
+
254
+ ### Events
255
+
256
+ ```typescript
257
+ import { SDKEvent } from 'datadog-frontend-toolkit';
258
+
259
+ observatory.onEvent(SDKEvent.ERROR_CAPTURED, (payload) => {
260
+ console.log('Error captured:', payload.data);
261
+ });
262
+
263
+ observatory.onEvent(SDKEvent.PERFORMANCE_ENTRY, (payload) => {
264
+ console.log('Web Vital:', payload.data);
265
+ });
266
+ ```
267
+
268
+ ### Global Access
269
+
270
+ ```typescript
271
+ // From anywhere in your app
272
+ import { getInstance, getLogger } from 'datadog-frontend-toolkit';
273
+
274
+ const sdk = getInstance(); // returns null if not initialized
275
+ const logger = getLogger(); // throws if not initialized
276
+ ```
277
+
278
+ ### Destroy
279
+
280
+ ```typescript
281
+ await observatory.destroy(); // Cleans up all handlers
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Plugins
287
+
288
+ ```typescript
289
+ import { init, ObservabilityPlugin } from 'datadog-frontend-toolkit';
290
+
291
+ const myPlugin: ObservabilityPlugin = {
292
+ name: 'my-custom-plugin',
293
+ version: '1.0.0',
294
+ setup(sdk) {
295
+ sdk.addGlobalContext('plugin', 'active');
296
+ sdk.onEvent('sdk:error_captured', (payload) => {
297
+ // Custom error processing
298
+ });
299
+ },
300
+ teardown() {
301
+ // Cleanup
302
+ },
303
+ };
304
+
305
+ init({
306
+ clientToken: '...',
307
+ applicationId: '...',
308
+ service: 'my-app',
309
+ env: 'production',
310
+ plugins: [myPlugin],
311
+ });
312
+ ```
313
+
314
+ ---
315
+
316
+ ## CLI — Resource Provisioning
317
+
318
+ The CLI provisions Datadog resources (dashboards, monitors, SLOs) for your service automatically.
319
+
320
+ > **Note:** This uses Datadog API/App keys and runs server-side only. Never expose these keys in the browser.
321
+
322
+ ### Setup Resources
323
+
324
+ ```bash
325
+ # Using CLI arguments
326
+ npx dd-toolkit setup \
327
+ --service my-app \
328
+ --env production \
329
+ --api-key $DD_API_KEY \
330
+ --app-key $DD_APP_KEY \
331
+ --team frontend
332
+
333
+ # Using environment variables
334
+ export DD_API_KEY=your-api-key
335
+ export DD_APP_KEY=your-app-key
336
+ npx dd-toolkit setup -s my-app -e production
337
+
338
+ # Dry run (preview only)
339
+ npx dd-toolkit setup -s my-app -e production --dry-run
340
+
341
+ # Skip specific resources
342
+ npx dd-toolkit setup -s my-app -e production --no-slos
343
+ ```
344
+
345
+ ### Check Status
346
+
347
+ ```bash
348
+ npx dd-toolkit status -s my-app -e production
349
+ ```
350
+
351
+ ### What Gets Provisioned
352
+
353
+ **Dashboard:**
354
+ - Frontend Observability overview with RUM metrics, Web Vitals, error tracking, and performance panels
355
+
356
+ **Monitors (6):**
357
+ - High Frontend Error Rate (>50 errors/5min)
358
+ - Poor LCP Performance (p75 > 4s)
359
+ - High CLS Score (p75 > 0.25)
360
+ - JS Error Spike (>100 errors/5min)
361
+ - Error Log Anomaly (>200 error logs/15min)
362
+ - Poor INP Performance (p75 > 500ms)
363
+
364
+ **SLOs (4):**
365
+ - Frontend Availability (99.5% target)
366
+ - LCP Performance (75% good threshold)
367
+ - INP Performance (75% good threshold)
368
+ - CLS Performance (75% good threshold)
369
+
370
+ ---
371
+
372
+ ## Framework Examples
373
+
374
+ ### React
375
+
376
+ ```typescript
377
+ // src/index.tsx
378
+ import { init } from 'datadog-frontend-toolkit';
379
+
380
+ const observatory = init({
381
+ clientToken: process.env.REACT_APP_DD_CLIENT_TOKEN!,
382
+ applicationId: process.env.REACT_APP_DD_APP_ID!,
383
+ service: 'react-app',
384
+ env: process.env.NODE_ENV,
385
+ version: process.env.REACT_APP_VERSION,
386
+ });
387
+
388
+ export { observatory };
389
+ ```
390
+
391
+ ### Vue
392
+
393
+ ```typescript
394
+ // src/main.ts
395
+ import { init } from 'datadog-frontend-toolkit';
396
+
397
+ const observatory = init({
398
+ clientToken: import.meta.env.VITE_DD_CLIENT_TOKEN,
399
+ applicationId: import.meta.env.VITE_DD_APP_ID,
400
+ service: 'vue-app',
401
+ env: import.meta.env.MODE,
402
+ });
403
+
404
+ app.config.errorHandler = (err) => {
405
+ observatory.captureError(err instanceof Error ? err : new Error(String(err)));
406
+ };
407
+ ```
408
+
409
+ ### Angular
410
+
411
+ ```typescript
412
+ // src/main.ts
413
+ import { init } from 'datadog-frontend-toolkit';
414
+
415
+ init({
416
+ clientToken: environment.ddClientToken,
417
+ applicationId: environment.ddAppId,
418
+ service: 'angular-app',
419
+ env: environment.production ? 'production' : 'development',
420
+ });
421
+ ```
422
+
423
+ ### Next.js
424
+
425
+ ```typescript
426
+ // src/lib/observability.ts
427
+ import { init } from 'datadog-frontend-toolkit';
428
+
429
+ export const observatory =
430
+ typeof window !== 'undefined'
431
+ ? init({
432
+ clientToken: process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN!,
433
+ applicationId: process.env.NEXT_PUBLIC_DD_APP_ID!,
434
+ service: 'nextjs-app',
435
+ env: process.env.NODE_ENV,
436
+ })
437
+ : null;
438
+ ```
439
+
440
+ ---
441
+
442
+ ## Architecture
443
+
444
+ ```
445
+ ┌─────────────────────────────────────────────────┐
446
+ │ init(config) │
447
+ │ ObservabilitySDK │
448
+ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
449
+ │ │ RUM │ │ Logs │ │ Logger │ │
450
+ │ │ Manager │ │ Manager │ │ Service │ │
451
+ │ └──────────┘ └──────────┘ └───────────────┘ │
452
+ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
453
+ │ │ Error │ │ Perf │ │ Network │ │
454
+ │ │ Boundary │ │ Monitor │ │ Interceptor │ │
455
+ │ └──────────┘ └──────────┘ └───────────────┘ │
456
+ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
457
+ │ │ Context │ │ Bootstrap│ │ Event │ │
458
+ │ │ Manager │ │ Guard │ │ Emitter │ │
459
+ │ └──────────┘ └──────────┘ └───────────────┘ │
460
+ └─────────────────────────────────────────────────┘
461
+
462
+ ▼ (CLI only, server-side)
463
+ ┌─────────────────────────────────────────────────┐
464
+ │ Resource Provisioner │
465
+ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │
466
+ │ │Dashboard │ │ Monitor │ │ SLO │ │
467
+ │ │Templates │ │Templates │ │ Templates │ │
468
+ │ └──────────┘ └──────────┘ └───────────────┘ │
469
+ └─────────────────────────────────────────────────┘
470
+ ```
471
+
472
+ **Design Patterns Used:**
473
+ - **Singleton** — SDK instance management
474
+ - **Facade** — Single entry point for all features
475
+ - **Observer** — Event system for loose coupling
476
+ - **Adapter** — Log level normalization
477
+ - **Builder** — Configuration resolution
478
+ - **Chain of Responsibility** — Error processing pipeline
479
+ - **Proxy/Decorator** — Network interception
480
+ - **Template Method** — Resource provisioning
481
+
482
+ ---
483
+
484
+ ## License
485
+
486
+ MIT
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContextManager = void 0;
4
+ const events_1 = require("../types/events");
5
+ /**
6
+ * Centralized context management for enriching all events with
7
+ * browser, user, session, and application metadata.
8
+ * Implements the Mediator pattern to share context across modules.
9
+ */
10
+ class ContextManager {
11
+ globalContext;
12
+ userContext;
13
+ config;
14
+ emitter;
15
+ viewName;
16
+ cachedBrowserInfo;
17
+ constructor(config, emitter) {
18
+ this.config = config;
19
+ this.emitter = emitter;
20
+ this.globalContext = { ...config.globalContext };
21
+ this.userContext = config.user ? { ...config.user } : undefined;
22
+ }
23
+ /**
24
+ * Returns the full context snapshot to attach to logs and events.
25
+ */
26
+ getFullContext() {
27
+ return {
28
+ ...this.globalContext,
29
+ service: this.config.service,
30
+ env: this.config.env,
31
+ version: this.config.version,
32
+ url: this.getCurrentUrl(),
33
+ view: this.viewName,
34
+ browser: this.getBrowserInfo(),
35
+ user: this.userContext,
36
+ tags: this.config.tags,
37
+ timestamp: new Date().toISOString(),
38
+ };
39
+ }
40
+ /**
41
+ * Returns only the global context (without browser info).
42
+ */
43
+ getGlobalContext() {
44
+ return { ...this.globalContext };
45
+ }
46
+ /**
47
+ * Sets a key-value pair in the global context.
48
+ */
49
+ setGlobalContext(key, value) {
50
+ this.globalContext[key] = value;
51
+ this.emitter.emit(events_1.SDKEvent.CONTEXT_UPDATED, {
52
+ type: events_1.SDKEvent.CONTEXT_UPDATED,
53
+ timestamp: Date.now(),
54
+ data: { key, value },
55
+ });
56
+ }
57
+ /**
58
+ * Removes a key from the global context.
59
+ */
60
+ removeGlobalContext(key) {
61
+ delete this.globalContext[key];
62
+ this.emitter.emit(events_1.SDKEvent.CONTEXT_UPDATED, {
63
+ type: events_1.SDKEvent.CONTEXT_UPDATED,
64
+ timestamp: Date.now(),
65
+ data: { key, removed: true },
66
+ });
67
+ }
68
+ /**
69
+ * Sets user context.
70
+ */
71
+ setUser(user) {
72
+ this.userContext = { ...user };
73
+ this.emitter.emit(events_1.SDKEvent.USER_SET, {
74
+ type: events_1.SDKEvent.USER_SET,
75
+ timestamp: Date.now(),
76
+ data: { userId: user.id },
77
+ });
78
+ }
79
+ /**
80
+ * Clears user context.
81
+ */
82
+ clearUser() {
83
+ this.userContext = undefined;
84
+ }
85
+ /**
86
+ * Gets current user context.
87
+ */
88
+ getUser() {
89
+ return this.userContext ? { ...this.userContext } : undefined;
90
+ }
91
+ /**
92
+ * Sets the current view/route name.
93
+ */
94
+ setView(name) {
95
+ this.viewName = name;
96
+ this.emitter.emit(events_1.SDKEvent.VIEW_CHANGED, {
97
+ type: events_1.SDKEvent.VIEW_CHANGED,
98
+ timestamp: Date.now(),
99
+ data: { view: name },
100
+ });
101
+ }
102
+ /**
103
+ * Gets the current view/route name.
104
+ */
105
+ getView() {
106
+ return this.viewName;
107
+ }
108
+ /**
109
+ * Collects browser and device information.
110
+ * Cached after first call since these values rarely change.
111
+ */
112
+ getBrowserInfo() {
113
+ if (this.cachedBrowserInfo) {
114
+ return {
115
+ ...this.cachedBrowserInfo,
116
+ online: typeof navigator !== 'undefined' ? navigator.onLine : true,
117
+ };
118
+ }
119
+ if (typeof window === 'undefined' || typeof navigator === 'undefined') {
120
+ return this.getSSRBrowserInfo();
121
+ }
122
+ this.cachedBrowserInfo = {
123
+ userAgent: navigator.userAgent,
124
+ language: navigator.language,
125
+ platform: navigator.platform ?? 'unknown',
126
+ vendor: navigator.vendor ?? 'unknown',
127
+ cookieEnabled: navigator.cookieEnabled,
128
+ online: navigator.onLine,
129
+ screenResolution: `${screen.width}x${screen.height}`,
130
+ viewportSize: `${window.innerWidth}x${window.innerHeight}`,
131
+ devicePixelRatio: window.devicePixelRatio,
132
+ colorDepth: screen.colorDepth,
133
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
134
+ memory: this.getMemoryInfo(),
135
+ connection: this.getConnectionInfo(),
136
+ };
137
+ return { ...this.cachedBrowserInfo };
138
+ }
139
+ getCurrentUrl() {
140
+ try {
141
+ return typeof window !== 'undefined' ? window.location.href : 'unknown';
142
+ }
143
+ catch {
144
+ return 'unknown';
145
+ }
146
+ }
147
+ getMemoryInfo() {
148
+ try {
149
+ const perf = performance;
150
+ if (perf.memory) {
151
+ return {
152
+ jsHeapSizeLimit: perf.memory.jsHeapSizeLimit,
153
+ totalJSHeapSize: perf.memory.totalJSHeapSize,
154
+ usedJSHeapSize: perf.memory.usedJSHeapSize,
155
+ };
156
+ }
157
+ }
158
+ catch {
159
+ // Not available
160
+ }
161
+ return undefined;
162
+ }
163
+ getConnectionInfo() {
164
+ try {
165
+ const nav = navigator;
166
+ if (nav.connection) {
167
+ return {
168
+ effectiveType: nav.connection.effectiveType,
169
+ downlink: nav.connection.downlink,
170
+ rtt: nav.connection.rtt,
171
+ saveData: nav.connection.saveData,
172
+ };
173
+ }
174
+ }
175
+ catch {
176
+ // Not available
177
+ }
178
+ return undefined;
179
+ }
180
+ getSSRBrowserInfo() {
181
+ return {
182
+ userAgent: 'ssr',
183
+ language: 'en',
184
+ platform: 'server',
185
+ vendor: 'unknown',
186
+ cookieEnabled: false,
187
+ online: true,
188
+ screenResolution: '0x0',
189
+ viewportSize: '0x0',
190
+ devicePixelRatio: 1,
191
+ colorDepth: 0,
192
+ timezone: 'UTC',
193
+ };
194
+ }
195
+ }
196
+ exports.ContextManager = ContextManager;
197
+ //# sourceMappingURL=ContextManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContextManager.js","sourceRoot":"","sources":["../../../src/context/ContextManager.ts"],"names":[],"mappings":"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"}