@thisbefine/analytics 0.1.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +403 -0
  3. package/dist/core/analytics.d.ts +123 -0
  4. package/dist/core/analytics.d.ts.map +1 -0
  5. package/dist/core/analytics.js +334 -0
  6. package/dist/core/analytics.js.map +1 -0
  7. package/dist/core/errors.d.ts +94 -0
  8. package/dist/core/errors.d.ts.map +1 -0
  9. package/dist/core/errors.js +420 -0
  10. package/dist/core/errors.js.map +1 -0
  11. package/dist/core/logger.d.ts +28 -0
  12. package/dist/core/logger.d.ts.map +1 -0
  13. package/dist/core/logger.js +36 -0
  14. package/dist/core/logger.js.map +1 -0
  15. package/dist/core/logging.d.ts +12 -0
  16. package/dist/core/logging.d.ts.map +1 -0
  17. package/dist/core/logging.js +33 -0
  18. package/dist/core/logging.js.map +1 -0
  19. package/dist/core/privacy.d.ts +53 -0
  20. package/dist/core/privacy.d.ts.map +1 -0
  21. package/dist/core/privacy.js +94 -0
  22. package/dist/core/privacy.js.map +1 -0
  23. package/dist/core/queue.d.ts +59 -0
  24. package/dist/core/queue.d.ts.map +1 -0
  25. package/dist/core/queue.js +263 -0
  26. package/dist/core/queue.js.map +1 -0
  27. package/dist/core/session.d.ts +90 -0
  28. package/dist/core/session.d.ts.map +1 -0
  29. package/dist/core/session.js +246 -0
  30. package/dist/core/session.js.map +1 -0
  31. package/dist/core/storage.d.ts +64 -0
  32. package/dist/core/storage.d.ts.map +1 -0
  33. package/dist/core/storage.js +242 -0
  34. package/dist/core/storage.js.map +1 -0
  35. package/dist/core/types.d.ts +298 -0
  36. package/dist/core/types.d.ts.map +1 -0
  37. package/dist/core/types.js +34 -0
  38. package/dist/core/types.js.map +1 -0
  39. package/dist/core/validation.d.ts +11 -0
  40. package/dist/core/validation.d.ts.map +1 -0
  41. package/dist/core/validation.js +82 -0
  42. package/dist/core/validation.js.map +1 -0
  43. package/dist/core/version.d.ts +2 -0
  44. package/dist/core/version.d.ts.map +1 -0
  45. package/dist/core/version.js +4 -0
  46. package/dist/core/version.js.map +1 -0
  47. package/dist/index.d.ts +45 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +41 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/next/analytics.d.ts +59 -0
  52. package/dist/next/analytics.d.ts.map +1 -0
  53. package/dist/next/analytics.js +87 -0
  54. package/dist/next/analytics.js.map +1 -0
  55. package/dist/next.d.ts +46 -0
  56. package/dist/next.d.ts.map +1 -0
  57. package/dist/next.js +44 -0
  58. package/dist/next.js.map +1 -0
  59. package/dist/react/analytics.d.ts +51 -0
  60. package/dist/react/analytics.d.ts.map +1 -0
  61. package/dist/react/analytics.js +63 -0
  62. package/dist/react/analytics.js.map +1 -0
  63. package/dist/react/bug-report-widget.d.ts +21 -0
  64. package/dist/react/bug-report-widget.d.ts.map +1 -0
  65. package/dist/react/bug-report-widget.js +34 -0
  66. package/dist/react/bug-report-widget.js.map +1 -0
  67. package/dist/react/hooks.d.ts +141 -0
  68. package/dist/react/hooks.d.ts.map +1 -0
  69. package/dist/react/hooks.js +186 -0
  70. package/dist/react/hooks.js.map +1 -0
  71. package/dist/react.d.ts +42 -0
  72. package/dist/react.d.ts.map +1 -0
  73. package/dist/react.js +39 -0
  74. package/dist/react.js.map +1 -0
  75. package/dist/widget/bug-report.d.ts +16 -0
  76. package/dist/widget/bug-report.d.ts.map +1 -0
  77. package/dist/widget/bug-report.js +416 -0
  78. package/dist/widget/bug-report.js.map +1 -0
  79. package/package.json +107 -0
