@grainql/analytics-web 1.3.0 → 1.6.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.
- package/README.md +421 -2
- package/dist/cjs/index.d.ts +107 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +107 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.ts +107 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.global.dev.js +331 -3
- package/dist/index.global.dev.js.map +2 -2
- package/dist/index.global.js +2 -2
- package/dist/index.global.js.map +3 -3
- package/dist/index.js +358 -2
- package/dist/index.mjs +358 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @grainql/analytics-web
|
|
2
2
|
|
|
3
|
-
A lightweight, dependency-free TypeScript SDK for sending analytics events
|
|
3
|
+
A lightweight, dependency-free TypeScript SDK for sending analytics events and managing remote configurations via Grain's REST API with automatic batching, retry logic, and reliable event delivery.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -13,6 +13,7 @@ A lightweight, dependency-free TypeScript SDK for sending analytics events to Gr
|
|
|
13
13
|
- 🎯 **TypeScript first** - Full type safety out of the box
|
|
14
14
|
- 👤 **Global user tracking** - Set user ID once, used for all events
|
|
15
15
|
- 📊 **Template events** - Pre-built event tracking for common scenarios
|
|
16
|
+
- ⚙️ **Remote Config** - Dynamic configuration management with caching and real-time updates
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -20,6 +21,8 @@ A lightweight, dependency-free TypeScript SDK for sending analytics events to Gr
|
|
|
20
21
|
npm install @grainql/analytics-web
|
|
21
22
|
```
|
|
22
23
|
|
|
24
|
+
> **Latest Version**: v1.6.0 includes comprehensive remote configuration management capabilities alongside the existing analytics features.
|
|
25
|
+
|
|
23
26
|
## Quick Start
|
|
24
27
|
|
|
25
28
|
### Basic Usage (No Authentication)
|
|
@@ -41,7 +44,7 @@ grain.track('page_view', {
|
|
|
41
44
|
// Track with user ID
|
|
42
45
|
grain.track('button_click', {
|
|
43
46
|
button: 'signup',
|
|
44
|
-
userId: 'user123'
|
|
47
|
+
userId: 'user123' // Note: Subject to same security restrictions as setProperty
|
|
45
48
|
});
|
|
46
49
|
```
|
|
47
50
|
|
|
@@ -63,6 +66,43 @@ grain.setUserId('user123');
|
|
|
63
66
|
grain.track('page_view', { page: '/dashboard' });
|
|
64
67
|
```
|
|
65
68
|
|
|
69
|
+
### User Properties
|
|
70
|
+
|
|
71
|
+
Set user properties that can be used for analytics and segmentation:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// Set properties for the current user
|
|
75
|
+
await grain.setProperty({
|
|
76
|
+
plan: 'premium',
|
|
77
|
+
status: 'active',
|
|
78
|
+
signupDate: '2024-01-15',
|
|
79
|
+
source: 'web'
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Set properties for a specific user
|
|
83
|
+
await grain.setProperty({
|
|
84
|
+
plan: 'free',
|
|
85
|
+
lastLogin: new Date().toISOString()
|
|
86
|
+
}, { userId: 'user123' });
|
|
87
|
+
|
|
88
|
+
// Properties are automatically serialized to strings
|
|
89
|
+
await grain.setProperty({
|
|
90
|
+
isActive: true, // Becomes "true"
|
|
91
|
+
count: 42, // Becomes "42"
|
|
92
|
+
metadata: { // Becomes JSON string
|
|
93
|
+
source: 'api',
|
|
94
|
+
version: '2.0'
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Important Security Notes:**
|
|
100
|
+
- You can set up to 4 properties per request, and all values are automatically converted to strings
|
|
101
|
+
- **UserId Override Restrictions**: When using `{ userId: 'specific-user' }` in options, ensure you have proper permissions:
|
|
102
|
+
- If your tenant requires JWT authentication, the userId must match the JWT subject
|
|
103
|
+
- Grain may block requests if too many distinct userIds are used from the same instance, browser, device, or IP
|
|
104
|
+
- Use userId overrides only when you have explicit permission to set properties for other users
|
|
105
|
+
|
|
66
106
|
### Server-Side Authentication
|
|
67
107
|
|
|
68
108
|
```typescript
|
|
@@ -88,6 +128,196 @@ const grain = createGrainAnalytics({
|
|
|
88
128
|
});
|
|
89
129
|
```
|
|
90
130
|
|
|
131
|
+
## Remote Config
|
|
132
|
+
|
|
133
|
+
The SDK includes powerful remote configuration capabilities that allow you to dynamically control your application's behavior without code deployments.
|
|
134
|
+
|
|
135
|
+
### Basic Usage
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const grain = createGrainAnalytics({
|
|
139
|
+
tenantId: 'your-tenant-id',
|
|
140
|
+
userId: 'user123',
|
|
141
|
+
// Set default values for immediate access
|
|
142
|
+
defaultConfigurations: {
|
|
143
|
+
hero_text: 'Welcome to our app!',
|
|
144
|
+
button_color: 'blue',
|
|
145
|
+
feature_enabled: 'false'
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Get configuration value (synchronous, from cache or defaults)
|
|
150
|
+
const heroText = grain.getConfig('hero_text'); // Returns cached value or default
|
|
151
|
+
|
|
152
|
+
// Get configuration asynchronously (cache-first, with API fallback)
|
|
153
|
+
const buttonColor = await grain.getConfigAsync('button_color');
|
|
154
|
+
|
|
155
|
+
// Get all configurations
|
|
156
|
+
const allConfigs = grain.getAllConfigs();
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Preloading Configurations
|
|
160
|
+
|
|
161
|
+
Preload configurations at page load for immediate access:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Set user ID first
|
|
165
|
+
grain.setUserId('user123');
|
|
166
|
+
|
|
167
|
+
// Preload specific keys for immediate access
|
|
168
|
+
await grain.preloadConfig(['hero_text', 'button_color', 'feature_enabled']);
|
|
169
|
+
|
|
170
|
+
// Now these values are available synchronously
|
|
171
|
+
const heroText = grain.getConfig('hero_text');
|
|
172
|
+
const buttonColor = grain.getConfig('button_color');
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Advanced Configuration Options
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const grain = createGrainAnalytics({
|
|
179
|
+
tenantId: 'your-tenant-id',
|
|
180
|
+
userId: 'user123',
|
|
181
|
+
// Default values for immediate access
|
|
182
|
+
defaultConfigurations: {
|
|
183
|
+
hero_text: 'Default Hero Text',
|
|
184
|
+
button_color: 'blue',
|
|
185
|
+
feature_enabled: 'false'
|
|
186
|
+
},
|
|
187
|
+
// Custom cache key
|
|
188
|
+
configCacheKey: 'my_app_config',
|
|
189
|
+
// Auto-refresh every 2 minutes
|
|
190
|
+
configRefreshInterval: 120000,
|
|
191
|
+
// Enable/disable caching
|
|
192
|
+
enableConfigCache: true
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Fetching Configurations with Properties
|
|
197
|
+
|
|
198
|
+
Send user properties to get personalized configurations:
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// Fetch with user properties for personalization
|
|
202
|
+
const configs = await grain.getAllConfigsAsync({
|
|
203
|
+
properties: {
|
|
204
|
+
plan: 'premium',
|
|
205
|
+
location: 'US',
|
|
206
|
+
signup_date: '2024-01-15'
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Or fetch specific keys with properties
|
|
211
|
+
const heroText = await grain.getConfigAsync('hero_text', {
|
|
212
|
+
properties: {
|
|
213
|
+
plan: 'premium',
|
|
214
|
+
location: 'US'
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Configuration Change Listeners
|
|
220
|
+
|
|
221
|
+
Listen for configuration changes in real-time:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// Add a listener for configuration changes
|
|
225
|
+
grain.addConfigChangeListener((configurations) => {
|
|
226
|
+
console.log('Configurations updated:', configurations);
|
|
227
|
+
|
|
228
|
+
// Update UI based on new configurations
|
|
229
|
+
if (configurations.hero_text) {
|
|
230
|
+
document.getElementById('hero').textContent = configurations.hero_text;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (configurations.button_color) {
|
|
234
|
+
document.getElementById('cta-button').style.backgroundColor = configurations.button_color;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Remove listener when no longer needed
|
|
239
|
+
const listener = (configs) => { /* ... */ };
|
|
240
|
+
grain.addConfigChangeListener(listener);
|
|
241
|
+
grain.removeConfigChangeListener(listener);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Force Refresh
|
|
245
|
+
|
|
246
|
+
Force refresh configurations from the API:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// Force refresh a specific configuration
|
|
250
|
+
const latestHeroText = await grain.getConfigAsync('hero_text', {
|
|
251
|
+
forceRefresh: true
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Force refresh all configurations
|
|
255
|
+
const allLatestConfigs = await grain.getAllConfigsAsync({
|
|
256
|
+
forceRefresh: true
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Error Handling
|
|
261
|
+
|
|
262
|
+
The SDK gracefully handles configuration fetch failures:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
try {
|
|
266
|
+
const configs = await grain.getAllConfigsAsync();
|
|
267
|
+
// Use configurations
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error('Failed to fetch configurations:', error);
|
|
270
|
+
// Fall back to default values
|
|
271
|
+
const heroText = grain.getConfig('hero_text'); // Returns default if available
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### React Integration Example
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { useEffect, useState } from 'react';
|
|
279
|
+
import { createGrainAnalytics } from '@grainql/analytics-web';
|
|
280
|
+
|
|
281
|
+
const grain = createGrainAnalytics({
|
|
282
|
+
tenantId: 'your-tenant-id',
|
|
283
|
+
userId: 'user123',
|
|
284
|
+
defaultConfigurations: {
|
|
285
|
+
hero_text: 'Loading...',
|
|
286
|
+
button_color: 'blue'
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
function App() {
|
|
291
|
+
const [configs, setConfigs] = useState(grain.getAllConfigs());
|
|
292
|
+
|
|
293
|
+
useEffect(() => {
|
|
294
|
+
// Preload configurations
|
|
295
|
+
grain.preloadConfig(['hero_text', 'button_color']).then(() => {
|
|
296
|
+
setConfigs(grain.getAllConfigs());
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Listen for configuration changes
|
|
300
|
+
const handleConfigChange = (newConfigs) => {
|
|
301
|
+
setConfigs(newConfigs);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
grain.addConfigChangeListener(handleConfigChange);
|
|
305
|
+
|
|
306
|
+
return () => {
|
|
307
|
+
grain.removeConfigChangeListener(handleConfigChange);
|
|
308
|
+
};
|
|
309
|
+
}, []);
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<div>
|
|
313
|
+
<h1 style={{ color: configs.button_color }}>
|
|
314
|
+
{configs.hero_text}
|
|
315
|
+
</h1>
|
|
316
|
+
</div>
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
91
321
|
## Template Events
|
|
92
322
|
|
|
93
323
|
The SDK provides pre-built event tracking methods for common scenarios:
|
|
@@ -191,6 +421,11 @@ interface GrainConfig {
|
|
|
191
421
|
retryAttempts?: number; // Retry attempts for failed requests (default: 3)
|
|
192
422
|
retryDelay?: number; // Base retry delay in ms (default: 1000)
|
|
193
423
|
debug?: boolean; // Enable debug logging (default: false)
|
|
424
|
+
// Remote Config options
|
|
425
|
+
defaultConfigurations?: Record<string, string>; // Default values for configurations
|
|
426
|
+
configCacheKey?: string; // Custom cache key for configurations (default: 'grain_config')
|
|
427
|
+
configRefreshInterval?: number; // Auto-refresh interval in ms (default: 300000)
|
|
428
|
+
enableConfigCache?: boolean; // Enable/disable configuration caching (default: true)
|
|
194
429
|
}
|
|
195
430
|
```
|
|
196
431
|
|
|
@@ -248,6 +483,33 @@ Alias for `setUserId()` - sets user ID for subsequent events:
|
|
|
248
483
|
grain.identify('user123');
|
|
249
484
|
```
|
|
250
485
|
|
|
486
|
+
#### `setProperty(properties, options?)`
|
|
487
|
+
|
|
488
|
+
Set user properties for analytics and segmentation:
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
// Set properties for current user
|
|
492
|
+
await grain.setProperty({
|
|
493
|
+
plan: 'premium',
|
|
494
|
+
status: 'active',
|
|
495
|
+
signupDate: '2024-01-15'
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// Set properties for specific user
|
|
499
|
+
await grain.setProperty({
|
|
500
|
+
plan: 'free'
|
|
501
|
+
}, { userId: 'user123' });
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**Parameters:**
|
|
505
|
+
- `properties`: Object with up to 4 key-value pairs
|
|
506
|
+
- `options.userId`: Optional user ID override
|
|
507
|
+
|
|
508
|
+
**Security Considerations:**
|
|
509
|
+
- When using `options.userId`, ensure you have proper permissions to set properties for other users
|
|
510
|
+
- With JWT authentication, the userId must match the JWT subject
|
|
511
|
+
- Grain may block requests if too many distinct userIds are used from the same source
|
|
512
|
+
|
|
251
513
|
#### `flush()`
|
|
252
514
|
|
|
253
515
|
Manually flush all queued events:
|
|
@@ -264,6 +526,88 @@ Clean up resources and send remaining events:
|
|
|
264
526
|
grain.destroy();
|
|
265
527
|
```
|
|
266
528
|
|
|
529
|
+
### Remote Config Methods
|
|
530
|
+
|
|
531
|
+
#### `getConfig(key)`
|
|
532
|
+
|
|
533
|
+
Get configuration value synchronously (from cache or defaults):
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
const heroText = grain.getConfig('hero_text'); // Returns string | undefined
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
#### `getAllConfigs()`
|
|
540
|
+
|
|
541
|
+
Get all configurations synchronously (from cache or defaults):
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
const configs = grain.getAllConfigs(); // Returns Record<string, string>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
#### `getConfigAsync(key, options?)`
|
|
548
|
+
|
|
549
|
+
Get configuration value asynchronously (cache-first with API fallback):
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
const heroText = await grain.getConfigAsync('hero_text');
|
|
553
|
+
const buttonColor = await grain.getConfigAsync('button_color', {
|
|
554
|
+
properties: { plan: 'premium' },
|
|
555
|
+
forceRefresh: true
|
|
556
|
+
});
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
#### `getAllConfigsAsync(options?)`
|
|
560
|
+
|
|
561
|
+
Get all configurations asynchronously (cache-first with API fallback):
|
|
562
|
+
|
|
563
|
+
```typescript
|
|
564
|
+
const configs = await grain.getAllConfigsAsync();
|
|
565
|
+
const allConfigs = await grain.getAllConfigsAsync({
|
|
566
|
+
properties: { plan: 'premium', location: 'US' },
|
|
567
|
+
forceRefresh: true
|
|
568
|
+
});
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
#### `fetchConfig(options?)`
|
|
572
|
+
|
|
573
|
+
Fetch configurations directly from API:
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
const response = await grain.fetchConfig({
|
|
577
|
+
immediateKeys: ['hero_text', 'button_color'],
|
|
578
|
+
properties: { plan: 'premium' }
|
|
579
|
+
});
|
|
580
|
+
// Returns RemoteConfigResponse with full API response
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
#### `preloadConfig(immediateKeys?, properties?)`
|
|
584
|
+
|
|
585
|
+
Preload configurations for immediate access:
|
|
586
|
+
|
|
587
|
+
```typescript
|
|
588
|
+
await grain.preloadConfig(['hero_text', 'button_color']);
|
|
589
|
+
// Configurations are now available synchronously
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
#### `addConfigChangeListener(listener)`
|
|
593
|
+
|
|
594
|
+
Add listener for configuration changes:
|
|
595
|
+
|
|
596
|
+
```typescript
|
|
597
|
+
const listener = (configurations) => {
|
|
598
|
+
console.log('Configs updated:', configurations);
|
|
599
|
+
};
|
|
600
|
+
grain.addConfigChangeListener(listener);
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
#### `removeConfigChangeListener(listener)`
|
|
604
|
+
|
|
605
|
+
Remove configuration change listener:
|
|
606
|
+
|
|
607
|
+
```typescript
|
|
608
|
+
grain.removeConfigChangeListener(listener);
|
|
609
|
+
```
|
|
610
|
+
|
|
267
611
|
### Template Event Methods
|
|
268
612
|
|
|
269
613
|
#### Authentication Events
|
|
@@ -317,6 +661,21 @@ interface CheckoutEventProperties {
|
|
|
317
661
|
}
|
|
318
662
|
```
|
|
319
663
|
|
|
664
|
+
## Security Considerations
|
|
665
|
+
|
|
666
|
+
### User ID Override Restrictions
|
|
667
|
+
|
|
668
|
+
When using userId overrides in event tracking or property setting, be aware of these security restrictions:
|
|
669
|
+
|
|
670
|
+
- **JWT Authentication**: If your tenant requires JWT authentication, any userId override must match the JWT subject
|
|
671
|
+
- **Rate Limiting**: Grain may block requests if too many distinct userIds are used from the same instance, browser, device, or IP address
|
|
672
|
+
- **Permissions**: Only use userId overrides when you have explicit permission to track events or set properties for other users
|
|
673
|
+
|
|
674
|
+
**Best Practices:**
|
|
675
|
+
- Use global `setUserId()` for the current user instead of per-event userId overrides
|
|
676
|
+
- Avoid switching between many different userIds from the same client
|
|
677
|
+
- Ensure your authentication strategy aligns with your userId usage patterns
|
|
678
|
+
|
|
320
679
|
## Authentication Strategies
|
|
321
680
|
|
|
322
681
|
### NONE
|
|
@@ -411,6 +770,66 @@ await grain.trackPageView({ page: '/dashboard' });
|
|
|
411
770
|
grain.setUserId(null);
|
|
412
771
|
```
|
|
413
772
|
|
|
773
|
+
## Changelog
|
|
774
|
+
|
|
775
|
+
### [1.6.0] - 2025-09-08
|
|
776
|
+
|
|
777
|
+
#### Added
|
|
778
|
+
- **Remote Config API**: Complete remote configuration management system
|
|
779
|
+
- `getConfig()` and `getAllConfigs()` for synchronous access
|
|
780
|
+
- `getConfigAsync()` and `getAllConfigsAsync()` for async access with cache-first strategy
|
|
781
|
+
- `fetchConfig()` for direct API calls
|
|
782
|
+
- `preloadConfig()` for preloading configurations at page load
|
|
783
|
+
- Configuration change listeners with `addConfigChangeListener()` and `removeConfigChangeListener()`
|
|
784
|
+
- Automatic configuration caching with localStorage persistence
|
|
785
|
+
- Auto-refresh timer for keeping configurations up-to-date
|
|
786
|
+
- Default values support for immediate access without API calls
|
|
787
|
+
- User properties support for personalized configurations
|
|
788
|
+
- Force refresh option to bypass cache
|
|
789
|
+
- Full authentication support (NONE, SERVER_SIDE, JWT)
|
|
790
|
+
- **Enhanced Configuration Options**:
|
|
791
|
+
- `defaultConfigurations` for setting default values
|
|
792
|
+
- `configCacheKey` for custom cache keys
|
|
793
|
+
- `configRefreshInterval` for auto-refresh timing
|
|
794
|
+
- `enableConfigCache` for cache control
|
|
795
|
+
|
|
796
|
+
#### Technical
|
|
797
|
+
- Added comprehensive remote config interfaces and types
|
|
798
|
+
- Implemented robust error handling and retry logic for config API
|
|
799
|
+
- Added localStorage-based caching with graceful fallbacks
|
|
800
|
+
- Integrated config refresh timer with proper cleanup
|
|
801
|
+
- Enhanced TypeScript interfaces for better type safety
|
|
802
|
+
- Added comprehensive test coverage for remote config functionality
|
|
803
|
+
- Improved test stability and reliability
|
|
804
|
+
|
|
805
|
+
### [1.4.0] - 2024-12-19
|
|
806
|
+
|
|
807
|
+
#### Added
|
|
808
|
+
- **User Properties API**: New `setProperty()` method for setting user properties
|
|
809
|
+
- Set up to 4 properties per request
|
|
810
|
+
- Automatic string serialization for all values
|
|
811
|
+
- Support for user-specific property overrides
|
|
812
|
+
- Full authentication support (NONE, SERVER_SIDE, JWT)
|
|
813
|
+
- **Updated API Endpoints**:
|
|
814
|
+
- Events now use `/v1/events/{tenant}/multi` endpoint
|
|
815
|
+
- Properties use `/v1/events/{tenant}/properties` endpoint
|
|
816
|
+
|
|
817
|
+
#### Changed
|
|
818
|
+
- Updated all event sending to use the new `/multi` endpoint
|
|
819
|
+
- Enhanced error handling and retry logic for properties API
|
|
820
|
+
|
|
821
|
+
#### Technical
|
|
822
|
+
- Added comprehensive test coverage for properties functionality
|
|
823
|
+
- Updated all existing tests to use new endpoint structure
|
|
824
|
+
- Improved TypeScript interfaces for better type safety
|
|
825
|
+
|
|
826
|
+
### [1.3.0] - Previous Release
|
|
827
|
+
|
|
828
|
+
- Template events for common analytics scenarios
|
|
829
|
+
- Enhanced user ID management
|
|
830
|
+
- Improved error handling and retry logic
|
|
831
|
+
- Cross-platform compatibility improvements
|
|
832
|
+
|
|
414
833
|
## License
|
|
415
834
|
|
|
416
835
|
MIT
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -30,10 +30,49 @@ export interface GrainConfig {
|
|
|
30
30
|
retryDelay?: number;
|
|
31
31
|
maxEventsPerRequest?: number;
|
|
32
32
|
debug?: boolean;
|
|
33
|
+
defaultConfigurations?: Record<string, string>;
|
|
34
|
+
configCacheKey?: string;
|
|
35
|
+
configRefreshInterval?: number;
|
|
36
|
+
enableConfigCache?: boolean;
|
|
33
37
|
}
|
|
34
38
|
export interface SendEventOptions {
|
|
35
39
|
flush?: boolean;
|
|
36
40
|
}
|
|
41
|
+
export interface SetPropertyOptions {
|
|
42
|
+
userId?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface PropertyPayload {
|
|
45
|
+
userId: string;
|
|
46
|
+
[key: string]: string;
|
|
47
|
+
}
|
|
48
|
+
export interface RemoteConfigRequest {
|
|
49
|
+
userId: string;
|
|
50
|
+
immediateKeys: string[];
|
|
51
|
+
properties?: Record<string, string>;
|
|
52
|
+
}
|
|
53
|
+
export interface RemoteConfigResponse {
|
|
54
|
+
userId: string;
|
|
55
|
+
snapshotId: string;
|
|
56
|
+
configurations: Record<string, string>;
|
|
57
|
+
isFinal: boolean;
|
|
58
|
+
qualifiedSegments: string[];
|
|
59
|
+
qualifiedRuleSets: string[];
|
|
60
|
+
timestamp: string;
|
|
61
|
+
isFromCache: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface RemoteConfigOptions {
|
|
64
|
+
immediateKeys?: string[];
|
|
65
|
+
properties?: Record<string, string>;
|
|
66
|
+
userId?: string;
|
|
67
|
+
forceRefresh?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export interface RemoteConfigCache {
|
|
70
|
+
configurations: Record<string, string>;
|
|
71
|
+
snapshotId: string;
|
|
72
|
+
timestamp: string;
|
|
73
|
+
userId: string;
|
|
74
|
+
}
|
|
75
|
+
export type ConfigChangeListener = (configurations: Record<string, string>) => void;
|
|
37
76
|
export interface LoginEventProperties extends Record<string, unknown> {
|
|
38
77
|
method?: string;
|
|
39
78
|
success?: boolean;
|
|
@@ -124,6 +163,10 @@ export declare class GrainAnalytics {
|
|
|
124
163
|
private flushTimer;
|
|
125
164
|
private isDestroyed;
|
|
126
165
|
private globalUserId;
|
|
166
|
+
private configCache;
|
|
167
|
+
private configRefreshTimer;
|
|
168
|
+
private configChangeListeners;
|
|
169
|
+
private configFetchPromise;
|
|
127
170
|
constructor(config: GrainConfig);
|
|
128
171
|
private validateConfig;
|
|
129
172
|
private log;
|
|
@@ -152,6 +195,14 @@ export declare class GrainAnalytics {
|
|
|
152
195
|
* Get current global user ID
|
|
153
196
|
*/
|
|
154
197
|
getUserId(): string | null;
|
|
198
|
+
/**
|
|
199
|
+
* Set user properties
|
|
200
|
+
*/
|
|
201
|
+
setProperty(properties: Record<string, unknown>, options?: SetPropertyOptions): Promise<void>;
|
|
202
|
+
/**
|
|
203
|
+
* Send properties to the API
|
|
204
|
+
*/
|
|
205
|
+
private sendProperties;
|
|
155
206
|
/**
|
|
156
207
|
* Track user login event
|
|
157
208
|
*/
|
|
@@ -188,6 +239,62 @@ export declare class GrainAnalytics {
|
|
|
188
239
|
* Manually flush all queued events
|
|
189
240
|
*/
|
|
190
241
|
flush(): Promise<void>;
|
|
242
|
+
/**
|
|
243
|
+
* Initialize configuration cache from localStorage
|
|
244
|
+
*/
|
|
245
|
+
private initializeConfigCache;
|
|
246
|
+
/**
|
|
247
|
+
* Save configuration cache to localStorage
|
|
248
|
+
*/
|
|
249
|
+
private saveConfigCache;
|
|
250
|
+
/**
|
|
251
|
+
* Get configuration value with fallback to defaults
|
|
252
|
+
*/
|
|
253
|
+
getConfig(key: string): string | undefined;
|
|
254
|
+
/**
|
|
255
|
+
* Get all configurations with fallback to defaults
|
|
256
|
+
*/
|
|
257
|
+
getAllConfigs(): Record<string, string>;
|
|
258
|
+
/**
|
|
259
|
+
* Fetch configurations from API
|
|
260
|
+
*/
|
|
261
|
+
fetchConfig(options?: RemoteConfigOptions): Promise<RemoteConfigResponse>;
|
|
262
|
+
/**
|
|
263
|
+
* Get configuration asynchronously (cache-first with fallback to API)
|
|
264
|
+
*/
|
|
265
|
+
getConfigAsync(key: string, options?: RemoteConfigOptions): Promise<string | undefined>;
|
|
266
|
+
/**
|
|
267
|
+
* Get all configurations asynchronously (cache-first with fallback to API)
|
|
268
|
+
*/
|
|
269
|
+
getAllConfigsAsync(options?: RemoteConfigOptions): Promise<Record<string, string>>;
|
|
270
|
+
/**
|
|
271
|
+
* Update configuration cache and notify listeners
|
|
272
|
+
*/
|
|
273
|
+
private updateConfigCache;
|
|
274
|
+
/**
|
|
275
|
+
* Add configuration change listener
|
|
276
|
+
*/
|
|
277
|
+
addConfigChangeListener(listener: ConfigChangeListener): void;
|
|
278
|
+
/**
|
|
279
|
+
* Remove configuration change listener
|
|
280
|
+
*/
|
|
281
|
+
removeConfigChangeListener(listener: ConfigChangeListener): void;
|
|
282
|
+
/**
|
|
283
|
+
* Notify all configuration change listeners
|
|
284
|
+
*/
|
|
285
|
+
private notifyConfigChangeListeners;
|
|
286
|
+
/**
|
|
287
|
+
* Start automatic configuration refresh timer
|
|
288
|
+
*/
|
|
289
|
+
private startConfigRefreshTimer;
|
|
290
|
+
/**
|
|
291
|
+
* Stop automatic configuration refresh timer
|
|
292
|
+
*/
|
|
293
|
+
private stopConfigRefreshTimer;
|
|
294
|
+
/**
|
|
295
|
+
* Preload configurations for immediate access
|
|
296
|
+
*/
|
|
297
|
+
preloadConfig(immediateKeys?: string[], properties?: Record<string, string>): Promise<void>;
|
|
191
298
|
/**
|
|
192
299
|
* Split events array into chunks of specified size
|
|
193
300
|
*/
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|