@ordersune/crm-web-sdk 1.0.6
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/LICENSE +1 -0
- package/README.md +131 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/web-sdk.d.ts +32 -0
- package/dist/web-sdk.js +218 -0
- package/package.json +24 -0
package/LICENSE
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MIT License
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Order Sune CRM TypeScript SDK
|
|
2
|
+
|
|
3
|
+
A powerful TypeScript SDK for integrating the Order Sune CRM solution into your web applications. Enables seamless user tracking, event monitoring, and customer data management.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ordersune/crm-web-sdk
|
|
9
|
+
# or
|
|
10
|
+
yarn add @ordersune/crm-web-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Initialize the SDK
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { WebSDK } from '@ordersune/crm-web-sdk';
|
|
19
|
+
|
|
20
|
+
const crm = new WebSDK({
|
|
21
|
+
apiKey: 'your-api-key',
|
|
22
|
+
endpoint: 'https://api.example.com',
|
|
23
|
+
debug: false
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### User Identification
|
|
28
|
+
|
|
29
|
+
Identify and track users with custom traits:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Identify a registered user
|
|
33
|
+
crm.identify('user123', {
|
|
34
|
+
email: 'user@example.com',
|
|
35
|
+
name: 'John Doe',
|
|
36
|
+
subscription: 'premium'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Get current user profile
|
|
40
|
+
const userProfile = crm.getUserProfile();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Event Tracking
|
|
44
|
+
|
|
45
|
+
Track user events with custom properties:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
// Basic event tracking
|
|
49
|
+
crm.trackEvent('page_view');
|
|
50
|
+
|
|
51
|
+
// Event with properties
|
|
52
|
+
crm.trackEvent('purchase_completed', {
|
|
53
|
+
productId: 'prod_123',
|
|
54
|
+
amount: 99.99,
|
|
55
|
+
currency: 'USD'
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Event with custom options
|
|
59
|
+
crm.trackEvent('custom_event',
|
|
60
|
+
{ key: 'value' },
|
|
61
|
+
{
|
|
62
|
+
timestamp: '2024-12-28T10:00:00Z',
|
|
63
|
+
requestId: 'req_abc123'
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Custom Attributes
|
|
69
|
+
|
|
70
|
+
Track persistent user attributes:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
crm.trackCustomAttribute('preference_theme', 'dark');
|
|
74
|
+
crm.trackCustomAttribute('notification_enabled', true);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Types
|
|
78
|
+
|
|
79
|
+
### SDKConfig
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
interface SDKConfig {
|
|
83
|
+
apiKey: string; // Your API key
|
|
84
|
+
endpoint: string; // API endpoint URL
|
|
85
|
+
debug?: boolean; // Enable debug logging
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### UserProfile
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
interface UserProfile {
|
|
93
|
+
id: string; // User identifier
|
|
94
|
+
user_type: string; // 'registered' or 'guest'
|
|
95
|
+
traits: Record<string, any>; // Custom user traits
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### EventOptions
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
interface EventOptions {
|
|
103
|
+
timestamp?: string; // Custom event timestamp
|
|
104
|
+
requestId?: string; // Custom request identifier
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Features
|
|
109
|
+
|
|
110
|
+
- Automatic session tracking
|
|
111
|
+
- Device and browser detection
|
|
112
|
+
- Batch event processing
|
|
113
|
+
- Offline event queuing
|
|
114
|
+
- TypeScript support with full type definitions
|
|
115
|
+
- Debug mode for development
|
|
116
|
+
|
|
117
|
+
## Requirements
|
|
118
|
+
|
|
119
|
+
- TypeScript 5.0+
|
|
120
|
+
- Modern browser environment with localStorage support
|
|
121
|
+
- Stable internet connection for event sending
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT License
|
|
126
|
+
|
|
127
|
+
For detailed API documentation and examples, visit our [documentation site](https://docs.ordersune.com/crm).
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
Need help? [Contact Support](mailto:support@ordersune.com)
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface UserProfile {
|
|
2
|
+
id: string;
|
|
3
|
+
user_type: string;
|
|
4
|
+
traits: Record<string, any>;
|
|
5
|
+
}
|
|
6
|
+
export interface EventOptions {
|
|
7
|
+
timestamp?: string;
|
|
8
|
+
requestId?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface SDKConfig {
|
|
11
|
+
apiKey: string;
|
|
12
|
+
endpoint: string;
|
|
13
|
+
debug?: boolean;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const log: (debug: boolean, message: string, ...args: any[]) => void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SDKConfig, EventOptions, UserProfile } from "./types";
|
|
2
|
+
export declare class WebSDK {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly endpoint;
|
|
5
|
+
private readonly debug;
|
|
6
|
+
private readonly maxBatchSize;
|
|
7
|
+
private readonly batchInterval;
|
|
8
|
+
private readonly sdkVersion;
|
|
9
|
+
private deviceId;
|
|
10
|
+
private deviceDetails?;
|
|
11
|
+
private currentUser?;
|
|
12
|
+
private eventQueue;
|
|
13
|
+
private isProcessingQueue;
|
|
14
|
+
private customAttributes;
|
|
15
|
+
constructor(config: SDKConfig);
|
|
16
|
+
identify(userId: string, traits?: Record<string, any>): void;
|
|
17
|
+
trackEvent(eventName: string, properties?: Record<string, any>, options?: EventOptions): void;
|
|
18
|
+
trackCustomAttribute(attributeName: string, attributeValue: any): void;
|
|
19
|
+
getUserProfile(): UserProfile | undefined;
|
|
20
|
+
private initialize;
|
|
21
|
+
private getStoredDeviceId;
|
|
22
|
+
private storeDeviceId;
|
|
23
|
+
private getGuestUserId;
|
|
24
|
+
private initializeDeviceDetails;
|
|
25
|
+
private detectDeviceType;
|
|
26
|
+
private detectBrowserType;
|
|
27
|
+
private detectBrowserVersion;
|
|
28
|
+
private startBatchProcessing;
|
|
29
|
+
private queueEvent;
|
|
30
|
+
private processBatch;
|
|
31
|
+
private sendBatchToServer;
|
|
32
|
+
}
|
package/dist/web-sdk.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebSDK = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
const STORAGE_PREFIX = "os.";
|
|
7
|
+
const DEFAULT_BATCH_SIZE = 10;
|
|
8
|
+
const DEFAULT_BATCH_INTERVAL = 10000;
|
|
9
|
+
const SDK_VERSION = "1.0.6";
|
|
10
|
+
class WebSDK {
|
|
11
|
+
constructor(config) {
|
|
12
|
+
var _a;
|
|
13
|
+
this.maxBatchSize = DEFAULT_BATCH_SIZE;
|
|
14
|
+
this.batchInterval = DEFAULT_BATCH_INTERVAL;
|
|
15
|
+
this.sdkVersion = SDK_VERSION;
|
|
16
|
+
this.eventQueue = [];
|
|
17
|
+
this.isProcessingQueue = false;
|
|
18
|
+
this.customAttributes = {};
|
|
19
|
+
this.apiKey = config.apiKey;
|
|
20
|
+
this.endpoint = config.endpoint;
|
|
21
|
+
this.debug = (_a = config.debug) !== null && _a !== void 0 ? _a : false;
|
|
22
|
+
this.deviceId = this.getStoredDeviceId() || (0, uuid_1.v4)();
|
|
23
|
+
this.initialize();
|
|
24
|
+
}
|
|
25
|
+
identify(userId, traits = {}) {
|
|
26
|
+
var _a;
|
|
27
|
+
this.currentUser = {
|
|
28
|
+
id: userId || this.getGuestUserId(),
|
|
29
|
+
user_type: userId ? "registered" : "guest",
|
|
30
|
+
traits: { ...(_a = this.currentUser) === null || _a === void 0 ? void 0 : _a.traits, ...traits },
|
|
31
|
+
};
|
|
32
|
+
this.trackEvent("user_identified", {
|
|
33
|
+
user_id: this.currentUser.id,
|
|
34
|
+
traits,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
trackEvent(eventName, properties = {}, options = {}) {
|
|
38
|
+
const payload = {
|
|
39
|
+
deviceId: this.deviceId,
|
|
40
|
+
eventName,
|
|
41
|
+
timestamp: options.timestamp || Date.now(),
|
|
42
|
+
requestId: options.requestId || (0, uuid_1.v4)(),
|
|
43
|
+
properties,
|
|
44
|
+
};
|
|
45
|
+
this.queueEvent(payload);
|
|
46
|
+
}
|
|
47
|
+
trackCustomAttribute(attributeName, attributeValue) {
|
|
48
|
+
this.customAttributes[attributeName] = attributeValue;
|
|
49
|
+
}
|
|
50
|
+
getUserProfile() {
|
|
51
|
+
return this.currentUser;
|
|
52
|
+
}
|
|
53
|
+
initialize() {
|
|
54
|
+
this.storeDeviceId();
|
|
55
|
+
this.initializeDeviceDetails();
|
|
56
|
+
this.identify("");
|
|
57
|
+
this.startBatchProcessing();
|
|
58
|
+
(0, utils_1.log)(this.debug, "SDK Initialized");
|
|
59
|
+
}
|
|
60
|
+
getStoredDeviceId() {
|
|
61
|
+
return localStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`);
|
|
62
|
+
}
|
|
63
|
+
storeDeviceId() {
|
|
64
|
+
localStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`, this.deviceId);
|
|
65
|
+
}
|
|
66
|
+
getGuestUserId() {
|
|
67
|
+
return `guest_user_${this.deviceId}`;
|
|
68
|
+
}
|
|
69
|
+
async initializeDeviceDetails() {
|
|
70
|
+
this.deviceDetails = {
|
|
71
|
+
deviceModel: await this.detectDeviceType(),
|
|
72
|
+
browser: this.detectBrowserType(),
|
|
73
|
+
browserVersion: this.detectBrowserVersion(),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async detectDeviceType() {
|
|
77
|
+
if ("userAgentData" in navigator) {
|
|
78
|
+
try {
|
|
79
|
+
const data = await navigator.userAgentData.getHighEntropyValues(["platform", "mobile"]);
|
|
80
|
+
if (data.mobile) {
|
|
81
|
+
return data.platform.toLowerCase().includes("ios")
|
|
82
|
+
? "ios"
|
|
83
|
+
: "android";
|
|
84
|
+
}
|
|
85
|
+
const platform = data.platform.toLowerCase();
|
|
86
|
+
if (platform.includes("mac"))
|
|
87
|
+
return "mac";
|
|
88
|
+
if (platform.includes("win"))
|
|
89
|
+
return "windows";
|
|
90
|
+
if (platform.includes("linux"))
|
|
91
|
+
return "linux";
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
(0, utils_1.log)(this.debug, "Client Hints API failed", error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
98
|
+
if (/iphone|ipad|ipod/.test(userAgent))
|
|
99
|
+
return "ios";
|
|
100
|
+
if (/android/.test(userAgent))
|
|
101
|
+
return "android";
|
|
102
|
+
if (/macintosh|mac os x/.test(userAgent))
|
|
103
|
+
return "mac";
|
|
104
|
+
if (/windows|win32|win64/.test(userAgent))
|
|
105
|
+
return "windows";
|
|
106
|
+
if (/linux/.test(userAgent))
|
|
107
|
+
return "linux";
|
|
108
|
+
return "unknown";
|
|
109
|
+
}
|
|
110
|
+
detectBrowserType() {
|
|
111
|
+
if ("userAgentData" in navigator) {
|
|
112
|
+
try {
|
|
113
|
+
const brands = navigator.userAgentData.brands;
|
|
114
|
+
const brand = brands.find((b) => !["Chrome HTML", "Chromium", "Not A(Brand"].includes(b.brand));
|
|
115
|
+
if (brand)
|
|
116
|
+
return brand.brand.toLowerCase();
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
(0, utils_1.log)(this.debug, "Browser detection failed", error);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
123
|
+
if (/edg\//.test(userAgent))
|
|
124
|
+
return "edge";
|
|
125
|
+
if (/chrome/.test(userAgent) && !/edg\//.test(userAgent))
|
|
126
|
+
return "chrome";
|
|
127
|
+
if (/firefox/.test(userAgent))
|
|
128
|
+
return "firefox";
|
|
129
|
+
if (/safari/.test(userAgent) && !/chrome/.test(userAgent))
|
|
130
|
+
return "safari";
|
|
131
|
+
return "unknown";
|
|
132
|
+
}
|
|
133
|
+
detectBrowserVersion() {
|
|
134
|
+
if ("userAgentData" in navigator) {
|
|
135
|
+
try {
|
|
136
|
+
const brands = navigator.userAgentData.brands;
|
|
137
|
+
const brand = brands.find((b) => !["Chrome HTML", "Chromium", "Not A(Brand"].includes(b.brand));
|
|
138
|
+
if (brand)
|
|
139
|
+
return brand.version;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
(0, utils_1.log)(this.debug, "Browser version detection failed", error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
146
|
+
const browserPatterns = {
|
|
147
|
+
chrome: /chrome\/(\d+)/,
|
|
148
|
+
firefox: /firefox\/(\d+)/,
|
|
149
|
+
safari: /version\/(\d+)/,
|
|
150
|
+
edge: /edg\/(\d+)/,
|
|
151
|
+
};
|
|
152
|
+
const browserType = this.detectBrowserType();
|
|
153
|
+
const pattern = browserPatterns[browserType];
|
|
154
|
+
if (!pattern)
|
|
155
|
+
return "unknown";
|
|
156
|
+
const match = userAgent.match(pattern);
|
|
157
|
+
return match ? match[1] : "unknown";
|
|
158
|
+
}
|
|
159
|
+
startBatchProcessing() {
|
|
160
|
+
setInterval(() => {
|
|
161
|
+
if (this.eventQueue.length > 0) {
|
|
162
|
+
this.processBatch();
|
|
163
|
+
}
|
|
164
|
+
}, this.batchInterval);
|
|
165
|
+
}
|
|
166
|
+
queueEvent(payload) {
|
|
167
|
+
this.eventQueue.push(payload);
|
|
168
|
+
(0, utils_1.log)(this.debug, "Event queued", payload);
|
|
169
|
+
if (this.eventQueue.length >= this.maxBatchSize) {
|
|
170
|
+
this.processBatch();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async processBatch() {
|
|
174
|
+
if (this.isProcessingQueue)
|
|
175
|
+
return;
|
|
176
|
+
this.isProcessingQueue = true;
|
|
177
|
+
const batchToSend = this.eventQueue.splice(0, this.maxBatchSize);
|
|
178
|
+
try {
|
|
179
|
+
await this.sendBatchToServer(batchToSend);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
this.eventQueue.unshift(...batchToSend);
|
|
183
|
+
(0, utils_1.log)(this.debug, "Batch processing failed", error);
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
this.isProcessingQueue = false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async sendBatchToServer(batch) {
|
|
190
|
+
var _a;
|
|
191
|
+
const payload = {
|
|
192
|
+
sdkVersion: this.sdkVersion,
|
|
193
|
+
deviceInfo: this.deviceDetails,
|
|
194
|
+
userId: (_a = this.currentUser) === null || _a === void 0 ? void 0 : _a.id,
|
|
195
|
+
events: batch,
|
|
196
|
+
userAttributes: this.customAttributes,
|
|
197
|
+
};
|
|
198
|
+
try {
|
|
199
|
+
const response = await fetch(`${this.endpoint}/analytics/data`, {
|
|
200
|
+
method: "POST",
|
|
201
|
+
headers: {
|
|
202
|
+
"Content-Type": "application/json",
|
|
203
|
+
"x-api-key": this.apiKey,
|
|
204
|
+
},
|
|
205
|
+
body: JSON.stringify(payload),
|
|
206
|
+
});
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
209
|
+
}
|
|
210
|
+
await response.json();
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
(0, utils_1.log)(this.debug, "Failed to send batch to server", error);
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.WebSDK = WebSDK;
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ordersune/crm-web-sdk",
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"prepare": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"uuid": "^11.0.3"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.0.0",
|
|
22
|
+
"@types/uuid": "^9.0.0"
|
|
23
|
+
}
|
|
24
|
+
}
|