@@ -0,0 +1,416 @@
1
+ const BUG_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 256 256"><path d="M144,92a12,12,0,1,1,12,12A12,12,0,0,1,144,92ZM100,104a12,12,0,1,0-12-12A12,12,0,0,0,100,104Zm136,24a8,8,0,0,1-8,8H196v12a92.37,92.37,0,0,1-2.32,20.65l37,25.34A8,8,0,0,1,226,206a8.09,8.09,0,0,1-4.58-1.44l-34.87-23.88a91.85,91.85,0,0,1-117.1,0L34.58,204.56A8.09,8.09,0,0,1,30,206a8,8,0,0,1-4.57-14.56l37-25.34A92.37,92.37,0,0,1,60,148V136H28a8,8,0,0,1,0-16H60V92A68.07,68.07,0,0,1,128,24h0A68.07,68.07,0,0,1,196,92v28h32A8,8,0,0,1,236,128ZM76,148a76,76,0,0,0,152,0V92a52,52,0,0,0-104,0v56Z"/></svg>`;
2
+ const CLOSE_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 256 256"><path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"/></svg>`;
3
+ const WIDGET_STYLES = `
4
+ :host { all: initial; }
5
+ * { box-sizing: border-box; margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
6
+
7
+ .tif-fab {
8
+ position: fixed;
9
+ z-index: 2147483647;
10
+ width: 48px;
11
+ height: 48px;
12
+ border-radius: 50%;
13
+ border: none;
14
+ cursor: pointer;
15
+ display: flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ color: white;
19
+ box-shadow: 0 4px 12px rgba(0,0,0,0.25);
20
+ transition: transform 0.2s, box-shadow 0.2s;
21
+ }
22
+ .tif-fab:hover { transform: scale(1.1); box-shadow: 0 6px 16px rgba(0,0,0,0.3); }
23
+ .tif-fab.bottom-right { bottom: 20px; right: 20px; }
24
+ .tif-fab.bottom-left { bottom: 20px; left: 20px; }
25
+
26
+ .tif-overlay {
27
+ position: fixed;
28
+ z-index: 2147483647;
29
+ inset: 0;
30
+ background: rgba(0,0,0,0.4);
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ padding: 16px;
35
+ }
36
+
37
+ .tif-modal {
38
+ background: white;
39
+ border-radius: 12px;
40
+ width: 100%;
41
+ max-width: 440px;
42
+ max-height: 90vh;
43
+ overflow-y: auto;
44
+ box-shadow: 0 20px 60px rgba(0,0,0,0.3);
45
+ }
46
+
47
+ .tif-header {
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: space-between;
51
+ padding: 16px 20px;
52
+ border-bottom: 1px solid #e5e7eb;
53
+ }
54
+ .tif-header h2 { font-size: 16px; font-weight: 600; color: #111827; }
55
+ .tif-close {
56
+ background: none;
57
+ border: none;
58
+ cursor: pointer;
59
+ color: #6b7280;
60
+ padding: 4px;
61
+ border-radius: 6px;
62
+ display: flex;
63
+ align-items: center;
64
+ }
65
+ .tif-close:hover { background: #f3f4f6; color: #111827; }
66
+
67
+ .tif-body { padding: 20px; display: flex; flex-direction: column; gap: 16px; }
68
+
69
+ .tif-field label {
70
+ display: block;
71
+ font-size: 13px;
72
+ font-weight: 500;
73
+ color: #374151;
74
+ margin-bottom: 6px;
75
+ }
76
+ .tif-field input, .tif-field textarea, .tif-field select {
77
+ width: 100%;
78
+ border: 1px solid #d1d5db;
79
+ border-radius: 8px;
80
+ padding: 8px 12px;
81
+ font-size: 14px;
82
+ color: #111827;
83
+ outline: none;
84
+ transition: border-color 0.15s;
85
+ }
86
+ .tif-field input:focus, .tif-field textarea:focus, .tif-field select:focus {
87
+ border-color: #3b82f6;
88
+ box-shadow: 0 0 0 3px rgba(59,130,246,0.1);
89
+ }
90
+ .tif-field textarea { min-height: 80px; resize: vertical; }
91
+
92
+ .tif-screenshot-zone {
93
+ border: 2px dashed #d1d5db;
94
+ border-radius: 8px;
95
+ padding: 16px;
96
+ text-align: center;
97
+ color: #6b7280;
98
+ font-size: 13px;
99
+ cursor: pointer;
100
+ transition: border-color 0.15s;
101
+ }
102
+ .tif-screenshot-zone:hover { border-color: #3b82f6; }
103
+ .tif-screenshot-zone.has-image { border-color: #10b981; background: #f0fdf4; }
104
+ .tif-screenshot-zone img { max-width: 100%; max-height: 120px; margin-top: 8px; border-radius: 4px; }
105
+ .tif-screenshot-zone input[type="file"] { display: none; }
106
+
107
+ .tif-context {
108
+ font-size: 12px;
109
+ color: #9ca3af;
110
+ background: #f9fafb;
111
+ border-radius: 6px;
112
+ padding: 8px 12px;
113
+ }
114
+ .tif-context summary { cursor: pointer; font-weight: 500; }
115
+ .tif-context pre { margin-top: 6px; white-space: pre-wrap; word-break: break-all; font-size: 11px; }
116
+
117
+ .tif-footer { padding: 12px 20px; border-top: 1px solid #e5e7eb; display: flex; justify-content: flex-end; gap: 8px; }
118
+ .tif-btn {
119
+ padding: 8px 16px;
120
+ border-radius: 8px;
121
+ font-size: 14px;
122
+ font-weight: 500;
123
+ cursor: pointer;
124
+ border: none;
125
+ transition: background 0.15s;
126
+ }
127
+ .tif-btn-cancel { background: #f3f4f6; color: #374151; }
128
+ .tif-btn-cancel:hover { background: #e5e7eb; }
129
+ .tif-btn-submit { background: #3b82f6; color: white; }
130
+ .tif-btn-submit:hover { background: #2563eb; }
131
+ .tif-btn-submit:disabled { opacity: 0.5; cursor: not-allowed; }
132
+
133
+ .tif-toast {
134
+ position: fixed;
135
+ bottom: 80px;
136
+ left: 50%;
137
+ transform: translateX(-50%);
138
+ padding: 10px 20px;
139
+ border-radius: 8px;
140
+ font-size: 14px;
141
+ font-weight: 500;
142
+ color: white;
143
+ z-index: 2147483647;
144
+ animation: tif-fadein 0.2s;
145
+ }
146
+ .tif-toast.success { background: #10b981; }
147
+ .tif-toast.error { background: #ef4444; }
148
+ @keyframes tif-fadein { from { opacity: 0; transform: translateX(-50%) translateY(8px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
149
+ `;
150
+ const MAX_SCREENSHOT_BYTES = 500000;
151
+ /**
152
+ * Escape HTML special characters to prevent XSS
153
+ */
154
+ const escapeHtml = (str) => {
155
+ const div = document.createElement("div");
156
+ div.textContent = str;
157
+ return div.innerHTML;
158
+ };
159
+ /**
160
+ * Resize an image data URL to fit within the size limit
161
+ */
162
+ const resizeScreenshot = (dataUrl) => {
163
+ return new Promise((resolve) => {
164
+ if (dataUrl.length <= MAX_SCREENSHOT_BYTES) {
165
+ resolve(dataUrl);
166
+ return;
167
+ }
168
+ const img = new Image();
169
+ img.onload = () => {
170
+ try {
171
+ const canvas = document.createElement("canvas");
172
+ let { width, height } = img;
173
+ const scale = Math.sqrt(MAX_SCREENSHOT_BYTES / dataUrl.length);
174
+ width = Math.floor(width * scale);
175
+ height = Math.floor(height * scale);
176
+ canvas.width = width;
177
+ canvas.height = height;
178
+ const ctx = canvas.getContext("2d");
179
+ if (!ctx) {
180
+ resolve(dataUrl);
181
+ return;
182
+ }
183
+ ctx.drawImage(img, 0, 0, width, height);
184
+ resolve(canvas.toDataURL("image/jpeg", 0.7));
185
+ }
186
+ catch {
187
+ resolve(dataUrl);
188
+ }
189
+ };
190
+ img.onerror = () => {
191
+ resolve(dataUrl);
192
+ };
193
+ img.src = dataUrl;
194
+ });
195
+ };
196
+ /**
197
+ * Read a file as a data URL
198
+ */
199
+ const readFileAsDataUrl = (file) => {
200
+ return new Promise((resolve, reject) => {
201
+ const reader = new FileReader();
202
+ reader.onload = () => resolve(reader.result);
203
+ reader.onerror = reject;
204
+ reader.readAsDataURL(file);
205
+ });
206
+ };
207
+ /**
208
+ * Create and mount the bug report widget
209
+ */
210
+ export const createBugReportWidget = (analytics, options) => {
211
+ const position = options?.position ?? "bottom-right";
212
+ const buttonColor = options?.buttonColor ?? "#ef4444";
213
+ const buttonText = options?.buttonText ?? "Report Bug";
214
+ const host = document.createElement("div");
215
+ host.id = "thisbefine-bug-report";
216
+ const shadow = host.attachShadow({ mode: "open" });
217
+ const style = document.createElement("style");
218
+ style.textContent = WIDGET_STYLES;
219
+ shadow.appendChild(style);
220
+ let screenshotDataUrl = null;
221
+ let isSubmitting = false;
222
+ const fab = document.createElement("button");
223
+ fab.className = `tif-fab ${position}`;
224
+ fab.style.backgroundColor = buttonColor;
225
+ fab.innerHTML = BUG_ICON_SVG;
226
+ fab.title = buttonText;
227
+ fab.setAttribute("aria-label", buttonText);
228
+ shadow.appendChild(fab);
229
+ const getContextInfo = () => ({
230
+ url: window.location.href,
231
+ browser: navigator.userAgent,
232
+ os: navigator.platform,
233
+ });
234
+ const showToast = (message, type) => {
235
+ const toast = document.createElement("div");
236
+ toast.className = `tif-toast ${type}`;
237
+ toast.textContent = message;
238
+ shadow.appendChild(toast);
239
+ setTimeout(() => toast.remove(), 3000);
240
+ };
241
+ const openModal = () => {
242
+ const ctx = getContextInfo();
243
+ screenshotDataUrl = null;
244
+ const overlay = document.createElement("div");
245
+ overlay.className = "tif-overlay";
246
+ overlay.innerHTML = `
247
+ <div class="tif-modal">
248
+ <div class="tif-header">
249
+ <h2>Report a Bug</h2>
250
+ <button class="tif-close" aria-label="Close">${CLOSE_ICON_SVG}</button>
251
+ </div>
252
+ <div class="tif-body">
253
+ <div class="tif-field">
254
+ <label for="tif-title">Title *</label>
255
+ <input id="tif-title" type="text" placeholder="Brief description of the issue" maxlength="500" />
256
+ </div>
257
+ <div class="tif-field">
258
+ <label for="tif-desc">Description *</label>
259
+ <textarea id="tif-desc" placeholder="What happened? What did you expect to happen?" maxlength="10000"></textarea>
260
+ </div>
261
+ <div class="tif-field">
262
+ <label for="tif-severity">Severity</label>
263
+ <select id="tif-severity">
264
+ <option value="low">Low</option>
265
+ <option value="medium" selected>Medium</option>
266
+ <option value="high">High</option>
267
+ <option value="critical">Critical</option>
268
+ </select>
269
+ </div>
270
+ <div class="tif-field">
271
+ <label>Screenshot (optional)</label>
272
+ <div class="tif-screenshot-zone" id="tif-screenshot">
273
+ <span>Click to upload or paste from clipboard (Ctrl+V)</span>
274
+ <input type="file" accept="image/*" />
275
+ </div>
276
+ </div>
277
+ <details class="tif-context">
278
+ <summary>Captured context</summary>
279
+ <pre>${escapeHtml(JSON.stringify(ctx, null, 2))}</pre>
280
+ </details>
281
+ </div>
282
+ <div class="tif-footer">
283
+ <button class="tif-btn tif-btn-cancel">Cancel</button>
284
+ <button class="tif-btn tif-btn-submit" id="tif-submit">Submit Report</button>
285
+ </div>
286
+ </div>
287
+ `;
288
+ shadow.appendChild(overlay);
289
+ const close = () => overlay.remove();
290
+ overlay.querySelector(".tif-close")?.addEventListener("click", close);
291
+ overlay.querySelector(".tif-btn-cancel")?.addEventListener("click", close);
292
+ overlay.addEventListener("click", (e) => {
293
+ if (e.target === overlay)
294
+ close();
295
+ });
296
+ const screenshotZone = overlay.querySelector("#tif-screenshot");
297
+ const fileInput = screenshotZone.querySelector('input[type="file"]');
298
+ const setScreenshot = async (dataUrl) => {
299
+ try {
300
+ screenshotDataUrl = await resizeScreenshot(dataUrl);
301
+ screenshotZone.classList.add("has-image");
302
+ const existingImg = screenshotZone.querySelector("img");
303
+ if (existingImg)
304
+ existingImg.remove();
305
+ const img = document.createElement("img");
306
+ img.src = screenshotDataUrl;
307
+ screenshotZone.appendChild(img);
308
+ const span = screenshotZone.querySelector("span");
309
+ if (span) {
310
+ span.textContent = "Screenshot attached. Click to change.";
311
+ }
312
+ }
313
+ catch {
314
+ showToast("Failed to process screenshot.", "error");
315
+ }
316
+ };
317
+ screenshotZone.addEventListener("click", () => fileInput.click());
318
+ fileInput.addEventListener("change", async () => {
319
+ const file = fileInput.files?.[0];
320
+ if (file) {
321
+ const dataUrl = await readFileAsDataUrl(file);
322
+ await setScreenshot(dataUrl);
323
+ }
324
+ });
325
+ overlay.addEventListener("paste", async (e) => {
326
+ const clipboardEvent = e;
327
+ const items = clipboardEvent.clipboardData?.items;
328
+ if (!items)
329
+ return;
330
+ for (const item of items) {
331
+ if (item.type.startsWith("image/")) {
332
+ const file = item.getAsFile();
333
+ if (file) {
334
+ const dataUrl = await readFileAsDataUrl(file);
335
+ await setScreenshot(dataUrl);
336
+ }
337
+ break;
338
+ }
339
+ }
340
+ });
341
+ const submitBtn = overlay.querySelector("#tif-submit");
342
+ submitBtn.addEventListener("click", async () => {
343
+ if (isSubmitting)
344
+ return;
345
+ try {
346
+ const titleInput = overlay.querySelector("#tif-title");
347
+ const descInput = overlay.querySelector("#tif-desc");
348
+ const severitySelect = overlay.querySelector("#tif-severity");
349
+ if (!titleInput || !descInput || !severitySelect) {
350
+ showToast("Form elements not found.", "error");
351
+ return;
352
+ }
353
+ const title = titleInput.value.trim();
354
+ const description = descInput.value.trim();
355
+ const severity = severitySelect.value;
356
+ if (!title || !description) {
357
+ showToast("Please fill in the title and description.", "error");
358
+ return;
359
+ }
360
+ isSubmitting = true;
361
+ submitBtn.disabled = true;
362
+ submitBtn.textContent = "Submitting...";
363
+ let user;
364
+ try {
365
+ user = analytics.getUser();
366
+ }
367
+ catch {
368
+ user = { anonymousId: "unknown" };
369
+ }
370
+ const payload = {
371
+ title,
372
+ description,
373
+ severity,
374
+ screenshot: screenshotDataUrl ?? undefined,
375
+ metadata: ctx,
376
+ anonymousId: user.anonymousId,
377
+ userId: user.userId,
378
+ };
379
+ const analyticsConfig = analytics;
380
+ const apiHost = analyticsConfig.config?.host ?? "https://thisbefine.com";
381
+ const apiKey = analyticsConfig.config?.apiKey ?? "";
382
+ const response = await fetch(`${apiHost}/api/v1/bug-report`, {
383
+ method: "POST",
384
+ headers: {
385
+ "Content-Type": "application/json",
386
+ "X-API-Key": apiKey,
387
+ },
388
+ body: JSON.stringify(payload),
389
+ });
390
+ if (response.ok) {
391
+ close();
392
+ showToast("Bug report submitted. Thank you!", "success");
393
+ }
394
+ else {
395
+ showToast("Failed to submit. Please try again.", "error");
396
+ }
397
+ }
398
+ catch {
399
+ showToast("Something went wrong. Please try again.", "error");
400
+ }
401
+ finally {
402
+ isSubmitting = false;
403
+ submitBtn.disabled = false;
404
+ submitBtn.textContent = "Submit Report";
405
+ }
406
+ });
407
+ };
408
+ fab.addEventListener("click", openModal);
409
+ document.body.appendChild(host);
410
+ return {
411
+ destroy: () => {
412
+ host.remove();
413
+ },
414
+ };
415
+ };
416
+ //# sourceMappingURL=bug-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug-report.js","sourceRoot":"","sources":["../../src/widget/bug-report.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,107 @@
1
+ {
2
+ "name": "@thisbefine/analytics",
3
+ "version": "0.1.0",
4
+ "description": "Track events, catch errors, and pretend everything's fine. Lightweight analytics for indie SaaS.",
5
+ "author": "Thisbefine <hello@thisbefine.com>",
6
+ "license": "MIT",
7
+ "homepage": "https://thisbefine.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/thisbefine/analytics.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/thisbefine/analytics/issues"
14
+ },
15
+ "type": "module",
16
+ "sideEffects": false,
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "main": "./dist/index.js",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ },
31
+ "./react": {
32
+ "types": "./dist/react.d.ts",
33
+ "default": "./dist/react.js"
34
+ },
35
+ "./next": {
36
+ "types": "./dist/next.d.ts",
37
+ "default": "./dist/next.js"
38
+ }
39
+ },
40
+ "files": [
41
+ "dist",
42
+ "README.md"
43
+ ],
44
+ "scripts": {
45
+ "prebuild": "node scripts/generate-version.js",
46
+ "build": "tsc --project tsconfig.build.json",
47
+ "dev": "tsc --project tsconfig.build.json --watch",
48
+ "typecheck": "tsc --noEmit",
49
+ "format": "biome check . --write",
50
+ "lint": "biome check .",
51
+ "clean": "rm -rf dist",
52
+ "prepublishOnly": "pnpm run clean && pnpm run build",
53
+ "test": "vitest",
54
+ "test:run": "vitest run",
55
+ "test:watch": "vitest --watch",
56
+ "test:coverage": "vitest run --coverage",
57
+ "test:ui": "vitest --ui"
58
+ },
59
+ "peerDependencies": {
60
+ "next": ">=13",
61
+ "react": ">=18"
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "next": {
65
+ "optional": true
66
+ },
67
+ "react": {
68
+ "optional": true
69
+ }
70
+ },
71
+ "devDependencies": {
72
+ "@biomejs/biome": "2.3.13",
73
+ "@testing-library/jest-dom": "^6.6.3",
74
+ "@testing-library/react": "^16.1.0",
75
+ "@types/node": "^25.1.0",
76
+ "@types/react": "^19.2.10",
77
+ "@vitest/coverage-v8": "^3.0.0",
78
+ "@vitest/ui": "^3.0.0",
79
+ "jsdom": "^26.0.0",
80
+ "next": "^16.1.6",
81
+ "react": "^19.2.4",
82
+ "react-dom": "^19.2.4",
83
+ "typescript": "^5.9.3",
84
+ "vitest": "^3.0.0"
85
+ },
86
+ "keywords": [
87
+ "analytics",
88
+ "tracking",
89
+ "events",
90
+ "pageviews",
91
+ "user-identification",
92
+ "session-tracking",
93
+ "error-tracking",
94
+ "logging",
95
+ "nextjs",
96
+ "react",
97
+ "typescript",
98
+ "privacy",
99
+ "gdpr",
100
+ "thisbefine",
101
+ "saas",
102
+ "product-analytics"
103
+ ],
104
+ "dependencies": {
105
+ "uuid": "^13.0.0"
106
+ }
107
+ }