@licenseseat/js 0.3.1 → 0.4.2
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 +156 -1
- package/dist/index.bundled.js +2775 -0
- package/dist/index.js +467 -13
- package/dist/types/LicenseSeat.d.ts +40 -7
- package/dist/types/LicenseSeat.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +16 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/dist/types/types.d.ts +33 -0
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/LicenseSeat.js +136 -13
- package/src/global.d.ts +23 -0
- package/src/index.js +6 -2
- package/src/telemetry.js +518 -0
- package/src/types.js +12 -0
package/src/telemetry.js
ADDED
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LicenseSeat SDK Telemetry Collection
|
|
3
|
+
*
|
|
4
|
+
* Collects non-PII platform information for analytics.
|
|
5
|
+
* All fields use snake_case keys to match the server API.
|
|
6
|
+
*
|
|
7
|
+
* @module telemetry
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Detect the current OS name
|
|
12
|
+
* @returns {string} OS name ("Windows", "macOS", "Linux", "iOS", "Android", or "Unknown")
|
|
13
|
+
* @private
|
|
14
|
+
*/
|
|
15
|
+
function detectOSName() {
|
|
16
|
+
// Node.js environment
|
|
17
|
+
if (typeof process !== "undefined" && process.platform) {
|
|
18
|
+
const map = {
|
|
19
|
+
darwin: "macOS",
|
|
20
|
+
win32: "Windows",
|
|
21
|
+
linux: "Linux",
|
|
22
|
+
freebsd: "FreeBSD",
|
|
23
|
+
sunos: "SunOS",
|
|
24
|
+
};
|
|
25
|
+
return map[process.platform] || process.platform;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Browser: prefer userAgentData when available
|
|
29
|
+
if (typeof navigator !== "undefined") {
|
|
30
|
+
if (navigator.userAgentData && navigator.userAgentData.platform) {
|
|
31
|
+
return navigator.userAgentData.platform;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const ua = navigator.userAgent || "";
|
|
35
|
+
if (/Android/i.test(ua)) return "Android";
|
|
36
|
+
if (/iPhone|iPad|iPod/i.test(ua)) return "iOS";
|
|
37
|
+
if (/Mac/i.test(ua)) return "macOS";
|
|
38
|
+
if (/Win/i.test(ua)) return "Windows";
|
|
39
|
+
if (/Linux/i.test(ua)) return "Linux";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return "Unknown";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Detect the current OS version
|
|
47
|
+
* @returns {string|null} OS version string or null
|
|
48
|
+
* @private
|
|
49
|
+
*/
|
|
50
|
+
function detectOSVersion() {
|
|
51
|
+
// Node.js
|
|
52
|
+
if (typeof process !== "undefined" && process.version) {
|
|
53
|
+
try {
|
|
54
|
+
const os = await_free_os_release();
|
|
55
|
+
if (os) return os;
|
|
56
|
+
} catch (_) {
|
|
57
|
+
// fall through
|
|
58
|
+
}
|
|
59
|
+
return process.version; // e.g. "v20.10.0"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Browser
|
|
63
|
+
if (typeof navigator !== "undefined") {
|
|
64
|
+
const ua = navigator.userAgent || "";
|
|
65
|
+
|
|
66
|
+
// macOS: "Mac OS X 10_15_7" or "Mac OS X 10.15.7"
|
|
67
|
+
const macMatch = ua.match(/Mac OS X\s+([\d._]+)/);
|
|
68
|
+
if (macMatch) return macMatch[1].replace(/_/g, ".");
|
|
69
|
+
|
|
70
|
+
// Windows: "Windows NT 10.0"
|
|
71
|
+
const winMatch = ua.match(/Windows NT\s+([\d.]+)/);
|
|
72
|
+
if (winMatch) return winMatch[1];
|
|
73
|
+
|
|
74
|
+
// Android: "Android 14"
|
|
75
|
+
const androidMatch = ua.match(/Android\s+([\d.]+)/);
|
|
76
|
+
if (androidMatch) return androidMatch[1];
|
|
77
|
+
|
|
78
|
+
// iOS: "OS 17_1_1" or "OS 17.1.1"
|
|
79
|
+
const iosMatch = ua.match(/OS\s+([\d._]+)/);
|
|
80
|
+
if (iosMatch) return iosMatch[1].replace(/_/g, ".");
|
|
81
|
+
|
|
82
|
+
// Linux: usually no version in UA
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Synchronous OS release helper (avoids top-level await)
|
|
90
|
+
* @returns {string|null}
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
function await_free_os_release() {
|
|
94
|
+
try {
|
|
95
|
+
// Dynamic require for Node.js (won't execute in browser bundles)
|
|
96
|
+
// eslint-disable-next-line no-new-func
|
|
97
|
+
const os = new Function("try { return require('os') } catch(e) { return null }")();
|
|
98
|
+
if (os && os.release) return os.release();
|
|
99
|
+
} catch (_) {
|
|
100
|
+
// not available
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Dynamic require helper for Node.js modules (won't execute in browser bundles)
|
|
107
|
+
* @param {string} moduleName - The module to require
|
|
108
|
+
* @returns {Object|null}
|
|
109
|
+
* @private
|
|
110
|
+
*/
|
|
111
|
+
function dynamicRequire(moduleName) {
|
|
112
|
+
try {
|
|
113
|
+
// eslint-disable-next-line no-new-func
|
|
114
|
+
return new Function("m", "try { return require(m) } catch(e) { return null }")(moduleName);
|
|
115
|
+
} catch (_) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Detect the runtime platform
|
|
122
|
+
* @returns {string} "node", "electron", "react-native", "deno", "bun", or "browser"
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
function detectPlatform() {
|
|
126
|
+
if (typeof process !== "undefined") {
|
|
127
|
+
if (process.versions && process.versions.electron) return "electron";
|
|
128
|
+
if (process.versions && process.versions.bun) return "bun";
|
|
129
|
+
if (process.versions && process.versions.node) return "node";
|
|
130
|
+
}
|
|
131
|
+
// @ts-ignore
|
|
132
|
+
if (typeof Deno !== "undefined") return "deno";
|
|
133
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") return "react-native";
|
|
134
|
+
if (typeof window !== "undefined") return "browser";
|
|
135
|
+
return "unknown";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Detect device model (browser only, via userAgentData)
|
|
140
|
+
* @returns {string|null}
|
|
141
|
+
* @private
|
|
142
|
+
*/
|
|
143
|
+
function detectDeviceModel() {
|
|
144
|
+
try {
|
|
145
|
+
if (typeof navigator !== "undefined" && navigator.userAgentData) {
|
|
146
|
+
return navigator.userAgentData.model || null;
|
|
147
|
+
}
|
|
148
|
+
} catch (_) {
|
|
149
|
+
// not available
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Detect the user's locale
|
|
156
|
+
* @returns {string|null}
|
|
157
|
+
* @private
|
|
158
|
+
*/
|
|
159
|
+
function detectLocale() {
|
|
160
|
+
if (typeof navigator !== "undefined" && navigator.language) {
|
|
161
|
+
return navigator.language;
|
|
162
|
+
}
|
|
163
|
+
if (typeof Intl !== "undefined") {
|
|
164
|
+
try {
|
|
165
|
+
return Intl.DateTimeFormat().resolvedOptions().locale || null;
|
|
166
|
+
} catch (_) {
|
|
167
|
+
// fall through
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (typeof process !== "undefined" && process.env) {
|
|
171
|
+
return process.env.LANG || process.env.LC_ALL || null;
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Detect the user's timezone
|
|
178
|
+
* @returns {string|null}
|
|
179
|
+
* @private
|
|
180
|
+
*/
|
|
181
|
+
function detectTimezone() {
|
|
182
|
+
if (typeof Intl !== "undefined") {
|
|
183
|
+
try {
|
|
184
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || null;
|
|
185
|
+
} catch (_) {
|
|
186
|
+
// fall through
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Detect device type
|
|
194
|
+
* @returns {string} "phone", "tablet", "desktop", "server", or "unknown"
|
|
195
|
+
* @private
|
|
196
|
+
*/
|
|
197
|
+
function detectDeviceType() {
|
|
198
|
+
try {
|
|
199
|
+
const platform = detectPlatform();
|
|
200
|
+
|
|
201
|
+
// Node.js server (but not Electron)
|
|
202
|
+
if (platform === "node" || platform === "bun" || platform === "deno") return "server";
|
|
203
|
+
if (platform === "electron") return "desktop";
|
|
204
|
+
|
|
205
|
+
// React Native: check screen dimensions
|
|
206
|
+
if (platform === "react-native") {
|
|
207
|
+
if (typeof screen !== "undefined" && screen.width) {
|
|
208
|
+
return screen.width < 768 ? "phone" : "tablet";
|
|
209
|
+
}
|
|
210
|
+
return "phone";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Browser
|
|
214
|
+
if (typeof navigator !== "undefined") {
|
|
215
|
+
// Check userAgentData.mobile first (Chromium)
|
|
216
|
+
if (navigator.userAgentData && typeof navigator.userAgentData.mobile === "boolean") {
|
|
217
|
+
if (navigator.userAgentData.mobile) {
|
|
218
|
+
// Distinguish phone vs tablet by screen width
|
|
219
|
+
if (typeof screen !== "undefined" && screen.width >= 768) return "tablet";
|
|
220
|
+
return "phone";
|
|
221
|
+
}
|
|
222
|
+
return "desktop";
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Fallback: touch points heuristic
|
|
226
|
+
if (navigator.maxTouchPoints > 0) {
|
|
227
|
+
if (typeof screen !== "undefined" && screen.width >= 768) return "tablet";
|
|
228
|
+
return "phone";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return "desktop";
|
|
232
|
+
}
|
|
233
|
+
} catch (_) {
|
|
234
|
+
// fall through
|
|
235
|
+
}
|
|
236
|
+
return "unknown";
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Detect CPU architecture
|
|
241
|
+
* @returns {string|null} "arm64", "x64", "x86", "arm", or null
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
function detectArchitecture() {
|
|
245
|
+
try {
|
|
246
|
+
// Node.js / Bun
|
|
247
|
+
if (typeof process !== "undefined" && process.arch) {
|
|
248
|
+
const map = { ia32: "x86", x64: "x64", arm: "arm", arm64: "arm64" };
|
|
249
|
+
return map[process.arch] || process.arch;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Browser: userAgentData.architecture (sync access, may be empty string)
|
|
253
|
+
if (typeof navigator !== "undefined" && navigator.userAgentData) {
|
|
254
|
+
// architecture may not be available synchronously; getHighEntropyValues is async
|
|
255
|
+
// We can only get it if it's already populated
|
|
256
|
+
if (navigator.userAgentData.architecture) {
|
|
257
|
+
return navigator.userAgentData.architecture;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} catch (_) {
|
|
261
|
+
// not available
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Detect number of CPU cores
|
|
268
|
+
* @returns {number|null}
|
|
269
|
+
* @private
|
|
270
|
+
*/
|
|
271
|
+
function detectCpuCores() {
|
|
272
|
+
try {
|
|
273
|
+
// Browser
|
|
274
|
+
if (typeof navigator !== "undefined" && navigator.hardwareConcurrency) {
|
|
275
|
+
return navigator.hardwareConcurrency;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Node.js
|
|
279
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
280
|
+
const os = dynamicRequire("os");
|
|
281
|
+
if (os && os.cpus) {
|
|
282
|
+
const cpus = os.cpus();
|
|
283
|
+
if (cpus && cpus.length) return cpus.length;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
} catch (_) {
|
|
287
|
+
// not available
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Detect approximate RAM in GB
|
|
294
|
+
* @returns {number|null}
|
|
295
|
+
* @private
|
|
296
|
+
*/
|
|
297
|
+
function detectMemoryGb() {
|
|
298
|
+
try {
|
|
299
|
+
// Browser (Chrome only)
|
|
300
|
+
if (typeof navigator !== "undefined" && navigator.deviceMemory) {
|
|
301
|
+
return navigator.deviceMemory;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Node.js
|
|
305
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
306
|
+
const os = dynamicRequire("os");
|
|
307
|
+
if (os && os.totalmem) {
|
|
308
|
+
return Math.round(os.totalmem() / (1024 * 1024 * 1024));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} catch (_) {
|
|
312
|
+
// not available
|
|
313
|
+
}
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Detect 2-letter language code
|
|
319
|
+
* @returns {string|null} e.g. "en", "pt", "es"
|
|
320
|
+
* @private
|
|
321
|
+
*/
|
|
322
|
+
function detectLanguage() {
|
|
323
|
+
try {
|
|
324
|
+
const locale = detectLocale();
|
|
325
|
+
if (locale) {
|
|
326
|
+
const lang = locale.split(/[-_]/)[0];
|
|
327
|
+
if (lang && lang.length >= 2) return lang.toLowerCase();
|
|
328
|
+
}
|
|
329
|
+
} catch (_) {
|
|
330
|
+
// fall through
|
|
331
|
+
}
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Detect screen resolution
|
|
337
|
+
* @returns {string|null} e.g. "1920x1080"
|
|
338
|
+
* @private
|
|
339
|
+
*/
|
|
340
|
+
function detectScreenResolution() {
|
|
341
|
+
try {
|
|
342
|
+
if (typeof screen !== "undefined" && screen.width && screen.height) {
|
|
343
|
+
return `${screen.width}x${screen.height}`;
|
|
344
|
+
}
|
|
345
|
+
} catch (_) {
|
|
346
|
+
// not available
|
|
347
|
+
}
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Detect display pixel ratio
|
|
353
|
+
* @returns {number|null}
|
|
354
|
+
* @private
|
|
355
|
+
*/
|
|
356
|
+
function detectDisplayScale() {
|
|
357
|
+
try {
|
|
358
|
+
if (typeof window !== "undefined" && window.devicePixelRatio) {
|
|
359
|
+
return window.devicePixelRatio;
|
|
360
|
+
}
|
|
361
|
+
} catch (_) {
|
|
362
|
+
// not available
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Detect browser name
|
|
369
|
+
* @returns {string|null} e.g. "Chrome", "Safari", "Firefox", "Edge"
|
|
370
|
+
* @private
|
|
371
|
+
*/
|
|
372
|
+
function detectBrowserName() {
|
|
373
|
+
try {
|
|
374
|
+
if (typeof navigator === "undefined") return null;
|
|
375
|
+
|
|
376
|
+
// Prefer userAgentData brands (Chromium-based browsers)
|
|
377
|
+
if (navigator.userAgentData && navigator.userAgentData.brands) {
|
|
378
|
+
const brands = navigator.userAgentData.brands;
|
|
379
|
+
// Look for specific browser brands, skip "Chromium" and "Not" brands
|
|
380
|
+
for (const b of brands) {
|
|
381
|
+
const name = b.brand || "";
|
|
382
|
+
if (/^(Google Chrome|Microsoft Edge|Opera|Brave|Vivaldi|Samsung Internet)$/i.test(name)) {
|
|
383
|
+
return name;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
// Fallback to Chromium if that's all we have
|
|
387
|
+
for (const b of brands) {
|
|
388
|
+
if ((b.brand || "").toLowerCase() === "chromium") return "Chrome";
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Fallback: parse user agent string
|
|
393
|
+
const ua = navigator.userAgent || "";
|
|
394
|
+
if (/Edg\//i.test(ua)) return "Edge";
|
|
395
|
+
if (/OPR\//i.test(ua) || /Opera/i.test(ua)) return "Opera";
|
|
396
|
+
if (/Brave/i.test(ua)) return "Brave";
|
|
397
|
+
if (/Vivaldi/i.test(ua)) return "Vivaldi";
|
|
398
|
+
if (/Firefox/i.test(ua)) return "Firefox";
|
|
399
|
+
if (/SamsungBrowser/i.test(ua)) return "Samsung Internet";
|
|
400
|
+
if (/CriOS/i.test(ua)) return "Chrome"; // Chrome on iOS
|
|
401
|
+
if (/Chrome/i.test(ua)) return "Chrome";
|
|
402
|
+
if (/Safari/i.test(ua)) return "Safari";
|
|
403
|
+
} catch (_) {
|
|
404
|
+
// not available
|
|
405
|
+
}
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Detect browser version
|
|
411
|
+
* @returns {string|null} e.g. "123.0"
|
|
412
|
+
* @private
|
|
413
|
+
*/
|
|
414
|
+
function detectBrowserVersion() {
|
|
415
|
+
try {
|
|
416
|
+
if (typeof navigator === "undefined") return null;
|
|
417
|
+
|
|
418
|
+
// Prefer userAgentData brands
|
|
419
|
+
if (navigator.userAgentData && navigator.userAgentData.brands) {
|
|
420
|
+
const brands = navigator.userAgentData.brands;
|
|
421
|
+
for (const b of brands) {
|
|
422
|
+
const name = b.brand || "";
|
|
423
|
+
if (/^(Google Chrome|Microsoft Edge|Opera|Brave|Vivaldi|Samsung Internet)$/i.test(name)) {
|
|
424
|
+
return b.version || null;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
for (const b of brands) {
|
|
428
|
+
if ((b.brand || "").toLowerCase() === "chromium") return b.version || null;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Fallback: parse user agent
|
|
433
|
+
const ua = navigator.userAgent || "";
|
|
434
|
+
const patterns = [
|
|
435
|
+
/Edg\/([\d.]+)/,
|
|
436
|
+
/OPR\/([\d.]+)/,
|
|
437
|
+
/Firefox\/([\d.]+)/,
|
|
438
|
+
/SamsungBrowser\/([\d.]+)/,
|
|
439
|
+
/CriOS\/([\d.]+)/,
|
|
440
|
+
/Chrome\/([\d.]+)/,
|
|
441
|
+
/Version\/([\d.]+).*Safari/,
|
|
442
|
+
];
|
|
443
|
+
for (const re of patterns) {
|
|
444
|
+
const m = ua.match(re);
|
|
445
|
+
if (m) return m[1];
|
|
446
|
+
}
|
|
447
|
+
} catch (_) {
|
|
448
|
+
// not available
|
|
449
|
+
}
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Detect runtime version
|
|
455
|
+
* @returns {string|null} e.g. "20.11.0" for Node, "1.40.0" for Deno
|
|
456
|
+
* @private
|
|
457
|
+
*/
|
|
458
|
+
function detectRuntimeVersion() {
|
|
459
|
+
try {
|
|
460
|
+
if (typeof process !== "undefined" && process.versions) {
|
|
461
|
+
if (process.versions.bun) return process.versions.bun;
|
|
462
|
+
if (process.versions.electron) return process.versions.electron;
|
|
463
|
+
if (process.versions.node) return process.versions.node;
|
|
464
|
+
}
|
|
465
|
+
// @ts-ignore
|
|
466
|
+
if (typeof Deno !== "undefined" && Deno.version) return Deno.version.deno;
|
|
467
|
+
} catch (_) {
|
|
468
|
+
// not available
|
|
469
|
+
}
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Collect telemetry data for the current environment.
|
|
475
|
+
* Returns a plain object with snake_case keys matching the server schema.
|
|
476
|
+
* Null/undefined values are filtered out.
|
|
477
|
+
*
|
|
478
|
+
* @param {string} sdkVersion - The SDK version string
|
|
479
|
+
* @param {Object} [options] - Additional options
|
|
480
|
+
* @param {string} [options.appVersion] - User-provided app version
|
|
481
|
+
* @param {string} [options.appBuild] - User-provided app build
|
|
482
|
+
* @returns {Object} Telemetry data object
|
|
483
|
+
*/
|
|
484
|
+
export function collectTelemetry(sdkVersion, options) {
|
|
485
|
+
const locale = detectLocale();
|
|
486
|
+
|
|
487
|
+
const raw = {
|
|
488
|
+
sdk_version: sdkVersion,
|
|
489
|
+
sdk_name: 'js',
|
|
490
|
+
os_name: detectOSName(),
|
|
491
|
+
os_version: detectOSVersion(),
|
|
492
|
+
platform: detectPlatform(),
|
|
493
|
+
device_model: detectDeviceModel(),
|
|
494
|
+
device_type: detectDeviceType(),
|
|
495
|
+
locale: locale,
|
|
496
|
+
timezone: detectTimezone(),
|
|
497
|
+
language: detectLanguage(),
|
|
498
|
+
architecture: detectArchitecture(),
|
|
499
|
+
cpu_cores: detectCpuCores(),
|
|
500
|
+
memory_gb: detectMemoryGb(),
|
|
501
|
+
screen_resolution: detectScreenResolution(),
|
|
502
|
+
display_scale: detectDisplayScale(),
|
|
503
|
+
browser_name: detectBrowserName(),
|
|
504
|
+
browser_version: detectBrowserVersion(),
|
|
505
|
+
runtime_version: detectRuntimeVersion(),
|
|
506
|
+
app_version: (options && options.appVersion) || null,
|
|
507
|
+
app_build: (options && options.appBuild) || null,
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
// Filter out null/undefined values
|
|
511
|
+
const result = {};
|
|
512
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
513
|
+
if (value != null) {
|
|
514
|
+
result[key] = value;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return result;
|
|
518
|
+
}
|
package/src/types.js
CHANGED
|
@@ -21,6 +21,10 @@
|
|
|
21
21
|
* @property {number} [maxOfflineDays=0] - Maximum days a license can be used offline (0 = disabled)
|
|
22
22
|
* @property {number} [maxClockSkewMs=300000] - Maximum allowed clock skew in ms for offline validation (default: 5 minutes)
|
|
23
23
|
* @property {boolean} [autoInitialize=true] - Automatically initialize and validate cached license on construction
|
|
24
|
+
* @property {boolean} [telemetryEnabled=true] - Enable telemetry collection on POST requests (set false for GDPR compliance)
|
|
25
|
+
* @property {number} [heartbeatInterval=300000] - Interval in ms between automatic heartbeats (default: 5 minutes, set 0 to disable)
|
|
26
|
+
* @property {string} [appVersion] - User-provided app version string, sent as app_version in telemetry
|
|
27
|
+
* @property {string} [appBuild] - User-provided app build identifier, sent as app_build in telemetry
|
|
24
28
|
*/
|
|
25
29
|
|
|
26
30
|
/**
|
|
@@ -198,6 +202,14 @@
|
|
|
198
202
|
* @property {string} status - Key status ("active", "revoked")
|
|
199
203
|
*/
|
|
200
204
|
|
|
205
|
+
/**
|
|
206
|
+
* Heartbeat response from the API
|
|
207
|
+
* @typedef {Object} HeartbeatResponse
|
|
208
|
+
* @property {string} object - Object type ("heartbeat")
|
|
209
|
+
* @property {string} received_at - ISO8601 timestamp of when the heartbeat was received
|
|
210
|
+
* @property {LicenseObject} license - The license object
|
|
211
|
+
*/
|
|
212
|
+
|
|
201
213
|
/**
|
|
202
214
|
* Health check response
|
|
203
215
|
* @typedef {Object} HealthResponse
|