@sygnl/identity-manager 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,12 @@
1
+ All Rights Reserved
2
+
3
+ Copyright (c) 2025 Edge Foundry, Inc.
4
+
5
+ This software and associated documentation files (the "Software") are proprietary
6
+ and confidential to Edge Foundry, Inc.
7
+
8
+ Unauthorized copying, modification, distribution, or use of this Software,
9
+ via any medium, is strictly prohibited without the express written permission
10
+ of Edge Foundry, Inc.
11
+
12
+ For licensing inquiries, please contact: legal@sygnl.com
package/README.md ADDED
@@ -0,0 +1,467 @@
1
+ # @sygnl/identity-manager
2
+
3
+ > Lightweight identity and session management with cookie + localStorage fallback
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@sygnl/identity-manager.svg)](https://www.npmjs.com/package/@sygnl/identity-manager)
6
+ [![License](https://img.shields.io/npm/l/@sygnl/identity-manager.svg)](https://github.com/sygnl/identity-manager/blob/main/LICENSE)
7
+
8
+ ## Features
9
+
10
+ - ๐ŸŽฏ **Zero Dependencies** - Fully self-contained
11
+ - ๐Ÿ”’ **Privacy-First** - Anonymous user identification without PII
12
+ - ๐Ÿ’พ **Dual Storage** - Cookie + localStorage fallback for maximum persistence
13
+ - ๐ŸŒ **SSR-Safe** - Works in both browser and Node.js environments
14
+ - โš™๏ธ **Fully Configurable** - Customize every aspect of cookie/storage behavior
15
+ - ๐Ÿงช **Well Tested** - Comprehensive test suite with >90% coverage
16
+ - ๐Ÿ“ฆ **TypeScript Native** - Full type definitions included
17
+ - ๐Ÿš€ **Tiny Bundle** - ~2KB minified + gzipped
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @sygnl/identity-manager
23
+ ```
24
+
25
+ ```bash
26
+ yarn add @sygnl/identity-manager
27
+ ```
28
+
29
+ ```bash
30
+ pnpm add @sygnl/identity-manager
31
+ ```
32
+
33
+ ## Quick Start
34
+
35
+ ```typescript
36
+ import { IdentityManager } from '@sygnl/identity-manager';
37
+
38
+ // Create instance with default settings
39
+ const identity = new IdentityManager();
40
+
41
+ // Get or create anonymous user ID (365-day persistence)
42
+ const userId = identity.ensureAnonymousId();
43
+ // โ†’ "a3f2b8c9-4d5e-4f6a-8b9c-1d2e3f4a5b6c"
44
+
45
+ // Get or create session ID (1-day persistence)
46
+ const sessionId = identity.ensureSessionId();
47
+ // โ†’ "sess_1704067200000"
48
+ ```
49
+
50
+ ## Use Cases
51
+
52
+ ### Analytics & Tracking
53
+
54
+ Track user behavior across sessions without requiring login:
55
+
56
+ ```typescript
57
+ const identity = new IdentityManager();
58
+
59
+ // Track page view with persistent user ID
60
+ analytics.track('page_view', {
61
+ userId: identity.ensureAnonymousId(),
62
+ sessionId: identity.ensureSessionId(),
63
+ page: window.location.pathname,
64
+ });
65
+ ```
66
+
67
+ ### A/B Testing
68
+
69
+ Consistently assign users to experiment groups:
70
+
71
+ ```typescript
72
+ const identity = new IdentityManager();
73
+ const userId = identity.ensureAnonymousId();
74
+
75
+ // User always gets same variant across sessions
76
+ const variant = hashUserId(userId) % 2 === 0 ? 'A' : 'B';
77
+ ```
78
+
79
+ ### Shopping Cart Persistence
80
+
81
+ Associate cart with anonymous user before login:
82
+
83
+ ```typescript
84
+ const identity = new IdentityManager();
85
+
86
+ async function addToCart(productId: string) {
87
+ await fetch('/api/cart', {
88
+ method: 'POST',
89
+ body: JSON.stringify({
90
+ anonymousId: identity.ensureAnonymousId(),
91
+ productId,
92
+ }),
93
+ });
94
+ }
95
+ ```
96
+
97
+ ### Form Progress Tracking
98
+
99
+ Resume incomplete forms across sessions:
100
+
101
+ ```typescript
102
+ const identity = new IdentityManager();
103
+ const formKey = `form_${identity.ensureAnonymousId()}`;
104
+
105
+ // Save progress
106
+ localStorage.setItem(formKey, JSON.stringify(formData));
107
+
108
+ // Resume later
109
+ const savedData = localStorage.getItem(formKey);
110
+ ```
111
+
112
+ ## API Reference
113
+
114
+ ### Constructor
115
+
116
+ ```typescript
117
+ new IdentityManager(options?: PartialIdentityManagerOptions)
118
+ ```
119
+
120
+ Creates a new IdentityManager instance with optional configuration.
121
+
122
+ #### Options
123
+
124
+ | Option | Type | Default | Description |
125
+ |--------|------|---------|-------------|
126
+ | `anonymousIdCookieName` | `string` | `'_stid'` | Cookie name for anonymous ID |
127
+ | `sessionIdCookieName` | `string` | `'_session_id'` | Cookie name for session ID |
128
+ | `anonymousIdTTL` | `number` | `365` | Anonymous ID TTL in days |
129
+ | `sessionIdTTL` | `number` | `1` | Session ID TTL in days |
130
+ | `cookieDomain` | `string?` | `undefined` | Cookie domain (e.g., `.example.com`) |
131
+ | `cookiePath` | `string` | `'/'` | Cookie path |
132
+ | `cookieSameSite` | `'Strict' \| 'Lax' \| 'None'` | `'Lax'` | Cookie SameSite attribute |
133
+ | `cookieSecure` | `boolean` | `true` | Cookie Secure flag (requires HTTPS) |
134
+ | `useLocalStorage` | `boolean` | `true` | Enable localStorage fallback |
135
+ | `debug` | `boolean` | `false` | Enable debug logging |
136
+
137
+ ### Methods
138
+
139
+ #### `ensureAnonymousId(): string`
140
+
141
+ Gets existing anonymous ID or creates a new one. Always returns a value.
142
+
143
+ ```typescript
144
+ const userId = identity.ensureAnonymousId();
145
+ // โ†’ "a3f2b8c9-4d5e-4f6a-8b9c-1d2e3f4a5b6c"
146
+ ```
147
+
148
+ **Persistence Strategy:**
149
+ 1. Check cookie
150
+ 2. Check localStorage (if enabled)
151
+ 3. Generate new UUID v4
152
+ 4. Save to both cookie and localStorage
153
+
154
+ #### `getAnonymousId(): string | null`
155
+
156
+ Gets existing anonymous ID without creating a new one.
157
+
158
+ ```typescript
159
+ const userId = identity.getAnonymousId();
160
+ // โ†’ "a3f2b8c9-..." or null
161
+ ```
162
+
163
+ #### `ensureSessionId(): string`
164
+
165
+ Gets existing session ID or creates a new one. Always returns a value.
166
+
167
+ ```typescript
168
+ const sessionId = identity.ensureSessionId();
169
+ // โ†’ "sess_1704067200000"
170
+ ```
171
+
172
+ **Format:** `sess_{timestamp}`
173
+
174
+ #### `getSessionId(): string | null`
175
+
176
+ Gets existing session ID without creating a new one.
177
+
178
+ ```typescript
179
+ const sessionId = identity.getSessionId();
180
+ // โ†’ "sess_1704067200000" or null
181
+ ```
182
+
183
+ #### `getCookie(name: string): string | null`
184
+
185
+ Low-level cookie getter.
186
+
187
+ ```typescript
188
+ const value = identity.getCookie('my_cookie');
189
+ ```
190
+
191
+ #### `setCookie(name: string, value: string, days: number): void`
192
+
193
+ Low-level cookie setter.
194
+
195
+ ```typescript
196
+ identity.setCookie('my_cookie', 'my_value', 30);
197
+ ```
198
+
199
+ #### `configure(options: PartialIdentityManagerOptions): void`
200
+
201
+ Updates configuration at runtime.
202
+
203
+ ```typescript
204
+ identity.configure({
205
+ debug: true,
206
+ anonymousIdTTL: 180,
207
+ });
208
+ ```
209
+
210
+ ## Advanced Usage
211
+
212
+ ### Custom Cookie Names
213
+
214
+ Use custom cookie names to avoid conflicts:
215
+
216
+ ```typescript
217
+ const identity = new IdentityManager({
218
+ anonymousIdCookieName: '_my_user_id',
219
+ sessionIdCookieName: '_my_session',
220
+ });
221
+ ```
222
+
223
+ ### Subdomain Sharing
224
+
225
+ Share identity across subdomains:
226
+
227
+ ```typescript
228
+ const identity = new IdentityManager({
229
+ cookieDomain: '.example.com', // Shares across *.example.com
230
+ });
231
+ ```
232
+
233
+ ### Extended Anonymous ID Persistence
234
+
235
+ Keep anonymous ID for longer:
236
+
237
+ ```typescript
238
+ const identity = new IdentityManager({
239
+ anonymousIdTTL: 730, // 2 years
240
+ });
241
+ ```
242
+
243
+ ### Longer Sessions
244
+
245
+ Extend session duration:
246
+
247
+ ```typescript
248
+ const identity = new IdentityManager({
249
+ sessionIdTTL: 7, // 1 week
250
+ });
251
+ ```
252
+
253
+ ### Debug Mode
254
+
255
+ Enable logging for troubleshooting:
256
+
257
+ ```typescript
258
+ const identity = new IdentityManager({
259
+ debug: true,
260
+ });
261
+
262
+ // Logs to console:
263
+ // [IdentityManager] ensureAnonymousId: generated new ID { anonymousId: "..." }
264
+ // [IdentityManager] setCookie: success { name: "_stid", value: "...", ... }
265
+ ```
266
+
267
+ ### Disable localStorage Fallback
268
+
269
+ Use cookies only:
270
+
271
+ ```typescript
272
+ const identity = new IdentityManager({
273
+ useLocalStorage: false,
274
+ });
275
+ ```
276
+
277
+ ### SameSite Configuration
278
+
279
+ For cross-site tracking (requires Secure):
280
+
281
+ ```typescript
282
+ const identity = new IdentityManager({
283
+ cookieSameSite: 'None',
284
+ cookieSecure: true, // Required for SameSite=None
285
+ });
286
+ ```
287
+
288
+ ### SSR/Node.js Usage
289
+
290
+ The library is SSR-safe and won't throw in Node.js:
291
+
292
+ ```typescript
293
+ // Server-side rendering
294
+ const identity = new IdentityManager();
295
+ const userId = identity.ensureAnonymousId(); // Returns null in SSR
296
+ ```
297
+
298
+ ## Edge Cases Handled
299
+
300
+ ### โœ… Cookie Blocking
301
+
302
+ When cookies are blocked by browser settings:
303
+ - Falls back to localStorage
304
+ - Gracefully returns null if both fail
305
+ - No errors thrown
306
+
307
+ ### โœ… Private Browsing Mode
308
+
309
+ When localStorage throws errors:
310
+ - Catches and handles silently
311
+ - Falls back to cookies only
312
+ - Continues working
313
+
314
+ ### โœ… Storage Quota Exceeded
315
+
316
+ When localStorage is full:
317
+ - Catches quota errors
318
+ - Uses cookie as primary storage
319
+ - No functionality loss
320
+
321
+ ### โœ… SSR/Node.js Environment
322
+
323
+ When `document`/`window` are undefined:
324
+ - Detects environment
325
+ - Returns null gracefully
326
+ - No errors thrown
327
+
328
+ ### โœ… Cookie Expiration
329
+
330
+ When cookies expire but localStorage persists:
331
+ - Automatically restores from localStorage
332
+ - Syncs back to cookie
333
+ - Seamless recovery
334
+
335
+ ## Migration Guide
336
+
337
+ ### From Custom Implementation
338
+
339
+ **Before:**
340
+ ```javascript
341
+ function getAnonymousId() {
342
+ let id = getCookie('_user_id');
343
+ if (!id) {
344
+ id = generateUUID();
345
+ setCookie('_user_id', id, 365);
346
+ }
347
+ return id;
348
+ }
349
+ ```
350
+
351
+ **After:**
352
+ ```typescript
353
+ import { IdentityManager } from '@sygnl/identity-manager';
354
+
355
+ const identity = new IdentityManager({
356
+ anonymousIdCookieName: '_user_id', // Match your existing cookie name
357
+ });
358
+
359
+ const id = identity.ensureAnonymousId();
360
+ ```
361
+
362
+ ### From pixel.source.js (Sygnl)
363
+
364
+ This package extracts and enhances these functions from `pixel.source.js`:
365
+ - `getCookie()` โ†’ `identity.getCookie()`
366
+ - `setCookie()` โ†’ `identity.setCookie()`
367
+ - `generateUUID()` โ†’ Internal (automatic)
368
+ - `ensureAnonymousId()` โ†’ `identity.ensureAnonymousId()`
369
+ - `ensureSessionId()` โ†’ `identity.ensureSessionId()`
370
+
371
+ **Benefits of migration:**
372
+ - โœ… TypeScript support
373
+ - โœ… Better error handling
374
+ - โœ… Configurable options
375
+ - โœ… Comprehensive tests
376
+ - โœ… SSR safety
377
+ - โœ… Maintained package
378
+
379
+ ## Browser Compatibility
380
+
381
+ - โœ… Chrome/Edge 90+
382
+ - โœ… Firefox 88+
383
+ - โœ… Safari 14+
384
+ - โœ… Node.js 18+ (SSR-safe)
385
+
386
+ **UUID Generation:**
387
+ - Uses `crypto.randomUUID()` in modern browsers
388
+ - Falls back to `Math.random()` for older browsers
389
+ - Both implementations are RFC4122 compliant
390
+
391
+ ## Performance
392
+
393
+ - **Bundle Size:** ~2KB minified + gzipped
394
+ - **Runtime:** <1ms for ID generation
395
+ - **Memory:** <1KB per instance
396
+ - **Zero dependencies**
397
+
398
+ ## Testing
399
+
400
+ Run the test suite:
401
+
402
+ ```bash
403
+ npm test
404
+ ```
405
+
406
+ Run with coverage:
407
+
408
+ ```bash
409
+ npm run test:coverage
410
+ ```
411
+
412
+ Watch mode for development:
413
+
414
+ ```bash
415
+ npm run test:watch
416
+ ```
417
+
418
+ **Test Coverage:**
419
+ - 60+ test cases
420
+ - >90% code coverage
421
+ - Edge cases covered
422
+ - Integration tests included
423
+
424
+ ## TypeScript
425
+
426
+ Full TypeScript support included:
427
+
428
+ ```typescript
429
+ import {
430
+ IdentityManager,
431
+ IdentityManagerOptions,
432
+ PartialIdentityManagerOptions,
433
+ DEFAULT_OPTIONS
434
+ } from '@sygnl/identity-manager';
435
+
436
+ // Type-safe configuration
437
+ const options: PartialIdentityManagerOptions = {
438
+ debug: true,
439
+ anonymousIdTTL: 365,
440
+ };
441
+
442
+ const identity = new IdentityManager(options);
443
+ ```
444
+
445
+ ## Contributing
446
+
447
+ Contributions welcome! Please read our [Contributing Guide](CONTRIBUTING.md) first.
448
+
449
+ ## License
450
+
451
+ Copyright ยฉ 2025 Edge Foundry, Inc. All rights reserved.
452
+
453
+ ## Support
454
+
455
+ - ๐Ÿ“ง Email: support@sygnl.com
456
+ - ๐Ÿ› Issues: [GitHub Issues](https://github.com/sygnl/identity-manager/issues)
457
+ - ๐Ÿ’ฌ Discussions: [GitHub Discussions](https://github.com/sygnl/identity-manager/discussions)
458
+
459
+ ## Related Packages
460
+
461
+ - [@sygnl/event-transport](#) - Analytics event transport layer
462
+ - [@sygnl/page-engagement](#) - Page engagement tracking
463
+ - [@sygnl/event-schema](#) - Event schema builder
464
+
465
+ ---
466
+
467
+ Made with โค๏ธ by [Sygnl](https://sygnl.com)