@clianta/sdk 1.5.1 → 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/CHANGELOG.md +20 -0
- package/dist/angular.cjs.js +259 -45
- package/dist/angular.cjs.js.map +1 -1
- package/dist/angular.d.ts +69 -0
- package/dist/angular.esm.js +259 -45
- package/dist/angular.esm.js.map +1 -1
- package/dist/clianta.cjs.js +259 -45
- package/dist/clianta.cjs.js.map +1 -1
- package/dist/clianta.esm.js +259 -45
- package/dist/clianta.esm.js.map +1 -1
- package/dist/clianta.umd.js +259 -45
- package/dist/clianta.umd.js.map +1 -1
- package/dist/clianta.umd.min.js +2 -2
- package/dist/clianta.umd.min.js.map +1 -1
- package/dist/index.d.ts +150 -7
- package/dist/react.cjs.js +326 -57
- package/dist/react.cjs.js.map +1 -1
- package/dist/react.d.ts +89 -3
- package/dist/react.esm.js +327 -59
- package/dist/react.esm.js.map +1 -1
- package/dist/svelte.cjs.js +259 -45
- package/dist/svelte.cjs.js.map +1 -1
- package/dist/svelte.d.ts +69 -0
- package/dist/svelte.esm.js +259 -45
- package/dist/svelte.esm.js.map +1 -1
- package/dist/vue.cjs.js +259 -45
- package/dist/vue.cjs.js.map +1 -1
- package/dist/vue.d.ts +69 -0
- package/dist/vue.esm.js +259 -45
- package/dist/vue.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/vue.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Clianta SDK v1.
|
|
2
|
+
* Clianta SDK v1.6.0
|
|
3
3
|
* (c) 2026 Clianta
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -12,7 +12,7 @@ var vue = require('vue');
|
|
|
12
12
|
* @see SDK_VERSION in core/config.ts
|
|
13
13
|
*/
|
|
14
14
|
/** SDK Version */
|
|
15
|
-
const SDK_VERSION = '1.
|
|
15
|
+
const SDK_VERSION = '1.6.0';
|
|
16
16
|
/** Default API endpoint — reads from env or falls back to localhost */
|
|
17
17
|
const getDefaultApiEndpoint = () => {
|
|
18
18
|
// Build-time env var (works with Next.js, Vite, CRA, etc.)
|
|
@@ -3694,6 +3694,85 @@ class CRMClient {
|
|
|
3694
3694
|
}
|
|
3695
3695
|
}
|
|
3696
3696
|
|
|
3697
|
+
/**
|
|
3698
|
+
* Privacy-safe visitor API client.
|
|
3699
|
+
* All methods return data for the current visitor only (no cross-visitor access).
|
|
3700
|
+
*/
|
|
3701
|
+
class VisitorClient {
|
|
3702
|
+
constructor(transport, workspaceId, visitorId) {
|
|
3703
|
+
this.transport = transport;
|
|
3704
|
+
this.workspaceId = workspaceId;
|
|
3705
|
+
this.visitorId = visitorId;
|
|
3706
|
+
}
|
|
3707
|
+
/** Update visitorId (e.g. after reset) */
|
|
3708
|
+
setVisitorId(id) {
|
|
3709
|
+
this.visitorId = id;
|
|
3710
|
+
}
|
|
3711
|
+
basePath() {
|
|
3712
|
+
return `/api/public/track/visitor/${this.workspaceId}/${this.visitorId}`;
|
|
3713
|
+
}
|
|
3714
|
+
/**
|
|
3715
|
+
* Get the current visitor's profile from the CRM.
|
|
3716
|
+
* Returns visitor data and linked contact info if identified.
|
|
3717
|
+
*/
|
|
3718
|
+
async getProfile() {
|
|
3719
|
+
const result = await this.transport.fetchData(`${this.basePath()}/profile`);
|
|
3720
|
+
if (result.success && result.data) {
|
|
3721
|
+
logger.debug('Visitor profile fetched:', result.data);
|
|
3722
|
+
return result.data;
|
|
3723
|
+
}
|
|
3724
|
+
logger.warn('Failed to fetch visitor profile:', result.error);
|
|
3725
|
+
return null;
|
|
3726
|
+
}
|
|
3727
|
+
/**
|
|
3728
|
+
* Get the current visitor's recent activity/events.
|
|
3729
|
+
* Returns paginated list of tracking events.
|
|
3730
|
+
*/
|
|
3731
|
+
async getActivity(options) {
|
|
3732
|
+
const params = {};
|
|
3733
|
+
if (options?.page)
|
|
3734
|
+
params.page = options.page.toString();
|
|
3735
|
+
if (options?.limit)
|
|
3736
|
+
params.limit = options.limit.toString();
|
|
3737
|
+
if (options?.eventType)
|
|
3738
|
+
params.eventType = options.eventType;
|
|
3739
|
+
if (options?.startDate)
|
|
3740
|
+
params.startDate = options.startDate;
|
|
3741
|
+
if (options?.endDate)
|
|
3742
|
+
params.endDate = options.endDate;
|
|
3743
|
+
const result = await this.transport.fetchData(`${this.basePath()}/activity`, params);
|
|
3744
|
+
if (result.success && result.data) {
|
|
3745
|
+
return result.data;
|
|
3746
|
+
}
|
|
3747
|
+
logger.warn('Failed to fetch visitor activity:', result.error);
|
|
3748
|
+
return null;
|
|
3749
|
+
}
|
|
3750
|
+
/**
|
|
3751
|
+
* Get a summarized journey timeline for the current visitor.
|
|
3752
|
+
* Includes top pages, sessions, time spent, and recent activities.
|
|
3753
|
+
*/
|
|
3754
|
+
async getTimeline() {
|
|
3755
|
+
const result = await this.transport.fetchData(`${this.basePath()}/timeline`);
|
|
3756
|
+
if (result.success && result.data) {
|
|
3757
|
+
return result.data;
|
|
3758
|
+
}
|
|
3759
|
+
logger.warn('Failed to fetch visitor timeline:', result.error);
|
|
3760
|
+
return null;
|
|
3761
|
+
}
|
|
3762
|
+
/**
|
|
3763
|
+
* Get engagement metrics for the current visitor.
|
|
3764
|
+
* Includes time on site, page views, bounce rate, and engagement score.
|
|
3765
|
+
*/
|
|
3766
|
+
async getEngagement() {
|
|
3767
|
+
const result = await this.transport.fetchData(`${this.basePath()}/engagement`);
|
|
3768
|
+
if (result.success && result.data) {
|
|
3769
|
+
return result.data;
|
|
3770
|
+
}
|
|
3771
|
+
logger.warn('Failed to fetch visitor engagement:', result.error);
|
|
3772
|
+
return null;
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
|
|
3697
3776
|
/**
|
|
3698
3777
|
* Clianta SDK - Main Tracker Class
|
|
3699
3778
|
* @see SDK_VERSION in core/config.ts
|
|
@@ -3707,10 +3786,16 @@ class Tracker {
|
|
|
3707
3786
|
this.isInitialized = false;
|
|
3708
3787
|
/** contactId after a successful identify() call */
|
|
3709
3788
|
this.contactId = null;
|
|
3789
|
+
/** groupId after a successful group() call */
|
|
3790
|
+
this.groupId = null;
|
|
3710
3791
|
/** Pending identify retry on next flush */
|
|
3711
3792
|
this.pendingIdentify = null;
|
|
3712
3793
|
/** Registered event schemas for validation */
|
|
3713
3794
|
this.eventSchemas = new Map();
|
|
3795
|
+
/** Event middleware pipeline */
|
|
3796
|
+
this.middlewares = [];
|
|
3797
|
+
/** Ready callbacks */
|
|
3798
|
+
this.readyCallbacks = [];
|
|
3714
3799
|
if (!workspaceId) {
|
|
3715
3800
|
throw new Error('[Clianta] Workspace ID is required');
|
|
3716
3801
|
}
|
|
@@ -3736,6 +3821,8 @@ class Tracker {
|
|
|
3736
3821
|
this.visitorId = this.createVisitorId();
|
|
3737
3822
|
this.sessionId = this.createSessionId();
|
|
3738
3823
|
logger.debug('IDs created', { visitorId: this.visitorId, sessionId: this.sessionId });
|
|
3824
|
+
// Initialize visitor API client
|
|
3825
|
+
this.visitor = new VisitorClient(this.transport, this.workspaceId, this.visitorId);
|
|
3739
3826
|
// Security warnings
|
|
3740
3827
|
if (this.config.apiEndpoint.startsWith('http://') &&
|
|
3741
3828
|
typeof window !== 'undefined' &&
|
|
@@ -3750,6 +3837,16 @@ class Tracker {
|
|
|
3750
3837
|
this.initPlugins();
|
|
3751
3838
|
this.isInitialized = true;
|
|
3752
3839
|
logger.info('SDK initialized successfully');
|
|
3840
|
+
// Fire ready callbacks
|
|
3841
|
+
for (const cb of this.readyCallbacks) {
|
|
3842
|
+
try {
|
|
3843
|
+
cb();
|
|
3844
|
+
}
|
|
3845
|
+
catch (e) {
|
|
3846
|
+
logger.error('onReady callback error:', e);
|
|
3847
|
+
}
|
|
3848
|
+
}
|
|
3849
|
+
this.readyCallbacks = [];
|
|
3753
3850
|
}
|
|
3754
3851
|
/**
|
|
3755
3852
|
* Create visitor ID based on storage mode
|
|
@@ -3862,6 +3959,10 @@ class Tracker {
|
|
|
3862
3959
|
if (this.contactId) {
|
|
3863
3960
|
event.contactId = this.contactId;
|
|
3864
3961
|
}
|
|
3962
|
+
// Attach groupId if known (from a prior group() call)
|
|
3963
|
+
if (this.groupId) {
|
|
3964
|
+
event.groupId = this.groupId;
|
|
3965
|
+
}
|
|
3865
3966
|
// Validate event against registered schema (debug mode only)
|
|
3866
3967
|
this.validateEventSchema(eventType, properties);
|
|
3867
3968
|
// Check consent before tracking
|
|
@@ -3875,8 +3976,11 @@ class Tracker {
|
|
|
3875
3976
|
logger.debug('Event dropped (no consent):', eventName);
|
|
3876
3977
|
return;
|
|
3877
3978
|
}
|
|
3878
|
-
|
|
3879
|
-
|
|
3979
|
+
// Run event through middleware pipeline
|
|
3980
|
+
this.runMiddleware(event, () => {
|
|
3981
|
+
this.queue.push(event);
|
|
3982
|
+
logger.debug('Event tracked:', eventName, properties);
|
|
3983
|
+
});
|
|
3880
3984
|
}
|
|
3881
3985
|
/**
|
|
3882
3986
|
* Track a page view
|
|
@@ -3938,80 +4042,47 @@ class Tracker {
|
|
|
3938
4042
|
}
|
|
3939
4043
|
/**
|
|
3940
4044
|
* Get the current visitor's profile from the CRM.
|
|
3941
|
-
*
|
|
3942
|
-
* Only returns data for the current visitor (privacy-safe for frontend).
|
|
4045
|
+
* @deprecated Use `tracker.visitor.getProfile()` instead.
|
|
3943
4046
|
*/
|
|
3944
4047
|
async getVisitorProfile() {
|
|
3945
4048
|
if (!this.isInitialized) {
|
|
3946
4049
|
logger.warn('SDK not initialized');
|
|
3947
4050
|
return null;
|
|
3948
4051
|
}
|
|
3949
|
-
|
|
3950
|
-
if (result.success && result.data) {
|
|
3951
|
-
logger.debug('Visitor profile fetched:', result.data);
|
|
3952
|
-
return result.data;
|
|
3953
|
-
}
|
|
3954
|
-
logger.warn('Failed to fetch visitor profile:', result.error);
|
|
3955
|
-
return null;
|
|
4052
|
+
return this.visitor.getProfile();
|
|
3956
4053
|
}
|
|
3957
4054
|
/**
|
|
3958
4055
|
* Get the current visitor's recent activity/events.
|
|
3959
|
-
*
|
|
4056
|
+
* @deprecated Use `tracker.visitor.getActivity()` instead.
|
|
3960
4057
|
*/
|
|
3961
4058
|
async getVisitorActivity(options) {
|
|
3962
4059
|
if (!this.isInitialized) {
|
|
3963
4060
|
logger.warn('SDK not initialized');
|
|
3964
4061
|
return null;
|
|
3965
4062
|
}
|
|
3966
|
-
|
|
3967
|
-
if (options?.page)
|
|
3968
|
-
params.page = options.page.toString();
|
|
3969
|
-
if (options?.limit)
|
|
3970
|
-
params.limit = options.limit.toString();
|
|
3971
|
-
if (options?.eventType)
|
|
3972
|
-
params.eventType = options.eventType;
|
|
3973
|
-
if (options?.startDate)
|
|
3974
|
-
params.startDate = options.startDate;
|
|
3975
|
-
if (options?.endDate)
|
|
3976
|
-
params.endDate = options.endDate;
|
|
3977
|
-
const result = await this.transport.fetchData(`/api/public/track/visitor/${this.workspaceId}/${this.visitorId}/activity`, params);
|
|
3978
|
-
if (result.success && result.data) {
|
|
3979
|
-
return result.data;
|
|
3980
|
-
}
|
|
3981
|
-
logger.warn('Failed to fetch visitor activity:', result.error);
|
|
3982
|
-
return null;
|
|
4063
|
+
return this.visitor.getActivity(options);
|
|
3983
4064
|
}
|
|
3984
4065
|
/**
|
|
3985
4066
|
* Get a summarized journey timeline for the current visitor.
|
|
3986
|
-
*
|
|
4067
|
+
* @deprecated Use `tracker.visitor.getTimeline()` instead.
|
|
3987
4068
|
*/
|
|
3988
4069
|
async getVisitorTimeline() {
|
|
3989
4070
|
if (!this.isInitialized) {
|
|
3990
4071
|
logger.warn('SDK not initialized');
|
|
3991
4072
|
return null;
|
|
3992
4073
|
}
|
|
3993
|
-
|
|
3994
|
-
if (result.success && result.data) {
|
|
3995
|
-
return result.data;
|
|
3996
|
-
}
|
|
3997
|
-
logger.warn('Failed to fetch visitor timeline:', result.error);
|
|
3998
|
-
return null;
|
|
4074
|
+
return this.visitor.getTimeline();
|
|
3999
4075
|
}
|
|
4000
4076
|
/**
|
|
4001
4077
|
* Get engagement metrics for the current visitor.
|
|
4002
|
-
*
|
|
4078
|
+
* @deprecated Use `tracker.visitor.getEngagement()` instead.
|
|
4003
4079
|
*/
|
|
4004
4080
|
async getVisitorEngagement() {
|
|
4005
4081
|
if (!this.isInitialized) {
|
|
4006
4082
|
logger.warn('SDK not initialized');
|
|
4007
4083
|
return null;
|
|
4008
4084
|
}
|
|
4009
|
-
|
|
4010
|
-
if (result.success && result.data) {
|
|
4011
|
-
return result.data;
|
|
4012
|
-
}
|
|
4013
|
-
logger.warn('Failed to fetch visitor engagement:', result.error);
|
|
4014
|
-
return null;
|
|
4085
|
+
return this.visitor.getEngagement();
|
|
4015
4086
|
}
|
|
4016
4087
|
/**
|
|
4017
4088
|
* Retry pending identify call
|
|
@@ -4042,6 +4113,149 @@ class Tracker {
|
|
|
4042
4113
|
logger.enabled = enabled;
|
|
4043
4114
|
logger.info(`Debug mode ${enabled ? 'enabled' : 'disabled'}`);
|
|
4044
4115
|
}
|
|
4116
|
+
// ============================================
|
|
4117
|
+
// GROUP, ALIAS, SCREEN
|
|
4118
|
+
// ============================================
|
|
4119
|
+
/**
|
|
4120
|
+
* Associate the current visitor with a group (company/account).
|
|
4121
|
+
* The groupId will be attached to all subsequent track() calls.
|
|
4122
|
+
*/
|
|
4123
|
+
group(groupId, traits = {}) {
|
|
4124
|
+
if (!groupId) {
|
|
4125
|
+
logger.warn('groupId is required for group()');
|
|
4126
|
+
return;
|
|
4127
|
+
}
|
|
4128
|
+
this.groupId = groupId;
|
|
4129
|
+
logger.info('Visitor grouped:', groupId);
|
|
4130
|
+
this.track('group', 'Group Identified', {
|
|
4131
|
+
groupId,
|
|
4132
|
+
...traits,
|
|
4133
|
+
});
|
|
4134
|
+
}
|
|
4135
|
+
/**
|
|
4136
|
+
* Merge two visitor identities.
|
|
4137
|
+
* Links `previousId` (typically the anonymous visitor) to `newId` (the known user).
|
|
4138
|
+
* If `previousId` is omitted, the current visitorId is used.
|
|
4139
|
+
*/
|
|
4140
|
+
async alias(newId, previousId) {
|
|
4141
|
+
if (!newId) {
|
|
4142
|
+
logger.warn('newId is required for alias()');
|
|
4143
|
+
return false;
|
|
4144
|
+
}
|
|
4145
|
+
const prevId = previousId || this.visitorId;
|
|
4146
|
+
logger.info('Aliasing visitor:', { from: prevId, to: newId });
|
|
4147
|
+
try {
|
|
4148
|
+
const url = `${this.config.apiEndpoint}/api/public/track/alias`;
|
|
4149
|
+
const response = await fetch(url, {
|
|
4150
|
+
method: 'POST',
|
|
4151
|
+
headers: { 'Content-Type': 'application/json' },
|
|
4152
|
+
body: JSON.stringify({
|
|
4153
|
+
workspaceId: this.workspaceId,
|
|
4154
|
+
previousId: prevId,
|
|
4155
|
+
newId,
|
|
4156
|
+
}),
|
|
4157
|
+
});
|
|
4158
|
+
if (response.ok) {
|
|
4159
|
+
logger.info('Alias successful');
|
|
4160
|
+
return true;
|
|
4161
|
+
}
|
|
4162
|
+
logger.error('Alias failed:', response.status);
|
|
4163
|
+
return false;
|
|
4164
|
+
}
|
|
4165
|
+
catch (error) {
|
|
4166
|
+
logger.error('Alias request failed:', error);
|
|
4167
|
+
return false;
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
/**
|
|
4171
|
+
* Track a screen view (for mobile-first PWAs and SPAs).
|
|
4172
|
+
* Similar to page() but semantically for app screens.
|
|
4173
|
+
*/
|
|
4174
|
+
screen(name, properties = {}) {
|
|
4175
|
+
this.track('screen_view', name, {
|
|
4176
|
+
...properties,
|
|
4177
|
+
screenName: name,
|
|
4178
|
+
});
|
|
4179
|
+
}
|
|
4180
|
+
// ============================================
|
|
4181
|
+
// MIDDLEWARE
|
|
4182
|
+
// ============================================
|
|
4183
|
+
/**
|
|
4184
|
+
* Register event middleware.
|
|
4185
|
+
* Middleware functions receive the event and a `next` callback.
|
|
4186
|
+
* Call `next()` to pass the event through, or don't call it to drop the event.
|
|
4187
|
+
*
|
|
4188
|
+
* @example
|
|
4189
|
+
* tracker.use((event, next) => {
|
|
4190
|
+
* // Strip PII from events
|
|
4191
|
+
* delete event.properties.email;
|
|
4192
|
+
* next(); // pass it through
|
|
4193
|
+
* });
|
|
4194
|
+
*/
|
|
4195
|
+
use(middleware) {
|
|
4196
|
+
this.middlewares.push(middleware);
|
|
4197
|
+
logger.debug('Middleware registered');
|
|
4198
|
+
}
|
|
4199
|
+
/**
|
|
4200
|
+
* Run event through the middleware pipeline.
|
|
4201
|
+
* Executes each middleware in order; if any skips `next()`, the event is dropped.
|
|
4202
|
+
*/
|
|
4203
|
+
runMiddleware(event, finalCallback) {
|
|
4204
|
+
if (this.middlewares.length === 0) {
|
|
4205
|
+
finalCallback();
|
|
4206
|
+
return;
|
|
4207
|
+
}
|
|
4208
|
+
let index = 0;
|
|
4209
|
+
const middlewares = this.middlewares;
|
|
4210
|
+
const next = () => {
|
|
4211
|
+
index++;
|
|
4212
|
+
if (index < middlewares.length) {
|
|
4213
|
+
try {
|
|
4214
|
+
middlewares[index](event, next);
|
|
4215
|
+
}
|
|
4216
|
+
catch (e) {
|
|
4217
|
+
logger.error('Middleware error:', e);
|
|
4218
|
+
finalCallback();
|
|
4219
|
+
}
|
|
4220
|
+
}
|
|
4221
|
+
else {
|
|
4222
|
+
finalCallback();
|
|
4223
|
+
}
|
|
4224
|
+
};
|
|
4225
|
+
try {
|
|
4226
|
+
middlewares[0](event, next);
|
|
4227
|
+
}
|
|
4228
|
+
catch (e) {
|
|
4229
|
+
logger.error('Middleware error:', e);
|
|
4230
|
+
finalCallback();
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
// ============================================
|
|
4234
|
+
// LIFECYCLE
|
|
4235
|
+
// ============================================
|
|
4236
|
+
/**
|
|
4237
|
+
* Register a callback to be invoked when the SDK is fully initialized.
|
|
4238
|
+
* If already initialized, the callback fires immediately.
|
|
4239
|
+
*/
|
|
4240
|
+
onReady(callback) {
|
|
4241
|
+
if (this.isInitialized) {
|
|
4242
|
+
try {
|
|
4243
|
+
callback();
|
|
4244
|
+
}
|
|
4245
|
+
catch (e) {
|
|
4246
|
+
logger.error('onReady callback error:', e);
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
else {
|
|
4250
|
+
this.readyCallbacks.push(callback);
|
|
4251
|
+
}
|
|
4252
|
+
}
|
|
4253
|
+
/**
|
|
4254
|
+
* Check if the SDK is fully initialized and ready.
|
|
4255
|
+
*/
|
|
4256
|
+
isReady() {
|
|
4257
|
+
return this.isInitialized;
|
|
4258
|
+
}
|
|
4045
4259
|
/**
|
|
4046
4260
|
* Register a schema for event validation.
|
|
4047
4261
|
* When debug mode is enabled, events will be validated against registered schemas.
|