@ordersune/crm-web-sdk 1.0.11 → 1.0.13

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 CHANGED
@@ -1,131 +1,249 @@
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)
1
+ # Order Sune CRM TypeScript SDK
2
+
3
+ A comprehensive TypeScript SDK for integrating the Order Sune CRM solution into your web applications. Enables seamless user tracking, event monitoring, purchase analytics, in-app messaging, 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
+ ## Quick Start
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
+ batchSize: 10,
25
+ batchInterval: 10000
26
+ });
27
+ ```
28
+
29
+ ## Core Features
30
+
31
+ ### User Management
32
+
33
+ #### User Identification
34
+ Track both registered and guest users:
35
+
36
+ ```typescript
37
+ // Identify a registered user
38
+ crm.identify('user123');
39
+
40
+ // Get current user profile
41
+ const userProfile = crm.getUserProfile();
42
+
43
+ // Clear user data and generate new device ID
44
+ crm.clearUserData();
45
+ ```
46
+
47
+ ### Event Tracking
48
+
49
+ #### Basic Event Tracking
50
+ ```typescript
51
+ // Simple event
52
+ crm.trackEvent('page_view');
53
+
54
+ // Event with properties
55
+ crm.trackEvent('purchase_completed', {
56
+ productId: 'prod_123',
57
+ amount: 99.99,
58
+ currency: 'USD'
59
+ });
60
+
61
+ // Event with custom options
62
+ crm.trackEvent('custom_event',
63
+ { key: 'value' },
64
+ {
65
+ timestamp: '2024-12-28T10:00:00Z',
66
+ requestId: 'req_abc123'
67
+ }
68
+ );
69
+ ```
70
+
71
+ #### Purchase Tracking
72
+ Track detailed purchase events:
73
+
74
+ ```typescript
75
+ crm.logProductPurchase(
76
+ 'order_123', // orderId
77
+ 'item_456', // itemId
78
+ 'Premium Widget', // itemName
79
+ 29.99, // unitPrice
80
+ 2, // quantity
81
+ 'web', // source
82
+ 'direct', // channel
83
+ 'electronics' // itemCategory (optional)
84
+ );
85
+ ```
86
+
87
+ ### Custom Attributes
88
+
89
+ Track persistent user attributes that are sent with every batch:
90
+
91
+ ```typescript
92
+ crm.trackCustomAttribute('preference_theme', 'dark');
93
+ crm.trackCustomAttribute('notification_enabled', true);
94
+ crm.trackCustomAttribute('user_tier', 'premium');
95
+ ```
96
+
97
+ ### Push Notifications
98
+
99
+ #### Token Management
100
+ ```typescript
101
+ // Set push notification token
102
+ crm.setToken('your-push-token');
103
+
104
+ // Log push notification clicks
105
+ crm.logClick('campaign_123');
106
+ ```
107
+
108
+ ### In-App Messaging
109
+
110
+ Display rich in-app messages with customizable styling:
111
+
112
+ ```typescript
113
+ const messageData = JSON.stringify({
114
+ header: "Welcome!",
115
+ message: "Check out our new features",
116
+ modal: {
117
+ button1: {
118
+ type: "Continue",
119
+ backgroundColor: "#007AFF",
120
+ textColor: "#FFFFFF",
121
+ borderColor: "#007AFF",
122
+ webOnClickValue: "redirect_to_web_url",
123
+ webOnClickAction: "https://example.com"
124
+ },
125
+ button2: {
126
+ type: "Skip",
127
+ backgroundColor: "#F2F2F2",
128
+ textColor: "#000000",
129
+ borderColor: "#CCCCCC"
130
+ },
131
+ dismissMessageAutomatically: true,
132
+ dismissMessageInSeconds: "10",
133
+ headerColor: "#000000",
134
+ messageColor: "#666666",
135
+ closeColor: "#999999"
136
+ },
137
+ mediaConfig: {
138
+ inAppImage: "https://example.com/image.png"
139
+ }
140
+ });
141
+
142
+ crm.displayInAppMessage(messageData, 'campaign_456');
143
+ ```
144
+
145
+ ### Batch Processing
146
+
147
+ #### Manual Control
148
+ ```typescript
149
+ // Force send all queued events immediately
150
+ await crm.forceSend();
151
+
152
+ // Clean up resources
153
+ crm.dispose();
154
+ ```
155
+
156
+ ## Configuration Options
157
+
158
+ ### SDKConfig
159
+
160
+ ```typescript
161
+ interface SDKConfig {
162
+ apiKey: string; // Your API key (required)
163
+ endpoint: string; // API endpoint URL (required)
164
+ debug?: boolean; // Enable debug logging
165
+ batchSize?: number; // Events per batch (default: 10)
166
+ batchInterval?: number; // Batch interval in ms (default: 10000)
167
+ }
168
+ ```
169
+
170
+ ## Data Types
171
+
172
+ ### UserProfile
173
+
174
+ ```typescript
175
+ interface UserProfile {
176
+ id: string; // User identifier
177
+ guestUserId?: string; // Guest user identifier
178
+ }
179
+ ```
180
+
181
+ ### EventOptions
182
+
183
+ ```typescript
184
+ interface EventOptions {
185
+ timestamp?: string; // Custom event timestamp
186
+ requestId?: string; // Custom request identifier
187
+ }
188
+ ```
189
+
190
+ ### PurchasePayload
191
+
192
+ ```typescript
193
+ interface PurchasePayload {
194
+ externalId: string; // Order ID
195
+ itemId: string; // Product/item ID
196
+ itemName: string; // Product name
197
+ unitPrice: number; // Price per unit
198
+ quantity: number; // Number of items
199
+ source: string; // Purchase source
200
+ channel: string; // Purchase channel
201
+ itemCategory?: string; // Product category
202
+ }
203
+ ```
204
+
205
+ ## Key Features
206
+
207
+ ### Automatic Functionality
208
+ - **Session Management**: Automatic session tracking with device ID generation
209
+ - **Guest User Handling**: Seamless guest-to-registered user transition
210
+ - **Batch Processing**: Efficient event batching with configurable size and interval
211
+ - **Offline Support**: Event queuing when offline with automatic retry
212
+ - **Device Detection**: Automatic platform and device information collection
213
+ - **Timezone Detection**: Automatic timezone detection and tracking
214
+
215
+ ### Performance Optimizations
216
+ - **Event Queuing**: Intelligent batching to reduce network requests
217
+ - **Session Storage**: Persistent storage for user data and custom attributes
218
+ - **Error Handling**: Robust error handling with automatic retry mechanisms
219
+ - **Memory Management**: Efficient cleanup and disposal methods
220
+
221
+ ### Developer Experience
222
+ - **TypeScript Support**: Full type definitions included
223
+ - **Debug Mode**: Comprehensive logging for development
224
+ - **Flexible Configuration**: Customizable batch sizes and intervals
225
+ - **Modern API**: Promise-based async operations
226
+
227
+ ## Requirements
228
+
229
+ - **TypeScript**: 5.0+
230
+ - **Browser**: Modern browsers with sessionStorage support
231
+ - **Network**: Internet connection for event transmission
232
+ - **Dependencies**: UUID library (automatically installed)
233
+
234
+ ## Browser Compatibility
235
+
236
+ - Chrome 60+
237
+ - Firefox 55+
238
+ - Safari 12+
239
+ - Edge 79+
240
+
241
+ ## License
242
+
243
+ MIT License
244
+
245
+ ## Support & Documentation
246
+
247
+ - [API Documentation](https://docs.ordersune.com/crm)
248
+ - [Support Portal](mailto:support@ordersune.com)
249
+ - [GitHub Issues](https://github.com/ordersune/crm-web-sdk/issues)
@@ -1,5 +1,6 @@
1
1
  export interface UserProfile {
2
2
  id: string;
3
+ guestUserId?: string;
3
4
  }
4
5
  export interface EventOptions {
5
6
  timestamp?: string;
@@ -24,19 +25,9 @@ export interface PurchasePayload {
24
25
  }
25
26
  export interface DeviceDetails {
26
27
  deviceId: string;
27
- deviceModel: string;
28
- browser: string;
29
- browserVersion: string;
30
- language: string;
31
- screenResolution: string;
32
- userAgent: string;
33
28
  platform: string;
34
29
  pushToken?: string;
35
30
  }
36
- export interface BrowserInfo {
37
- browserType: string;
38
- browserVersion: string;
39
- }
40
31
  export interface ButtonProperties {
41
32
  backgroundColor: string;
42
33
  borderColor: string;
package/dist/web-sdk.d.ts CHANGED
@@ -7,6 +7,7 @@ export declare class WebSDK {
7
7
  private readonly batchInterval;
8
8
  private readonly sdkVersion;
9
9
  private deviceId;
10
+ private guestUserId;
10
11
  private deviceDetails?;
11
12
  private currentUser?;
12
13
  private eventQueue;
@@ -34,10 +35,6 @@ export declare class WebSDK {
34
35
  private getGuestUserId;
35
36
  private buildPurchasePayload;
36
37
  private initializeDeviceDetails;
37
- private getBrowserInfo;
38
- private detectDeviceType;
39
- private detectBrowserType;
40
- private detectBrowserVersion;
41
38
  private startBatchProcessing;
42
39
  private queueEvent;
43
40
  private processBatch;
@@ -47,7 +44,7 @@ export declare class WebSDK {
47
44
  private openWebUrl;
48
45
  private showInAppMessage;
49
46
  private logInAppMessageClick;
50
- private logPushNotificationClick;
47
+ logClick(campaignId: string): Promise<void>;
51
48
  private processCampaignClick;
52
49
  private buildCampaignPayload;
53
50
  }
package/dist/web-sdk.js CHANGED
@@ -26,6 +26,7 @@ class WebSDK {
26
26
  this.maxBatchSize = (_b = config.batchSize) !== null && _b !== void 0 ? _b : DEFAULT_BATCH_SIZE;
27
27
  this.batchInterval = (_c = config.batchInterval) !== null && _c !== void 0 ? _c : DEFAULT_BATCH_INTERVAL;
28
28
  this.deviceId = this.getStoredDeviceId() || (0, uuid_1.v4)();
29
+ this.guestUserId = this.getGuestUserId();
29
30
  // Initialize async
30
31
  this.initialize().catch((error) => {
31
32
  (0, utils_1.log)(this.debug, "Async initialization failed", error);
@@ -68,25 +69,38 @@ class WebSDK {
68
69
  if ((storedUser === null || storedUser === void 0 ? void 0 : storedUser.id) === userId)
69
70
  return;
70
71
  (0, utils_1.log)(this.debug, "Identifying user", userId);
71
- this.currentUser = {
72
- id: userId || this.getGuestUserId(),
73
- };
72
+ // If userId is empty or matches guest pattern, use guest user
73
+ if (!userId) {
74
+ this.currentUser = {
75
+ id: this.guestUserId,
76
+ guestUserId: this.guestUserId
77
+ };
78
+ }
79
+ else {
80
+ // Real user identification - include both userId and guestUserId
81
+ this.currentUser = {
82
+ id: userId,
83
+ guestUserId: this.guestUserId
84
+ };
85
+ }
74
86
  this.storeUserProfile();
75
87
  }
76
88
  clearUserData() {
89
+ // Generate new device ID
90
+ this.deviceId = (0, uuid_1.v4)();
91
+ this.guestUserId = this.getGuestUserId();
77
92
  this.currentUser = {
78
- id: this.getGuestUserId(),
93
+ id: this.guestUserId,
94
+ guestUserId: this.guestUserId
79
95
  };
80
96
  this.attributeQueue = {};
81
97
  this.eventQueue = [];
82
98
  this.purchaseBatch = [];
99
+ this.storeDeviceId();
83
100
  sessionStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.current_user`, JSON.stringify(this.currentUser));
