teacupweb 2.2.1

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.
@@ -0,0 +1,19 @@
1
+ import clicks from './services/click.service';
2
+ import page from './services/page.service';
3
+ import forms from './services/forms.service';
4
+ import save from './save';
5
+
6
+ function track() {
7
+ // Track button clicks
8
+ clicks.track();
9
+
10
+ // Track page views and scrolling
11
+ page.track();
12
+
13
+ // forms
14
+ forms.track();
15
+
16
+ // save
17
+ save();
18
+ }
19
+ export default { track };
@@ -0,0 +1,109 @@
1
+ const data = {
2
+ button: [],
3
+ form: [],
4
+ page: [],
5
+ };
6
+ const prevData = {
7
+ button: [],
8
+ form: [],
9
+ page: [],
10
+ };
11
+ const clearData = () => {
12
+ prevData.button = [...data.button];
13
+ prevData.form = [...data.form];
14
+ prevData.page = [...data.page];
15
+ data.button = [];
16
+ data.form = [];
17
+ data.page = [];
18
+ };
19
+
20
+ const getNewData = () => {
21
+ const newData = {
22
+ button: [],
23
+ form: [],
24
+ page: [],
25
+ };
26
+
27
+ // Compare buttons - only include if not in prevData
28
+ data.button.forEach((btn) => {
29
+ const isDuplicate = prevData.button.some(
30
+ (prevBtn) => prevBtn.button === btn.button && prevBtn.page === btn.page
31
+ );
32
+ if (!isDuplicate) {
33
+ newData.button.push(btn);
34
+ }
35
+ });
36
+
37
+ // Compare pages - only include if page+percentage combo not in prevData
38
+ data.page.forEach((pg) => {
39
+ const isDuplicate = prevData.page.some(
40
+ (prevPg) =>
41
+ prevPg.page === pg.page && prevPg.percentage === pg.percentage
42
+ );
43
+ if (!isDuplicate) {
44
+ newData.page.push(pg);
45
+ }
46
+ });
47
+
48
+ // Compare forms - only include if form+percent combo not in prevData
49
+ data.form.forEach((frm) => {
50
+ const isDuplicate = prevData.form.some(
51
+ (prevFrm) =>
52
+ prevFrm.form === frm.form && prevFrm.percent === frm.percent
53
+ );
54
+ if (!isDuplicate) {
55
+ newData.form.push(frm);
56
+ }
57
+ });
58
+
59
+ return newData;
60
+ };
61
+
62
+ const setData = (type, result) => {
63
+ if (type === 'page') {
64
+ // Find existing page entry
65
+ const existingPageIndex = data.page.findIndex(
66
+ (page) => page.page === result.page
67
+ );
68
+
69
+ if (existingPageIndex !== -1) {
70
+ // Update only if new percentage is higher
71
+ const currentPercentage =
72
+ parseFloat(data.page[existingPageIndex].percentage) || 0;
73
+ const newPercentage = parseFloat(result.percentage) || 0;
74
+
75
+ if (newPercentage > currentPercentage) {
76
+ data.page[existingPageIndex].percentage = result.percentage;
77
+ }
78
+ } else {
79
+ // Add new entry if it doesn't exist
80
+ data.page.push(result);
81
+ }
82
+ } else if (type === 'form') {
83
+ // Find existing form entry
84
+ const existingFormIndex = data.form.findIndex(
85
+ (form) => form.form === result.form
86
+ );
87
+
88
+ if (existingFormIndex !== -1) {
89
+ // Update only if new percentage is higher
90
+ const currentPercent =
91
+ parseFloat(data.form[existingFormIndex].percent) || 0;
92
+ const newPercent = parseFloat(result.percent) || 0;
93
+
94
+ if (newPercent > currentPercent) {
95
+ data.form[existingFormIndex].percent = result.percent;
96
+ }
97
+ } else {
98
+ // Add new entry if it doesn't exist
99
+ data.form.push(result);
100
+ }
101
+ } else {
102
+ // For other types (like 'button'), just push without deduplication
103
+ data[type].push(result);
104
+ }
105
+
106
+ return data;
107
+ };
108
+
109
+ export default { setData, data, clearData, getNewData };
@@ -0,0 +1,25 @@
1
+ const FINGERPRINT_KEY = 'teacup_fingerprint';
2
+
3
+ export default function fingerprint() {
4
+ // Check if fingerprint already exists in localStorage
5
+ const existingFingerprint = localStorage.getItem(FINGERPRINT_KEY);
6
+
7
+ if (existingFingerprint) {
8
+ return existingFingerprint;
9
+ }
10
+
11
+ // Generate new fingerprint if not found
12
+ const canvas = document.createElement('canvas');
13
+ canvas.width = 20;
14
+ canvas.height = 2220;
15
+ const ctx = canvas.getContext('2d');
16
+ ctx.fillText('Hello', 10, 10);
17
+
18
+ const data = canvas.toDataURL();
19
+ const newFingerprint = data.slice(-32);
20
+
21
+ // Store in localStorage for future use
22
+ localStorage.setItem(FINGERPRINT_KEY, newFingerprint);
23
+
24
+ return newFingerprint;
25
+ }
@@ -0,0 +1,27 @@
1
+ import fetchAPI from '../Functions/FetchAPI';
2
+ import fingerprint from './identity';
3
+ import data from './data.controller';
4
+ import { initial } from '..';
5
+
6
+ export default function save() {
7
+ setInterval(() => {
8
+ const newData = data.getNewData();
9
+
10
+ // Check if there's any new data to send
11
+ const hasNewData =
12
+ newData.button.length > 0 ||
13
+ newData.form.length > 0 ||
14
+ newData.page.length > 0;
15
+
16
+ if (hasNewData) {
17
+ fetchAPI('api/analytics', 'POST', {
18
+ data: newData,
19
+ initial: initial,
20
+ fingerprint: fingerprint(),
21
+ });
22
+
23
+ // Clear data after sending
24
+ data.clearData();
25
+ }
26
+ }, 5000);
27
+ }
@@ -0,0 +1,13 @@
1
+ import data from './../data.controller';
2
+
3
+ function track() {
4
+ addEventListener('click', (e) => {
5
+ if (e.target.tagName == 'BUTTON') {
6
+ data.setData('button', {
7
+ button: e.target.innerText,
8
+ page: window.location.pathname,
9
+ });
10
+ }
11
+ });
12
+ }
13
+ export default { track };
@@ -0,0 +1,30 @@
1
+ import data from '../data.controller';
2
+ function track() {
3
+ document.addEventListener('input', (e) => {
4
+ const form = e.target.closest('form');
5
+ if (!form) return;
6
+
7
+ function findHeadingBeforeForm(form) {
8
+ let el = form.previousElementSibling;
9
+ while (el) {
10
+ if (/H[1-3]/.test(el.tagName)) return el;
11
+ el = el.previousElementSibling;
12
+ }
13
+ return null;
14
+ }
15
+
16
+ const heading = findHeadingBeforeForm(form);
17
+
18
+ const fields = form.querySelectorAll('input, textarea, select');
19
+ const filled = [...fields].filter((f) => f.value.trim() !== '').length;
20
+
21
+ const percent = (filled / fields.length) * 100;
22
+
23
+ data.setData('form', {
24
+ form: form.dataset.formName || heading?.innerText || 'unknown-form',
25
+ percentage: Math.ceil(percent),
26
+ });
27
+ });
28
+ }
29
+
30
+ export default { track };
@@ -0,0 +1,68 @@
1
+ import data from '../data.controller';
2
+
3
+ let currentPath = window.location.pathname;
4
+ let topPercent = 0;
5
+
6
+ function trackRoute() {
7
+ ['pushState', 'replaceState'].forEach((method) => {
8
+ const original = history[method];
9
+ history[method] = function () {
10
+ const result = original.apply(this, arguments);
11
+
12
+ // New page navigation detected
13
+ const newPath = window.location.pathname;
14
+ if (newPath !== currentPath) {
15
+ // Initialize new page with 0%
16
+ currentPath = newPath;
17
+ topPercent = 0;
18
+ data.setData('page', {
19
+ page: currentPath,
20
+ percentage: 0,
21
+ });
22
+ }
23
+
24
+ return result;
25
+ };
26
+ });
27
+ }
28
+
29
+ function trackPageView() {
30
+ document.addEventListener('scroll', () => {
31
+ const scrollTop = document.documentElement.scrollTop;
32
+ const scrollHeight = document.documentElement.scrollHeight;
33
+ const clientHeight = document.documentElement.clientHeight;
34
+
35
+ const percent = Math.ceil(
36
+ (scrollTop / (scrollHeight - clientHeight)) * 100
37
+ );
38
+
39
+ // Update only if percentage increased
40
+ if (percent > topPercent) {
41
+ topPercent = percent;
42
+
43
+ // Update the data with new percentage
44
+ data.setData('page', {
45
+ page: currentPath,
46
+ percentage: topPercent,
47
+ });
48
+ }
49
+ });
50
+ }
51
+
52
+ function track() {
53
+ // Initialize current page
54
+ data.setData('page', {
55
+ page: currentPath,
56
+ percentage: 0,
57
+ });
58
+
59
+ // Set up route tracking for navigation
60
+ trackRoute();
61
+
62
+ // Set up scroll tracking
63
+ trackPageView();
64
+ }
65
+
66
+ export default {
67
+ track,
68
+ };
package/CHANGELOG.md ADDED
@@ -0,0 +1,75 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+
9
+ ## [1.1.0] - 2025-12-26
10
+
11
+ ### Added
12
+ - **Duplicate Prevention System**: Analytics data is now compared with previously sent data to prevent duplicates from being stored in the database
13
+ - **LocalStorage Fingerprint**: Visitor fingerprint now persists in localStorage across browser sessions for consistent identification
14
+ - `getNewData()` function in data controller that filters out duplicate analytics before sending
15
+
16
+ ### Changed
17
+ - Fingerprint generation now happens only once per browser and is stored in localStorage with key `teacupnet_fingerprint`
18
+ - Analytics save function now only sends API requests when there is new data to transmit
19
+ - Data comparison logic ensures button clicks, page views, and form interactions are only sent once
20
+
21
+ ### Fixed
22
+ - Duplicate button clicks on the same page are no longer sent multiple times
23
+ - Same page scroll percentages are no longer duplicated in database
24
+ - Form completion percentages only update when they change
25
+ - Reduced unnecessary API calls when no new analytics data is available
26
+
27
+ ### Performance
28
+ - Reduced database writes by filtering duplicates before transmission
29
+ - Reduced network requests by skipping empty data intervals
30
+ - Fingerprint generation optimized to run only once per browser session
31
+
32
+ ## [1.0.0] - 2025-12-17
33
+
34
+ ### Added
35
+ - Initial release of TeacupNet Library
36
+ - Analytics tracking module with automatic data collection
37
+ - Button click tracking across all pages
38
+ - Page view and scroll depth tracking
39
+ - Form completion percentage tracking
40
+ - Canvas fingerprinting for unique visitor identification
41
+ - Data controller for blog management
42
+ - API for posting data to inboxes
43
+ - Automatic data synchronization every 5 seconds
44
+ - Smart deduplication for page and form analytics
45
+ - TypeScript definitions for better IDE support
46
+
47
+ ### Features
48
+ - **Analytics Module**
49
+ - `analytics.track()` - Start automatic tracking of user interactions
50
+ - Real-time button click tracking
51
+ - Scroll depth monitoring with percentage calculation
52
+ - Form field completion tracking
53
+ - Custom form naming via `data-form-name` or heading detection
54
+
55
+ - **Data Module**
56
+ - `data.getBlogs()` - Retrieve all blogs for client
57
+ - `data.getBlog(id)` - Get specific blog by ID
58
+ - `data.postData(inboxId, data)` - Post data to inbox
59
+
60
+ ### Technical Details
61
+ - ES modules support
62
+ - Production-ready with Vercel backend integration
63
+ - Browser-based fingerprinting for visitor tracking
64
+ - Optimized data storage preventing duplicates
65
+ - Credential validation on initialization
66
+
67
+ ## [Unreleased]
68
+
69
+ ### Planned
70
+ - Custom event tracking
71
+ - Configurable sync intervals
72
+ - Offline data queue
73
+ - Enhanced TypeScript definitions
74
+ - Custom analytics filters
75
+ - Dashboard integration examples
@@ -0,0 +1,22 @@
1
+ import fetchAPI from '../Functions/FetchAPI';
2
+ import { initial } from '../index.js';
3
+
4
+ const getBlogs = async () => {
5
+ const id = initial.clientID;
6
+ const result = await fetchAPI(`dashboard/blogs/${id}`);
7
+ return result;
8
+ };
9
+
10
+ const getBlog = async (id) => {
11
+ const clientID = initial.clientID;
12
+ return await fetchAPI(`dashboard/blogs/${clientID}/${id}`);
13
+ };
14
+
15
+ const postData = async (id, data) => {
16
+ return await fetchAPI('api/inboxData', 'POST', {
17
+ inbox_id: id,
18
+ data: data,
19
+ });
20
+ };
21
+
22
+ export default { getBlogs, getBlog, postData };
@@ -0,0 +1,20 @@
1
+ export default async function fetchAPI(path, method = 'GET', body = null) {
2
+ const req = {
3
+ method: method,
4
+ headers: {
5
+ 'Content-Type': 'application/json',
6
+ },
7
+ body: JSON.stringify(body),
8
+ };
9
+ if (method === 'GET') delete req.body;
10
+
11
+ try {
12
+ const data = await fetch(
13
+ `https://backend.teacup.website/${path}`,
14
+ req
15
+ );
16
+ return await data.json();
17
+ } catch (error) {
18
+ console.log(error);
19
+ }
20
+ }
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025 Tahmid Jihan, TeacupNet
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,331 @@
1
+ # TeacupNet Library
2
+
3
+ A powerful JavaScript library for integrating TeacupNet analytics and data management capabilities into your web applications. Track user interactions, page views, form completions, and seamlessly connect to the TeacupNet backend.
4
+
5
+ ## Features
6
+
7
+ - 📊 **Analytics Tracking**: Automatic tracking of button clicks, page views, and form interactions
8
+ - 🎯 **Smart Form Tracking**: Track form completion percentage in real-time
9
+ - 📈 **Page Scroll Tracking**: Monitor how far users scroll on each page
10
+ - 🔒 **Fingerprinting**: Unique visitor identification using canvas fingerprinting
11
+ - 🚀 **Easy Integration**: Simple initialization and automatic data synchronization
12
+ - 📦 **Lightweight**: Minimal dependencies, optimized for performance
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install teacupnet-lib
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### 1. Initialize the Library
23
+
24
+ ```javascript
25
+ import teacupnet from 'teacupnet-lib';
26
+
27
+ // Initialize with your credentials
28
+ const client = teacupnet('YOUR_CLIENT_ID', 'YOUR_CLIENT_KEY');
29
+
30
+ if (client.error) {
31
+ console.error(client.message);
32
+ } else {
33
+ console.log('TeacupNet initialized successfully!');
34
+ }
35
+ ```
36
+
37
+ ### 2. Enable Analytics Tracking
38
+
39
+ ```javascript
40
+ import teacupnet from 'teacupnet-lib';
41
+
42
+ const client = teacupnet('YOUR_CLIENT_ID', 'YOUR_CLIENT_KEY');
43
+
44
+ // Start tracking analytics
45
+ client.analytics.track();
46
+ ```
47
+
48
+ That's it! The library will now automatically track:
49
+
50
+ - Button clicks
51
+ - Page navigation and scroll depth
52
+ - Form completion percentages
53
+
54
+ ## API Reference
55
+
56
+ ### Initialization
57
+
58
+ #### `teacupnet(clientID, clientKey)`
59
+
60
+ Initializes the TeacupNet library with your credentials.
61
+
62
+ **Parameters:**
63
+
64
+ - `clientID` (string): Your unique client identifier
65
+ - `clientKey` (string): Your secret client key
66
+
67
+ **Returns:**
68
+
69
+ - On success: Object with `analytics` and `data` controllers
70
+ - On failure: Object with `error` and `message` properties
71
+
72
+ **Example:**
73
+
74
+ ```javascript
75
+ const client = teacupnet('123', 'secretKey456');
76
+ ```
77
+
78
+ ### Analytics Module
79
+
80
+ #### `client.analytics.track()`
81
+
82
+ Starts automatic tracking of user interactions including:
83
+
84
+ - **Button Clicks**: Tracks every button click with the button text and page location
85
+ - **Page Views**: Tracks page navigation and scroll depth percentage
86
+ - **Form Interactions**: Monitors form completion percentage
87
+
88
+ **Example:**
89
+
90
+ ```javascript
91
+ client.analytics.track();
92
+ ```
93
+
94
+ **Data Collection:**
95
+
96
+ - Automatically sends analytics data to the server every 5 seconds
97
+ - Uses canvas fingerprinting for unique visitor identification
98
+ - Tracks only the highest scroll percentage per page (no duplicates)
99
+ - Tracks only the highest form completion percentage per form
100
+
101
+ ### Data Module
102
+
103
+ #### `client.data.getBlogs()`
104
+
105
+ Retrieves all blogs associated with your client account.
106
+
107
+ **Returns:** Promise resolving to an array of blog objects
108
+
109
+ **Example:**
110
+
111
+ ```javascript
112
+ const blogs = await client.data.getBlogs();
113
+ console.log(blogs);
114
+ ```
115
+
116
+ #### `client.data.getBlog(blogId)`
117
+
118
+ Retrieves a specific blog by its ID.
119
+
120
+ **Parameters:**
121
+
122
+ - `blogId` (string): The unique identifier of the blog
123
+
124
+ **Returns:** Promise resolving to a blog object
125
+
126
+ **Example:**
127
+
128
+ ```javascript
129
+ const blog = await client.data.getBlog('blog123');
130
+ console.log(blog);
131
+ ```
132
+
133
+ #### `client.data.postData(inboxId, data)`
134
+
135
+ Posts data to a specific inbox.
136
+
137
+ **Parameters:**
138
+
139
+ - `inboxId` (string): The unique identifier of the inbox
140
+ - `data` (object): The data to be posted
141
+
142
+ **Returns:** Promise resolving to the server response
143
+
144
+ **Example:**
145
+
146
+ ```javascript
147
+ const response = await client.data.postData('inbox123', {
148
+ name: 'John Doe',
149
+ email: 'john@example.com',
150
+ message: 'Hello!',
151
+ });
152
+ ```
153
+
154
+ ## Analytics Details
155
+
156
+ ### Button Click Tracking
157
+
158
+ Tracks all button clicks automatically:
159
+
160
+ ```javascript
161
+ // Captured data format:
162
+ {
163
+ button: "Submit", // Button text
164
+ page: "/contact" // Current page path
165
+ }
166
+ ```
167
+
168
+ ### Page View Tracking
169
+
170
+ Monitors page navigation and scroll depth:
171
+
172
+ ```javascript
173
+ // Captured data format:
174
+ {
175
+ page: "/about",
176
+ percentage: 75 // Highest scroll depth reached (0-100)
177
+ }
178
+ ```
179
+
180
+ **Note:** Only the highest scroll percentage is stored for each page visit.
181
+
182
+ ### Form Tracking
183
+
184
+ Tracks form completion in real-time:
185
+
186
+ ```javascript
187
+ // Captured data format:
188
+ {
189
+ form: "Contact Us", // From data-form-name attribute or preceding H1-H3 heading
190
+ percent: 66.7 // Percentage of filled fields
191
+ }
192
+ ```
193
+
194
+ **Form Naming:**
195
+
196
+ 1. Use `data-form-name` attribute on your form element
197
+ 2. Or place an `<h1>`, `<h2>`, or `<h3>` heading before the form
198
+ 3. Fallback: "unknown-form"
199
+
200
+ **Example:**
201
+
202
+ ```html
203
+ <!-- Option 1: Using data-form-name -->
204
+ <form data-form-name="Newsletter Signup">
205
+ <input type="email" name="email" />
206
+ <button type="submit">Subscribe</button>
207
+ </form>
208
+
209
+ <!-- Option 2: Using heading -->
210
+ <h2>Contact Us</h2>
211
+ <form>
212
+ <input type="text" name="name" />
213
+ <input type="email" name="email" />
214
+ <textarea name="message"></textarea>
215
+ <button type="submit">Send</button>
216
+ </form>
217
+ ```
218
+
219
+ ## Advanced Usage
220
+
221
+ ### Custom Analytics Implementation
222
+
223
+ If you want more control over tracking:
224
+
225
+ ```javascript
226
+ import teacupnet from 'teacupnet-lib';
227
+
228
+ const client = teacupnet('YOUR_CLIENT_ID', 'YOUR_CLIENT_KEY');
229
+
230
+ // Enable only specific tracking
231
+ // Note: This requires manual implementation
232
+ // The track() method enables all tracking automatically
233
+ ```
234
+
235
+ ### Working with React/Vue/Angular
236
+
237
+ The library works seamlessly with modern frameworks:
238
+
239
+ ```javascript
240
+ // React example
241
+ import { useEffect } from 'react';
242
+ import teacupnet from 'teacupnet-lib';
243
+
244
+ function App() {
245
+ useEffect(() => {
246
+ const client = teacupnet(
247
+ process.env.REACT_APP_CLIENT_ID,
248
+ process.env.REACT_APP_CLIENT_KEY
249
+ );
250
+
251
+ if (!client.error) {
252
+ client.analytics.track();
253
+ }
254
+ }, []);
255
+
256
+ return <div>Your App</div>;
257
+ }
258
+ ```
259
+
260
+ ## Data Synchronization
261
+
262
+ Analytics data is automatically sent to the TeacupNet backend:
263
+
264
+ - **Interval**: Every 5 seconds
265
+ - **Endpoint**: `https://teacupnet-backend.vercel.app/api/analytics`
266
+ - **Included**: Fingerprint, client credentials, and collected analytics data
267
+
268
+ ## Browser Support
269
+
270
+ - Chrome (latest)
271
+ - Firefox (latest)
272
+ - Safari (latest)
273
+ - Edge (latest)
274
+
275
+ **Note:** This library uses ES modules and requires a modern browser or build tool.
276
+
277
+ ## Security Considerations
278
+
279
+ - **Credentials**: Store your `clientID` and `clientKey` securely
280
+ - **Environment Variables**: Use environment variables for credentials in production
281
+ - **HTTPS**: The library communicates with the backend over HTTPS
282
+
283
+ **Example `.env` file:**
284
+
285
+ ```env
286
+ TEACUPNET_CLIENT_ID=your_client_id
287
+ TEACUPNET_CLIENT_KEY=your_client_key
288
+ ```
289
+
290
+ ## Troubleshooting
291
+
292
+ ### Library not tracking
293
+
294
+ Make sure you've called `client.analytics.track()` after initialization:
295
+
296
+ ```javascript
297
+ const client = teacupnet('CLIENT_ID', 'CLIENT_KEY');
298
+ client.analytics.track(); // Don't forget this!
299
+ ```
300
+
301
+ ### Invalid Credentials error
302
+
303
+ Verify your `clientID` and `clientKey` are correct:
304
+
305
+ ```javascript
306
+ const client = teacupnet('CLIENT_ID', 'CLIENT_KEY');
307
+ if (client.error) {
308
+ console.error('Initialization failed:', client.message);
309
+ }
310
+ ```
311
+
312
+ ### Data not appearing in dashboard
313
+
314
+ - Check browser console for errors
315
+ - Verify network requests are being sent to the backend
316
+ - Confirm your credentials have the correct permissions
317
+
318
+ ## Support
319
+
320
+ For issues, questions, or feature requests:
321
+
322
+ - GitHub Issues: [https://github.com/tahmidjihan/teacupnet-lib/issues](https://github.com/tahmidjihan/teacupnet-lib/issues)
323
+ - Repository: [https://github.com/tahmidjihan/teacupnet-lib](https://github.com/tahmidjihan/teacupnet-lib)
324
+
325
+ ## License
326
+
327
+ ISC © Tahmid Jihan, Teacupnet
328
+
329
+ ## Changelog
330
+
331
+ See [CHANGELOG.md](CHANGELOG.md) for version history and updates.
package/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ declare module 'teacupnet-lib' {
2
+ export default function init(clientID: string, clientKey: string): any;
3
+
4
+ export const initial: any;
5
+ }
6
+
package/index.js ADDED
@@ -0,0 +1,24 @@
1
+ import dataController from './Controllers/data.controller.js';
2
+ import analytics from './Analytics/analytics.controller.js';
3
+
4
+ export const initial = {
5
+ clientID: '',
6
+ clientKey: '',
7
+ };
8
+
9
+ function init(clientID, clientKey) {
10
+ if (!clientID || !clientKey) {
11
+ return {
12
+ error: 'Invalid Credentials',
13
+ message: 'Please provide clientID and clientKey',
14
+ };
15
+ }
16
+ initial.clientID = clientID;
17
+ initial.clientKey = clientKey;
18
+ return {
19
+ data: dataController,
20
+ analytics: analytics,
21
+ };
22
+ }
23
+
24
+ export default init;
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "teacupweb",
3
+ "version": "2.2.1",
4
+ "description": "A powerful JavaScript library for integrating Teacup analytics and data management. Track user interactions, page views, form completions, and seamlessly connect to the Teacup backend.",
5
+ "keywords": [
6
+ "analytics",
7
+ "tracking",
8
+ "teacup",
9
+ "user-analytics",
10
+ "form-tracking",
11
+ "page-tracking",
12
+ "click-tracking",
13
+ "visitor-tracking",
14
+ "fingerprinting",
15
+ "web-analytics"
16
+ ],
17
+ "homepage": "https://github.com/tahmidjihan/teacup-lib#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/tahmidjihan/teacup-lib/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/tahmidjihan/teacup-lib.git"
24
+ },
25
+ "license": "ISC",
26
+ "author": "Tahmid Jihan, Teacup",
27
+ "type": "module",
28
+ "main": "index.js",
29
+ "exports": "./index.js",
30
+ "files": [
31
+ "index.js",
32
+ "index.d.ts",
33
+ "Analytics/",
34
+ "Controllers/",
35
+ "Functions/",
36
+ "README.md",
37
+ "LICENSE",
38
+ "CHANGELOG.md"
39
+ ],
40
+ "scripts": {
41
+ "test": "echo \"Error: no test specified\" && exit 1"
42
+ },
43
+ "engines": {
44
+ "node": ">=14.0.0"
45
+ }
46
+ }