@appsonair.ir/react-native 1.0.5 → 1.0.7
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/android/build.gradle +4 -1
- package/android/src/main/java/com/otaupdater/OTAFcmHelper.kt +4 -1
- package/lib/index.d.ts +6 -0
- package/lib/index.js +9 -1
- package/lib/sync.js +114 -7
- package/lib/telemetry.js +3 -0
- package/lib/userInfo.d.ts +18 -0
- package/lib/userInfo.js +84 -0
- package/package.json +1 -1
package/android/build.gradle
CHANGED
|
@@ -66,5 +66,8 @@ dependencies {
|
|
|
66
66
|
implementation "com.facebook.react:react-android"
|
|
67
67
|
implementation "org.jetbrains.kotlin:kotlin-stdlib"
|
|
68
68
|
implementation "androidx.core:core:1.13.1"
|
|
69
|
-
|
|
69
|
+
// Use BOM so transitive artifacts (installations, play-services-*) resolve
|
|
70
|
+
// correctly and stay aligned with @react-native-firebase when present.
|
|
71
|
+
implementation platform("com.google.firebase:firebase-bom:33.9.0")
|
|
72
|
+
implementation "com.google.firebase:firebase-messaging"
|
|
70
73
|
}
|
|
@@ -56,7 +56,10 @@ internal object OTAFcmHelper {
|
|
|
56
56
|
ensureNotificationChannel(context.applicationContext)
|
|
57
57
|
|
|
58
58
|
try {
|
|
59
|
-
|
|
59
|
+
// getInstance(FirebaseApp) is package-private in newer Firebase Messaging SDKs;
|
|
60
|
+
// FirebaseApp.get(Class) is the supported public API for named apps.
|
|
61
|
+
val messaging = app.get(FirebaseMessaging::class.java)
|
|
62
|
+
messaging.token.addOnCompleteListener { task ->
|
|
60
63
|
val token =
|
|
61
64
|
if (task.isSuccessful) {
|
|
62
65
|
task.result?.takeIf { it.isNotBlank() }
|
package/lib/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { configureFromProject, getDeploymentKey, isOtaConfigured, resolveUpdater
|
|
|
3
3
|
import { sync, restartApp, installApk, resumePendingApkInstall, clearUpdate, getInstalledBundlePath, notifyAppReady } from './sync';
|
|
4
4
|
import { logEvent } from './events';
|
|
5
5
|
import { ping, startTelemetry, stopTelemetry } from './telemetry';
|
|
6
|
+
import { clearUserInfo, getUserInfo, setUserInfo } from './userInfo';
|
|
6
7
|
import { UpdateCheckResult } from './types';
|
|
7
8
|
export { configure, getConfig, getServerUrl } from './config';
|
|
8
9
|
export { DEFAULT_SERVER_URL } from './constants';
|
|
@@ -13,6 +14,8 @@ export declare function checkUpdate(): Promise<UpdateCheckResult>;
|
|
|
13
14
|
export { sync, restartApp, installApk, resumePendingApkInstall, clearUpdate, getInstalledBundlePath, notifyAppReady, isSyncInProgress, respondToUpdatePrompt, } from './sync';
|
|
14
15
|
export { ping, startTelemetry, stopTelemetry } from './telemetry';
|
|
15
16
|
export { logEvent } from './events';
|
|
17
|
+
export { setUserInfo, clearUserInfo, getUserInfo } from './userInfo';
|
|
18
|
+
export type { OTAUserInfo } from './userInfo';
|
|
16
19
|
export { OTAUpdateModal } from './ui/OTAUpdateModal';
|
|
17
20
|
export { OTAUpdateProvider } from './ui/OTAUpdateProvider';
|
|
18
21
|
export declare const OTAUpdater: {
|
|
@@ -31,5 +34,8 @@ export declare const OTAUpdater: {
|
|
|
31
34
|
startTelemetry: typeof startTelemetry;
|
|
32
35
|
stopTelemetry: typeof stopTelemetry;
|
|
33
36
|
logEvent: typeof logEvent;
|
|
37
|
+
setUserInfo: typeof setUserInfo;
|
|
38
|
+
clearUserInfo: typeof clearUserInfo;
|
|
39
|
+
getUserInfo: typeof getUserInfo;
|
|
34
40
|
};
|
|
35
41
|
export * from './types';
|
package/lib/index.js
CHANGED
|
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.OTAUpdater = exports.OTAUpdateProvider = exports.OTAUpdateModal = exports.logEvent = exports.stopTelemetry = exports.startTelemetry = exports.ping = exports.respondToUpdatePrompt = exports.isSyncInProgress = exports.notifyAppReady = exports.getInstalledBundlePath = exports.clearUpdate = exports.resumePendingApkInstall = exports.installApk = exports.restartApp = exports.sync = exports.resolveUpdaterConfig = exports.isOtaConfigured = exports.getDeploymentKey = exports.configureFromProject = exports.DEFAULT_SERVER_URL = exports.getServerUrl = exports.getConfig = exports.configure = void 0;
|
|
20
|
+
exports.OTAUpdater = exports.OTAUpdateProvider = exports.OTAUpdateModal = exports.getUserInfo = exports.clearUserInfo = exports.setUserInfo = exports.logEvent = exports.stopTelemetry = exports.startTelemetry = exports.ping = exports.respondToUpdatePrompt = exports.isSyncInProgress = exports.notifyAppReady = exports.getInstalledBundlePath = exports.clearUpdate = exports.resumePendingApkInstall = exports.installApk = exports.restartApp = exports.sync = exports.resolveUpdaterConfig = exports.isOtaConfigured = exports.getDeploymentKey = exports.configureFromProject = exports.DEFAULT_SERVER_URL = exports.getServerUrl = exports.getConfig = exports.configure = void 0;
|
|
21
21
|
exports.getCurrentLabel = getCurrentLabel;
|
|
22
22
|
exports.checkUpdate = checkUpdate;
|
|
23
23
|
const react_native_device_info_1 = __importDefault(require("react-native-device-info"));
|
|
@@ -31,6 +31,7 @@ Object.defineProperty(exports, "resolveUpdaterConfig", { enumerable: true, get:
|
|
|
31
31
|
const sync_1 = require("./sync");
|
|
32
32
|
const events_1 = require("./events");
|
|
33
33
|
const telemetry_1 = require("./telemetry");
|
|
34
|
+
const userInfo_1 = require("./userInfo");
|
|
34
35
|
var config_2 = require("./config");
|
|
35
36
|
Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return config_2.configure; } });
|
|
36
37
|
Object.defineProperty(exports, "getConfig", { enumerable: true, get: function () { return config_2.getConfig; } });
|
|
@@ -68,6 +69,10 @@ Object.defineProperty(exports, "startTelemetry", { enumerable: true, get: functi
|
|
|
68
69
|
Object.defineProperty(exports, "stopTelemetry", { enumerable: true, get: function () { return telemetry_2.stopTelemetry; } });
|
|
69
70
|
var events_2 = require("./events");
|
|
70
71
|
Object.defineProperty(exports, "logEvent", { enumerable: true, get: function () { return events_2.logEvent; } });
|
|
72
|
+
var userInfo_2 = require("./userInfo");
|
|
73
|
+
Object.defineProperty(exports, "setUserInfo", { enumerable: true, get: function () { return userInfo_2.setUserInfo; } });
|
|
74
|
+
Object.defineProperty(exports, "clearUserInfo", { enumerable: true, get: function () { return userInfo_2.clearUserInfo; } });
|
|
75
|
+
Object.defineProperty(exports, "getUserInfo", { enumerable: true, get: function () { return userInfo_2.getUserInfo; } });
|
|
71
76
|
var OTAUpdateModal_1 = require("./ui/OTAUpdateModal");
|
|
72
77
|
Object.defineProperty(exports, "OTAUpdateModal", { enumerable: true, get: function () { return OTAUpdateModal_1.OTAUpdateModal; } });
|
|
73
78
|
var OTAUpdateProvider_1 = require("./ui/OTAUpdateProvider");
|
|
@@ -88,5 +93,8 @@ exports.OTAUpdater = {
|
|
|
88
93
|
startTelemetry: telemetry_1.startTelemetry,
|
|
89
94
|
stopTelemetry: telemetry_1.stopTelemetry,
|
|
90
95
|
logEvent: events_1.logEvent,
|
|
96
|
+
setUserInfo: userInfo_1.setUserInfo,
|
|
97
|
+
clearUserInfo: userInfo_1.clearUserInfo,
|
|
98
|
+
getUserInfo: userInfo_1.getUserInfo,
|
|
91
99
|
};
|
|
92
100
|
__exportStar(require("./types"), exports);
|
package/lib/sync.js
CHANGED
|
@@ -456,6 +456,98 @@ function getApkFilePath(label) {
|
|
|
456
456
|
const dirs = ReactNativeBlobUtil.fs.dirs;
|
|
457
457
|
return `${dirs.DocumentDir}/ota-updates/${label}.apk`;
|
|
458
458
|
}
|
|
459
|
+
function getApkZipPath(label) {
|
|
460
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
461
|
+
const dirs = ReactNativeBlobUtil.fs.dirs;
|
|
462
|
+
return `${dirs.DocumentDir}/ota-updates/${label}-apk.zip`;
|
|
463
|
+
}
|
|
464
|
+
function getApkExtractDir(label) {
|
|
465
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
466
|
+
const dirs = ReactNativeBlobUtil.fs.dirs;
|
|
467
|
+
return `${dirs.DocumentDir}/ota-updates/${label}-apk`;
|
|
468
|
+
}
|
|
469
|
+
function apkAbiFromName(fileName) {
|
|
470
|
+
const lower = fileName.replace(/^.*[/\\]/, '').toLowerCase();
|
|
471
|
+
if (lower.includes('arm64-v8a') || lower.includes('arm64') || lower.includes('-v8a')) {
|
|
472
|
+
return 'arm64-v8a';
|
|
473
|
+
}
|
|
474
|
+
if (lower.includes('armeabi-v7a') ||
|
|
475
|
+
lower.includes('armeabi') ||
|
|
476
|
+
lower.includes('-v7a')) {
|
|
477
|
+
return 'armeabi-v7a';
|
|
478
|
+
}
|
|
479
|
+
if (lower.includes('x86_64')) {
|
|
480
|
+
return 'x86_64';
|
|
481
|
+
}
|
|
482
|
+
if (lower.includes('universal')) {
|
|
483
|
+
return 'universal';
|
|
484
|
+
}
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
async function listFilesRecursive(dir) {
|
|
488
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
489
|
+
const entries = await ReactNativeBlobUtil.fs.ls(dir);
|
|
490
|
+
const out = [];
|
|
491
|
+
for (const entry of entries) {
|
|
492
|
+
const path = `${dir}/${entry}`;
|
|
493
|
+
try {
|
|
494
|
+
const entryStat = await ReactNativeBlobUtil.fs.stat(path);
|
|
495
|
+
if (entryStat.type === 'directory') {
|
|
496
|
+
out.push(...(await listFilesRecursive(path)));
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
out.push(path);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
503
|
+
out.push(path);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return out;
|
|
507
|
+
}
|
|
508
|
+
async function pickExtractedApk(dir, deviceAbi) {
|
|
509
|
+
const files = await listFilesRecursive(dir);
|
|
510
|
+
const apks = files.filter((path) => path.toLowerCase().endsWith('.apk'));
|
|
511
|
+
if (apks.length === 0) {
|
|
512
|
+
throw new Error(`No APK found after unzipping ${dir}`);
|
|
513
|
+
}
|
|
514
|
+
if (apks.length === 1) {
|
|
515
|
+
return apks[0];
|
|
516
|
+
}
|
|
517
|
+
const wanted = (deviceAbi ?? (await getDeviceAbi()) ?? '').toLowerCase();
|
|
518
|
+
const scored = apks.map((path) => {
|
|
519
|
+
const abi = apkAbiFromName(path);
|
|
520
|
+
let score = 0;
|
|
521
|
+
if (abi && wanted && abi === wanted) {
|
|
522
|
+
score = 3;
|
|
523
|
+
}
|
|
524
|
+
else if (wanted.includes('arm64') && abi === 'arm64-v8a') {
|
|
525
|
+
score = 3;
|
|
526
|
+
}
|
|
527
|
+
else if ((wanted.includes('v7') || wanted.includes('armeabi')) &&
|
|
528
|
+
abi === 'armeabi-v7a') {
|
|
529
|
+
score = 2;
|
|
530
|
+
}
|
|
531
|
+
else if (abi === 'universal') {
|
|
532
|
+
score = 1;
|
|
533
|
+
}
|
|
534
|
+
return { path, score };
|
|
535
|
+
});
|
|
536
|
+
scored.sort((a, b) => b.score - a.score);
|
|
537
|
+
return scored[0].path;
|
|
538
|
+
}
|
|
539
|
+
async function extractApkUpdate(label, zipPath, deviceAbi) {
|
|
540
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
541
|
+
const extractDir = getApkExtractDir(label);
|
|
542
|
+
await removePathRecursive(extractDir);
|
|
543
|
+
await ReactNativeBlobUtil.fs.mkdir(extractDir);
|
|
544
|
+
await (0, zipExtract_1.extractZipToDirectory)(zipPath, extractDir);
|
|
545
|
+
const zipExists = await ReactNativeBlobUtil.fs.exists(zipPath);
|
|
546
|
+
if (zipExists) {
|
|
547
|
+
await ReactNativeBlobUtil.fs.unlink(zipPath);
|
|
548
|
+
}
|
|
549
|
+
return pickExtractedApk(extractDir, deviceAbi);
|
|
550
|
+
}
|
|
459
551
|
function getBundleDirectory() {
|
|
460
552
|
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
461
553
|
return `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/ota-updates`;
|
|
@@ -480,10 +572,13 @@ async function cleanupOldUpdates(keepLabel) {
|
|
|
480
572
|
keepLabel,
|
|
481
573
|
`${keepLabel}.zip`,
|
|
482
574
|
`${keepLabel}.bundle`,
|
|
575
|
+
`${keepLabel}.apk`,
|
|
576
|
+
`${keepLabel}-apk`,
|
|
577
|
+
`${keepLabel}-apk.zip`,
|
|
483
578
|
]);
|
|
484
579
|
const entries = await ReactNativeBlobUtil.fs.ls(dir);
|
|
485
580
|
await Promise.all(entries.map(async (entry) => {
|
|
486
|
-
if (keep.has(entry)
|
|
581
|
+
if (keep.has(entry)) {
|
|
487
582
|
return;
|
|
488
583
|
}
|
|
489
584
|
await removePathRecursive(`${dir}/${entry}`);
|
|
@@ -575,7 +670,7 @@ async function cleanupPartialDownload(path) {
|
|
|
575
670
|
* bytesWritten !== Content-Length — including when Content-Length is wrong
|
|
576
671
|
* but the full file actually landed. Recover those cases via size/hash checks.
|
|
577
672
|
*/
|
|
578
|
-
async function tryRecoverCompletedDownload(destPath, extension, totalBytes, expectedHash, packageFormat, label) {
|
|
673
|
+
async function tryRecoverCompletedDownload(destPath, extension, totalBytes, expectedHash, packageFormat, label, deviceAbi) {
|
|
579
674
|
try {
|
|
580
675
|
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
581
676
|
const exists = await ReactNativeBlobUtil.fs.exists(destPath);
|
|
@@ -594,6 +689,9 @@ async function tryRecoverCompletedDownload(destPath, extension, totalBytes, expe
|
|
|
594
689
|
else if (!sizeLooksComplete) {
|
|
595
690
|
return null;
|
|
596
691
|
}
|
|
692
|
+
if (extension === 'apk' && (packageFormat === 'zip' || (await isZipArchive(destPath)))) {
|
|
693
|
+
return extractApkUpdate(label, destPath, deviceAbi);
|
|
694
|
+
}
|
|
597
695
|
if (extension === 'bundle' && (await shouldExtractZipPackage(destPath, packageFormat))) {
|
|
598
696
|
return extractBundleUpdate(label, destPath);
|
|
599
697
|
}
|
|
@@ -606,16 +704,22 @@ async function tryRecoverCompletedDownload(destPath, extension, totalBytes, expe
|
|
|
606
704
|
async function downloadBundle(downloadUrl, deploymentKey, label, expectedSize, onProgress, extension = 'bundle', deviceAbi, packageFormat = 'bundle', expectedHash) {
|
|
607
705
|
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
608
706
|
const isZipBundle = extension === 'bundle' && packageFormat === 'zip';
|
|
707
|
+
const isApkZip = extension === 'apk' && packageFormat === 'zip';
|
|
609
708
|
const destPath = isZipBundle
|
|
610
709
|
? getBundleZipPath(label)
|
|
611
|
-
:
|
|
612
|
-
?
|
|
613
|
-
:
|
|
710
|
+
: isApkZip
|
|
711
|
+
? getApkZipPath(label)
|
|
712
|
+
: extension === 'apk'
|
|
713
|
+
? getApkFilePath(label)
|
|
714
|
+
: getLegacyBundleFilePath(label);
|
|
614
715
|
const totalBytes = await resolveDownloadSize(downloadUrl, deploymentKey, expectedSize, deviceAbi);
|
|
615
716
|
await ensureBundleDirectory();
|
|
616
717
|
if (isZipBundle) {
|
|
617
718
|
await removePathRecursive(getBundleReleaseDir(label));
|
|
618
719
|
}
|
|
720
|
+
if (isApkZip) {
|
|
721
|
+
await removePathRecursive(getApkExtractDir(label));
|
|
722
|
+
}
|
|
619
723
|
let lastError;
|
|
620
724
|
for (let attempt = 1; attempt <= DOWNLOAD_MAX_ATTEMPTS; attempt++) {
|
|
621
725
|
await cleanupPartialDownload(destPath);
|
|
@@ -676,6 +780,9 @@ async function downloadBundle(downloadUrl, deploymentKey, label, expectedSize, o
|
|
|
676
780
|
throw new Error('Package hash verification failed');
|
|
677
781
|
}
|
|
678
782
|
}
|
|
783
|
+
if (extension === 'apk' && (isApkZip || (await isZipArchive(destPath)))) {
|
|
784
|
+
return extractApkUpdate(label, destPath, deviceAbi);
|
|
785
|
+
}
|
|
679
786
|
if (extension === 'bundle' && (await shouldExtractZipPackage(destPath, packageFormat))) {
|
|
680
787
|
return extractBundleUpdate(label, destPath);
|
|
681
788
|
}
|
|
@@ -684,7 +791,7 @@ async function downloadBundle(downloadUrl, deploymentKey, label, expectedSize, o
|
|
|
684
791
|
catch (error) {
|
|
685
792
|
lastError = error;
|
|
686
793
|
if (isRetryableDownloadError(error)) {
|
|
687
|
-
const recovered = await tryRecoverCompletedDownload(destPath, extension, totalBytes, expectedHash, packageFormat, label);
|
|
794
|
+
const recovered = await tryRecoverCompletedDownload(destPath, extension, totalBytes, expectedHash, packageFormat, label, deviceAbi);
|
|
688
795
|
if (recovered) {
|
|
689
796
|
if (onProgress)
|
|
690
797
|
onProgress(1);
|
|
@@ -969,7 +1076,7 @@ async function performApkSync(update, showUI, messages, onProgress, changelog) {
|
|
|
969
1076
|
label: update.label,
|
|
970
1077
|
description: notes,
|
|
971
1078
|
isMandatory: update.isMandatory,
|
|
972
|
-
}), 'apk', update.deviceAbi, 'bundle', update.packageHash);
|
|
1079
|
+
}), 'apk', update.deviceAbi, update.packageFormat ?? 'bundle', update.packageHash);
|
|
973
1080
|
onProgress?.(types_1.SyncStatus.INSTALLING, 1);
|
|
974
1081
|
// Drop the OTA JS path before opening the installer so the new APK does not
|
|
975
1082
|
// keep loading the previous bundle on first launch after install.
|
package/lib/telemetry.js
CHANGED
|
@@ -11,6 +11,7 @@ const react_native_device_info_1 = __importDefault(require("react-native-device-
|
|
|
11
11
|
const config_1 = require("./config");
|
|
12
12
|
const deviceProfile_1 = require("./deviceProfile");
|
|
13
13
|
const sync_1 = require("./sync");
|
|
14
|
+
const userInfo_1 = require("./userInfo");
|
|
14
15
|
const PING_INTERVAL_MS = 60000;
|
|
15
16
|
let started = false;
|
|
16
17
|
let pingTimer = null;
|
|
@@ -27,6 +28,7 @@ async function buildPingBody(sessionStart) {
|
|
|
27
28
|
(0, deviceProfile_1.getDeviceProfile)(),
|
|
28
29
|
(0, sync_1.getFcmToken)(),
|
|
29
30
|
]);
|
|
31
|
+
const userInfo = (0, userInfo_1.getUserInfo)();
|
|
30
32
|
return {
|
|
31
33
|
clientUniqueId,
|
|
32
34
|
appVersion: react_native_device_info_1.default.getVersion(),
|
|
@@ -36,6 +38,7 @@ async function buildPingBody(sessionStart) {
|
|
|
36
38
|
packageHash: meta?.packageHash,
|
|
37
39
|
fcmToken,
|
|
38
40
|
sessionStart,
|
|
41
|
+
...(userInfo ?? {}),
|
|
39
42
|
};
|
|
40
43
|
}
|
|
41
44
|
async function ping(options = {}) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface OTAUserInfo {
|
|
2
|
+
/** Host-app user id (string or number coerced to string). */
|
|
3
|
+
userId?: string | number | null;
|
|
4
|
+
userName?: string | null;
|
|
5
|
+
userEmail?: string | null;
|
|
6
|
+
userPhone?: string | null;
|
|
7
|
+
}
|
|
8
|
+
export type SanitizedOTAUserInfo = {
|
|
9
|
+
userId?: string;
|
|
10
|
+
userName?: string;
|
|
11
|
+
userEmail?: string;
|
|
12
|
+
userPhone?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare function sanitizeUserInfo(info: OTAUserInfo | null | undefined): SanitizedOTAUserInfo | null;
|
|
15
|
+
/** Attach logged-in host-app user to subsequent device pings. Pass null to clear. */
|
|
16
|
+
export declare function setUserInfo(info: OTAUserInfo | null): void;
|
|
17
|
+
export declare function clearUserInfo(): void;
|
|
18
|
+
export declare function getUserInfo(): SanitizedOTAUserInfo | null;
|
package/lib/userInfo.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.sanitizeUserInfo = sanitizeUserInfo;
|
|
37
|
+
exports.setUserInfo = setUserInfo;
|
|
38
|
+
exports.clearUserInfo = clearUserInfo;
|
|
39
|
+
exports.getUserInfo = getUserInfo;
|
|
40
|
+
let currentUserInfo = null;
|
|
41
|
+
function sanitizeField(value, maxLen) {
|
|
42
|
+
if (value == null) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const text = String(value).trim();
|
|
46
|
+
if (!text) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return text.slice(0, maxLen);
|
|
50
|
+
}
|
|
51
|
+
function sanitizeUserInfo(info) {
|
|
52
|
+
if (!info || typeof info !== 'object') {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const sanitized = {};
|
|
56
|
+
const userId = sanitizeField(info.userId, 128);
|
|
57
|
+
const userName = sanitizeField(info.userName, 128);
|
|
58
|
+
const userEmail = sanitizeField(info.userEmail, 256);
|
|
59
|
+
const userPhone = sanitizeField(info.userPhone, 64);
|
|
60
|
+
if (userId)
|
|
61
|
+
sanitized.userId = userId;
|
|
62
|
+
if (userName)
|
|
63
|
+
sanitized.userName = userName;
|
|
64
|
+
if (userEmail)
|
|
65
|
+
sanitized.userEmail = userEmail;
|
|
66
|
+
if (userPhone)
|
|
67
|
+
sanitized.userPhone = userPhone;
|
|
68
|
+
return Object.keys(sanitized).length > 0 ? sanitized : null;
|
|
69
|
+
}
|
|
70
|
+
/** Attach logged-in host-app user to subsequent device pings. Pass null to clear. */
|
|
71
|
+
function setUserInfo(info) {
|
|
72
|
+
currentUserInfo = sanitizeUserInfo(info);
|
|
73
|
+
// Best-effort immediate sync so dashboards update without waiting for the interval.
|
|
74
|
+
void Promise.resolve().then(() => __importStar(require('./telemetry'))).then((mod) => mod.ping())
|
|
75
|
+
.catch(() => undefined);
|
|
76
|
+
}
|
|
77
|
+
function clearUserInfo() {
|
|
78
|
+
currentUserInfo = null;
|
|
79
|
+
void Promise.resolve().then(() => __importStar(require('./telemetry'))).then((mod) => mod.ping())
|
|
80
|
+
.catch(() => undefined);
|
|
81
|
+
}
|
|
82
|
+
function getUserInfo() {
|
|
83
|
+
return currentUserInfo;
|
|
84
|
+
}
|