84
101
  sessionStorage.removeItem(`${STORAGE_PREFIX}${this.apiKey}.custom_attributes`);
85
- this.trackEvent("user_logged_out", {
86
- device_id: this.deviceId,
87
- });
88
102
  if (this.debug) {
89
- (0, utils_1.log)(this.debug, "User data cleared");
103
+ (0, utils_1.log)(this.debug, "User data cleared, new device ID generated");
90
104
  }
91
105
  }
92
106
  trackEvent(eventName, properties = {}, options = {}) {
@@ -103,7 +117,12 @@ class WebSDK {
103
117
  this.queueEvent(payload);
104
118
  }
105
119
  setToken(token) {
106
- this.deviceDetails.pushToken = token;
120
+ if (this.deviceDetails) {
121
+ this.deviceDetails = {
122
+ ...this.deviceDetails,
123
+ pushToken: token,
124
+ };
125
+ }
107
126
  }
108
127
  trackCustomAttribute(attributeName, attributeValue) {
109
128
  if (!attributeName || typeof attributeName !== "string") {
@@ -155,14 +174,14 @@ class WebSDK {
155
174
  }
156
175
  }
157
176
  getStoredDeviceId() {
158
- return localStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`);
177
+ return sessionStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`);
159
178
  }
160
179
  getStoredUserProfile() {
161
180
  const storedUser = sessionStorage.getItem(`${STORAGE_PREFIX}${this.apiKey}.current_user`);
162
181
  return storedUser ? JSON.parse(storedUser) : null;
163
182
  }
164
183
  storeDeviceId() {
165
- localStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`, this.deviceId);
184
+ sessionStorage.setItem(`${STORAGE_PREFIX}${this.apiKey}.device_id`, this.deviceId);
166
185
  }
167
186
  storeUserProfile() {
168
187
  if (this.currentUser) {
@@ -208,112 +227,11 @@ class WebSDK {
208
227
  };
209
228
  }
210
229
  async initializeDeviceDetails() {
211
- const deviceType = await this.detectDeviceType();
212
- const browserInfo = await this.getBrowserInfo();
213
230
  this.deviceDetails = {
214
231
  deviceId: this.deviceId,
215
- deviceModel: deviceType,
216
- browser: browserInfo.browserType,
217
- browserVersion: browserInfo.browserVersion,
218
- language: navigator.language,
219
- screenResolution: `${window.screen.width}x${window.screen.height}`,
220
- userAgent: navigator.userAgent,
221
232
  platform: 'web',
222
233
  };
223
234
  }
224
- async getBrowserInfo() {
225
- const browserType = this.detectBrowserType();
226
- const browserVersion = this.detectBrowserVersion();
227
- return {
228
- browserType,
229
- browserVersion,
230
- };
231
- }
232
- async detectDeviceType() {
233
- try {
234
- if ("userAgentData" in navigator) {
235
- const data = await navigator.userAgentData.getHighEntropyValues(["platform", "mobile"]);
236
- if (data.mobile) {
237
- return data.platform.toLowerCase().includes("ios")
238
- ? "ios"
239
- : "android";
240
- }
241
- const platform = data.platform.toLowerCase();
242
- if (platform.includes("mac"))
243
- return "mac";
244
- if (platform.includes("win"))
245
- return "windows";
246
- if (platform.includes("linux"))
247
- return "linux";
248
- }
249
- }
250
- catch (error) {
251
- (0, utils_1.log)(this.debug, "Client Hints API failed", error);
252
- }
253
- const userAgent = navigator.userAgent.toLowerCase();
254
- if (/iphone|ipad|ipod/.test(userAgent))
255
- return "ios";
256
- if (/android/.test(userAgent))
257
- return "android";
258
- if (/macintosh|mac os x/.test(userAgent))
259
- return "mac";
260
- if (/windows|win32|win64/.test(userAgent))
261
- return "windows";
262
- if (/linux/.test(userAgent))
263
- return "linux";
264
- return "unknown";
265
- }
266
- detectBrowserType() {
267
- try {
268
- if ("userAgentData" in navigator) {
269
- const brands = navigator.userAgentData.brands;
270
- const brand = brands.find((b) => !["Chrome HTML", "Chromium", "Not A(Brand"].includes(b.brand));
271
- if (brand)
272
- return brand.brand.toLowerCase();
273
- }
274
- const userAgent = navigator.userAgent.toLowerCase();
275
- if (/edg\//.test(userAgent))
276
- return "edge";
277
- if (/chrome/.test(userAgent) && !/edg\//.test(userAgent))
278
- return "chrome";
279
- if (/firefox/.test(userAgent))
280
- return "firefox";
281
- if (/safari/.test(userAgent) && !/chrome/.test(userAgent))
282
- return "safari";
283
- return "unknown";
284
- }
285
- catch (error) {
286
- (0, utils_1.log)(this.debug, "Browser detection failed", error);
287
- return "unknown";
288
- }
289
- }
290
- detectBrowserVersion() {
291
- try {
292
- if ("userAgentData" in navigator) {
293
- const brands = navigator.userAgentData.brands;
294
- const brand = brands.find((b) => !["Chrome HTML", "Chromium", "Not A(Brand"].includes(b.brand));
295
- if (brand)
296
- return brand.version;
297
- }
298
- const userAgent = navigator.userAgent.toLowerCase();
299
- const browserPatterns = {
300
- chrome: /chrome\/(\d+)/,
301
- firefox: /firefox\/(\d+)/,
302
- safari: /version\/(\d+)/,
303
- edge: /edg\/(\d+)/,
304
- };
305
- const browserType = this.detectBrowserType();
306
- const pattern = browserPatterns[browserType];
307
- if (!pattern)
308
- return "unknown";
309
- const match = userAgent.match(pattern);
310
- return match ? match[1] : "unknown";
311
- }
312
- catch (error) {
313
- (0, utils_1.log)(this.debug, "Browser version detection failed", error);
314
- return "unknown";
315
- }
316
- }
317
235
  startBatchProcessing() {
318
236
  this.batchProcessingInterval = setInterval(() => {
319
237
  if (this.eventQueue.length > 0 ||
@@ -359,7 +277,7 @@ class WebSDK {
359
277
  }
360
278
  }
361
279
  async sendBatchToServer(events, purchases, currentAttributes) {
362
- var _a;
280
+ var _a, _b;
363
281
  if (!this.deviceDetails) {
364
282
  await this.initializeDeviceDetails();
365
283
  }
@@ -367,11 +285,13 @@ class WebSDK {
367
285
  sdkVersion: this.sdkVersion,
368
286
  deviceInfo: this.deviceDetails,
369
287
  userId: (_a = this.currentUser) === null || _a === void 0 ? void 0 : _a.id,
288
+ guestUserId: (_b = this.currentUser) === null || _b === void 0 ? void 0 : _b.guestUserId,
370
289
  time: Date.now(),
371
290
  events: events,
372
291
  purchases: purchases,
373
292
  userAttributes: currentAttributes,
374
293
  };
294
+ (0, utils_1.log)(this.debug, "Sending batch to server", payload);
375
295
  try {
376
296
  const response = await fetch(`${this.endpoint}/analytics/data`, {
377
297
  method: "POST",
@@ -618,7 +538,7 @@ class WebSDK {
618
538
  const campaignClickPayload = await this.buildCampaignPayload(campaignId, opened, clicked, dismissed);
619
539
  await this.processCampaignClick(campaignClickPayload);
620
540
  }
621
- async logPushNotificationClick(campaignId) {
541
+ async logClick(campaignId) {
622
542
  const pushCampaignClickPayload = await this.buildCampaignPayload(campaignId, true, true);
623
543
  await this.processCampaignClick(pushCampaignClickPayload);
624
544
  }
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
- {
2
- "name": "@ordersune/crm-web-sdk",
3
- "version": "1.0.11",
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
- }
1
+ {
2
+ "name": "@ordersune/crm-web-sdk",
3
+ "version": "1.0.13",
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
+ }