@cloudsignal/pwa-sdk 1.2.4 → 2.1.0
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/CHANGELOG.md +24 -22
- package/README.md +45 -509
- package/dist/{chunk-IMM7VF4N.js → chunk-IQHSODT4.js} +6 -6
- package/dist/chunk-IQHSODT4.js.map +1 -0
- package/dist/hmac-WITZIX2O.js +3 -0
- package/dist/{hmac-LWLR6F7Z.js.map → hmac-WITZIX2O.js.map} +1 -1
- package/dist/index.cjs +77 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +31 -35
- package/dist/index.d.ts +31 -35
- package/dist/index.global.js +6 -6
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +76 -85
- package/dist/index.js.map +1 -1
- package/dist/service-worker.js +1 -1
- package/dist/service-worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-IMM7VF4N.js.map +0 -1
- package/dist/hmac-LWLR6F7Z.js +0 -3
|
@@ -52,10 +52,10 @@ async function generateHMACSignature(secret, organizationId, timestamp, method,
|
|
|
52
52
|
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(canonicalString));
|
|
53
53
|
return toBase64(signature);
|
|
54
54
|
}
|
|
55
|
-
async function generateAuthHeaders(organizationId,
|
|
55
|
+
async function generateAuthHeaders(organizationId, organizationPublishableKey, method, url, body) {
|
|
56
56
|
const timestamp = Math.floor(Date.now() / 1e3).toString();
|
|
57
57
|
const signature = await generateHMACSignature(
|
|
58
|
-
|
|
58
|
+
organizationPublishableKey,
|
|
59
59
|
organizationId,
|
|
60
60
|
timestamp,
|
|
61
61
|
method,
|
|
@@ -69,11 +69,11 @@ async function generateAuthHeaders(organizationId, organizationSecret, method, u
|
|
|
69
69
|
"Content-Type": "application/json"
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
-
async function makeAuthenticatedRequest(organizationId,
|
|
72
|
+
async function makeAuthenticatedRequest(organizationId, organizationPublishableKey, method, url, body) {
|
|
73
73
|
const bodyStr = body ? JSON.stringify(body) : void 0;
|
|
74
74
|
const headers = await generateAuthHeaders(
|
|
75
75
|
organizationId,
|
|
76
|
-
|
|
76
|
+
organizationPublishableKey,
|
|
77
77
|
method,
|
|
78
78
|
url,
|
|
79
79
|
bodyStr
|
|
@@ -93,5 +93,5 @@ function isValidUUID(value) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
export { generateAuthHeaders, generateHMACSignature, isValidUUID, makeAuthenticatedRequest };
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
96
|
+
//# sourceMappingURL=chunk-IQHSODT4.js.map
|
|
97
|
+
//# sourceMappingURL=chunk-IQHSODT4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/hmac.ts"],"names":[],"mappings":"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","file":"chunk-IQHSODT4.js","sourcesContent":["/**\n * HMAC Authentication Utilities\n * Implements CloudSignal's HMAC signature scheme for API authentication\n */\n\n/**\n * Convert ArrayBuffer to hex string\n */\nfunction toHex(buffer: ArrayBuffer): string {\n return Array.from(new Uint8Array(buffer))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Convert ArrayBuffer to base64 string\n */\nfunction toBase64(buffer: ArrayBuffer): string {\n return btoa(String.fromCharCode(...new Uint8Array(buffer)))\n}\n\n/**\n * Generate HMAC signature for CloudSignal API requests\n *\n * @param secret - Signing key (organization publishable key, pk_*)\n * @param organizationId - Organization UUID\n * @param timestamp - Unix timestamp string\n * @param method - HTTP method (GET, POST, etc.)\n * @param url - Full URL or path\n * @param body - Request body (optional)\n * @returns Base64-encoded HMAC signature\n */\nexport async function generateHMACSignature(\n secret: string,\n organizationId: string,\n timestamp: string,\n method: string,\n url: string,\n body: string = ''\n): Promise<string> {\n const encoder = new TextEncoder()\n\n // Parse URL to extract path and query\n let path: string\n let query: string\n\n try {\n const urlObj = url.startsWith('http')\n ? new URL(url)\n : new URL(url, 'https://pwa.cloudsignal.app')\n path = urlObj.pathname\n query = urlObj.search ? urlObj.search.slice(1) : ''\n } catch {\n // Fallback for simple paths\n const queryIndex = url.indexOf('?')\n if (queryIndex > -1) {\n path = url.slice(0, queryIndex)\n query = url.slice(queryIndex + 1)\n } else {\n path = url\n query = ''\n }\n }\n\n // Build canonical string parts\n const canonicalParts = [\n method.toUpperCase(),\n path,\n query,\n organizationId,\n timestamp,\n ]\n\n // Add body hash if body is present\n if (body && body.length > 0) {\n const bodyHashBuffer = await crypto.subtle.digest('SHA-256', encoder.encode(body))\n const bodyHashHex = toHex(bodyHashBuffer)\n canonicalParts.push(bodyHashHex)\n }\n\n // Join parts with newlines\n const canonicalString = canonicalParts.join('\\n')\n\n // Import secret as HMAC key\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n )\n\n // Sign the canonical string\n const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(canonicalString))\n\n return toBase64(signature)\n}\n\n/**\n * Generate authentication headers for CloudSignal API requests\n *\n * @param organizationId - Organization UUID\n * @param organizationPublishableKey - Organization publishable key (pk_*)\n * @param method - HTTP method\n * @param url - Request URL\n * @param body - Request body (optional)\n * @returns Headers object with authentication headers\n */\nexport async function generateAuthHeaders(\n organizationId: string,\n organizationPublishableKey: string,\n method: string,\n url: string,\n body?: string\n): Promise<Record<string, string>> {\n const timestamp = Math.floor(Date.now() / 1000).toString()\n\n const signature = await generateHMACSignature(\n organizationPublishableKey,\n organizationId,\n timestamp,\n method,\n url,\n body || ''\n )\n\n return {\n 'X-CloudSignal-Organization-ID': organizationId,\n 'X-CloudSignal-Timestamp': timestamp,\n 'X-CloudSignal-Signature': signature,\n 'Content-Type': 'application/json',\n }\n}\n\n/**\n * Make an authenticated request to CloudSignal API\n *\n * @param organizationId - Organization UUID\n * @param organizationPublishableKey - Organization publishable key (pk_*)\n * @param method - HTTP method\n * @param url - Request URL\n * @param body - Request body (optional)\n * @returns Fetch Response\n */\nexport async function makeAuthenticatedRequest(\n organizationId: string,\n organizationPublishableKey: string,\n method: string,\n url: string,\n body?: Record<string, any>\n): Promise<Response> {\n const bodyStr = body ? JSON.stringify(body) : undefined\n\n const headers = await generateAuthHeaders(\n organizationId,\n organizationPublishableKey,\n method,\n url,\n bodyStr\n )\n\n const options: RequestInit = {\n method,\n headers,\n }\n\n if (bodyStr) {\n options.body = bodyStr\n }\n\n return fetch(url, options)\n}\n\n/**\n * Validate UUID format\n * \n * @param value - String to validate\n * @returns Whether the string is a valid UUID\n */\nexport function isValidUUID(value: string | null | undefined): boolean {\n if (!value || typeof value !== 'string') return false\n return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"hmac-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"hmac-WITZIX2O.js"}
|
package/dist/index.cjs
CHANGED
|
@@ -72,10 +72,10 @@ async function generateHMACSignature(secret, organizationId, timestamp, method,
|
|
|
72
72
|
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(canonicalString));
|
|
73
73
|
return toBase64(signature);
|
|
74
74
|
}
|
|
75
|
-
async function generateAuthHeaders(organizationId,
|
|
75
|
+
async function generateAuthHeaders(organizationId, organizationPublishableKey, method, url, body) {
|
|
76
76
|
const timestamp = Math.floor(Date.now() / 1e3).toString();
|
|
77
77
|
const signature = await generateHMACSignature(
|
|
78
|
-
|
|
78
|
+
organizationPublishableKey,
|
|
79
79
|
organizationId,
|
|
80
80
|
timestamp,
|
|
81
81
|
method,
|
|
@@ -89,11 +89,11 @@ async function generateAuthHeaders(organizationId, organizationSecret, method, u
|
|
|
89
89
|
"Content-Type": "application/json"
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
-
async function makeAuthenticatedRequest(organizationId,
|
|
92
|
+
async function makeAuthenticatedRequest(organizationId, organizationPublishableKey, method, url, body) {
|
|
93
93
|
const bodyStr = body ? JSON.stringify(body) : void 0;
|
|
94
94
|
const headers = await generateAuthHeaders(
|
|
95
95
|
organizationId,
|
|
96
|
-
|
|
96
|
+
organizationPublishableKey,
|
|
97
97
|
method,
|
|
98
98
|
url,
|
|
99
99
|
bodyStr
|
|
@@ -1046,13 +1046,13 @@ function createAuthContext(config) {
|
|
|
1046
1046
|
onTokenExpired: config.onTokenExpired
|
|
1047
1047
|
};
|
|
1048
1048
|
}
|
|
1049
|
-
if (!config.
|
|
1050
|
-
throw new Error("Either userToken or
|
|
1049
|
+
if (!config.organizationPublishableKey) {
|
|
1050
|
+
throw new Error("Either userToken or organizationPublishableKey is required");
|
|
1051
1051
|
}
|
|
1052
1052
|
return {
|
|
1053
1053
|
mode: "hmac",
|
|
1054
1054
|
organizationId: config.organizationId,
|
|
1055
|
-
|
|
1055
|
+
organizationPublishableKey: config.organizationPublishableKey
|
|
1056
1056
|
};
|
|
1057
1057
|
}
|
|
1058
1058
|
async function makeAuthenticatedRequestWithContext(authContext, method, url, body, onTokenExpired) {
|
|
@@ -1073,12 +1073,12 @@ async function makeAuthenticatedRequestWithContext(authContext, method, url, bod
|
|
|
1073
1073
|
);
|
|
1074
1074
|
}
|
|
1075
1075
|
const { makeAuthenticatedRequest: makeAuthenticatedRequest4 } = await Promise.resolve().then(() => (init_hmac(), hmac_exports));
|
|
1076
|
-
if (!authContext.
|
|
1077
|
-
throw new Error("
|
|
1076
|
+
if (!authContext.organizationPublishableKey) {
|
|
1077
|
+
throw new Error("organizationPublishableKey required for HMAC auth mode");
|
|
1078
1078
|
}
|
|
1079
1079
|
return makeAuthenticatedRequest4(
|
|
1080
1080
|
authContext.organizationId,
|
|
1081
|
-
authContext.
|
|
1081
|
+
authContext.organizationPublishableKey,
|
|
1082
1082
|
method,
|
|
1083
1083
|
url,
|
|
1084
1084
|
body
|
|
@@ -1356,7 +1356,7 @@ var PushNotificationManager = class {
|
|
|
1356
1356
|
this.deviceDetector = new DeviceDetector();
|
|
1357
1357
|
this.authContext = createAuthContext({
|
|
1358
1358
|
organizationId: options.organizationId,
|
|
1359
|
-
|
|
1359
|
+
organizationPublishableKey: options.organizationPublishableKey,
|
|
1360
1360
|
userToken: options.userToken
|
|
1361
1361
|
});
|
|
1362
1362
|
this.onRegistered = options.onRegistered;
|
|
@@ -1482,6 +1482,64 @@ var PushNotificationManager = class {
|
|
|
1482
1482
|
return null;
|
|
1483
1483
|
}
|
|
1484
1484
|
}
|
|
1485
|
+
/**
|
|
1486
|
+
* Register a PWA installation without a push subscription.
|
|
1487
|
+
*
|
|
1488
|
+
* Tracks users who installed the PWA (standalone display mode) but
|
|
1489
|
+
* haven't granted notification permission yet. A subsequent
|
|
1490
|
+
* ``registerForPush()`` call upgrades the same row to a full push
|
|
1491
|
+
* registration (matched server-side by browser fingerprint).
|
|
1492
|
+
*
|
|
1493
|
+
* Guarded by a localStorage flag so repeat ``initialize()`` calls in
|
|
1494
|
+
* the same storage session are no-ops.
|
|
1495
|
+
*/
|
|
1496
|
+
async registerInstallation() {
|
|
1497
|
+
try {
|
|
1498
|
+
if (isInstallationRegistered(this.organizationId, this.serviceId)) {
|
|
1499
|
+
this.log("Installation already registered, skipping");
|
|
1500
|
+
return null;
|
|
1501
|
+
}
|
|
1502
|
+
const fingerprint = await generateBrowserFingerprint();
|
|
1503
|
+
const deviceInfo = this.deviceDetector.getDeviceInfo();
|
|
1504
|
+
const platformInfo = this.deviceDetector.getPlatformInfo();
|
|
1505
|
+
const installationData = {
|
|
1506
|
+
service_id: this.serviceId,
|
|
1507
|
+
browser_fingerprint: fingerprint || void 0,
|
|
1508
|
+
device_type: deviceInfo.deviceType,
|
|
1509
|
+
device_model: deviceInfo.deviceModel,
|
|
1510
|
+
browser_name: platformInfo.browser,
|
|
1511
|
+
browser_version: platformInfo.browserVersion,
|
|
1512
|
+
os_name: platformInfo.os,
|
|
1513
|
+
os_version: platformInfo.osVersion,
|
|
1514
|
+
user_agent: platformInfo.userAgent,
|
|
1515
|
+
display_mode: "standalone",
|
|
1516
|
+
is_installed: true,
|
|
1517
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1518
|
+
language: navigator.language || "en-US"
|
|
1519
|
+
};
|
|
1520
|
+
const url = `${this.serviceUrl}/api/v1/registration/install-only`;
|
|
1521
|
+
const response = await makeAuthenticatedRequestWithContext(
|
|
1522
|
+
this.authContext,
|
|
1523
|
+
"POST",
|
|
1524
|
+
url,
|
|
1525
|
+
installationData,
|
|
1526
|
+
this.onTokenExpired
|
|
1527
|
+
);
|
|
1528
|
+
if (!response.ok) {
|
|
1529
|
+
const errorText = await response.text();
|
|
1530
|
+
throw new Error(`Installation registration failed: ${response.status} - ${errorText}`);
|
|
1531
|
+
}
|
|
1532
|
+
const result = await response.json();
|
|
1533
|
+
markInstallationRegistered(this.organizationId, this.serviceId, result.registration_id);
|
|
1534
|
+
this.log(`Installation registered: ${result.registration_id}`);
|
|
1535
|
+
return { registrationId: result.registration_id };
|
|
1536
|
+
} catch (error) {
|
|
1537
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1538
|
+
this.log(`Installation registration failed: ${err.message}`, "error");
|
|
1539
|
+
this.onError?.(err);
|
|
1540
|
+
return null;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1485
1543
|
/**
|
|
1486
1544
|
* Unregister from push notifications
|
|
1487
1545
|
*/
|
|
@@ -1595,72 +1653,6 @@ var PushNotificationManager = class {
|
|
|
1595
1653
|
return null;
|
|
1596
1654
|
}
|
|
1597
1655
|
}
|
|
1598
|
-
/**
|
|
1599
|
-
* Register PWA installation without push subscription.
|
|
1600
|
-
* This tracks users who installed the PWA but haven't subscribed to notifications.
|
|
1601
|
-
* Called automatically when installation is detected.
|
|
1602
|
-
*
|
|
1603
|
-
* @returns Installation registration result or null if already registered/failed
|
|
1604
|
-
*/
|
|
1605
|
-
async registerInstallation() {
|
|
1606
|
-
try {
|
|
1607
|
-
if (isInstallationRegistered(this.organizationId, this.serviceId)) {
|
|
1608
|
-
this.log("Installation already registered, skipping");
|
|
1609
|
-
return null;
|
|
1610
|
-
}
|
|
1611
|
-
const fingerprint = await generateBrowserFingerprint();
|
|
1612
|
-
const deviceInfo = this.deviceDetector.getDeviceInfo();
|
|
1613
|
-
const platformInfo = this.deviceDetector.getPlatformInfo();
|
|
1614
|
-
const installationData = {
|
|
1615
|
-
service_id: this.serviceId,
|
|
1616
|
-
browser_fingerprint: fingerprint || void 0,
|
|
1617
|
-
device_type: deviceInfo.deviceType,
|
|
1618
|
-
device_model: deviceInfo.deviceModel,
|
|
1619
|
-
browser_name: platformInfo.browser,
|
|
1620
|
-
browser_version: platformInfo.browserVersion,
|
|
1621
|
-
os_name: platformInfo.os,
|
|
1622
|
-
os_version: platformInfo.osVersion,
|
|
1623
|
-
user_agent: platformInfo.userAgent,
|
|
1624
|
-
display_mode: "standalone",
|
|
1625
|
-
is_installed: true,
|
|
1626
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1627
|
-
language: navigator.language || "en-US"
|
|
1628
|
-
};
|
|
1629
|
-
const url = `${this.serviceUrl}/api/v1/registration/install-only`;
|
|
1630
|
-
const response = await makeAuthenticatedRequestWithContext(
|
|
1631
|
-
this.authContext,
|
|
1632
|
-
"POST",
|
|
1633
|
-
url,
|
|
1634
|
-
installationData,
|
|
1635
|
-
this.onTokenExpired
|
|
1636
|
-
);
|
|
1637
|
-
if (!response.ok) {
|
|
1638
|
-
const errorText = await response.text();
|
|
1639
|
-
throw new Error(`Installation registration failed: ${response.status} - ${errorText}`);
|
|
1640
|
-
}
|
|
1641
|
-
const result = await response.json();
|
|
1642
|
-
markInstallationRegistered(this.organizationId, this.serviceId, result.registration_id);
|
|
1643
|
-
this.log(`Installation registered successfully: ${result.registration_id}`);
|
|
1644
|
-
return { registrationId: result.registration_id };
|
|
1645
|
-
} catch (error) {
|
|
1646
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1647
|
-
this.log(`Installation registration failed: ${err.message}`, "error");
|
|
1648
|
-
this.onError?.(err);
|
|
1649
|
-
return null;
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
/**
|
|
1653
|
-
* Check if installation is already registered
|
|
1654
|
-
*/
|
|
1655
|
-
isInstallationRegistered() {
|
|
1656
|
-
return isInstallationRegistered(this.organizationId, this.serviceId);
|
|
1657
|
-
}
|
|
1658
|
-
/**
|
|
1659
|
-
* Get stored installation registration ID
|
|
1660
|
-
*/
|
|
1661
|
-
getInstallationId() {
|
|
1662
|
-
return getStorageItem(`install_id_${this.organizationId}_${this.serviceId}`);
|
|
1663
|
-
}
|
|
1664
1656
|
/**
|
|
1665
1657
|
* Request notification permission
|
|
1666
1658
|
*/
|
|
@@ -1755,7 +1747,7 @@ var HeartbeatManager = class {
|
|
|
1755
1747
|
this.onTokenExpired = options.onTokenExpired;
|
|
1756
1748
|
this.authContext = createAuthContext({
|
|
1757
1749
|
organizationId: options.organizationId,
|
|
1758
|
-
|
|
1750
|
+
organizationPublishableKey: options.organizationPublishableKey,
|
|
1759
1751
|
userToken: options.userToken
|
|
1760
1752
|
});
|
|
1761
1753
|
this.config = {
|
|
@@ -3192,7 +3184,7 @@ var IOSInstallBanner = class {
|
|
|
3192
3184
|
|
|
3193
3185
|
// src/CloudSignalPWA.ts
|
|
3194
3186
|
var DEFAULT_SERVICE_URL = "https://pwa.cloudsignal.app";
|
|
3195
|
-
var SDK_VERSION = "1.2.
|
|
3187
|
+
var SDK_VERSION = "1.2.0";
|
|
3196
3188
|
var CloudSignalPWA = class {
|
|
3197
3189
|
constructor(config) {
|
|
3198
3190
|
this.initialized = false;
|
|
@@ -3206,12 +3198,12 @@ var CloudSignalPWA = class {
|
|
|
3206
3198
|
this.config = config;
|
|
3207
3199
|
this.serviceUrl = config.serviceUrl || DEFAULT_SERVICE_URL;
|
|
3208
3200
|
this.debug = config.debug ?? false;
|
|
3209
|
-
if (!config.
|
|
3210
|
-
throw new Error("Either
|
|
3201
|
+
if (!config.organizationPublishableKey && !config.userToken) {
|
|
3202
|
+
throw new Error("Either organizationPublishableKey or userToken must be provided");
|
|
3211
3203
|
}
|
|
3212
3204
|
this.authContext = createAuthContext({
|
|
3213
3205
|
organizationId: config.organizationId,
|
|
3214
|
-
|
|
3206
|
+
organizationPublishableKey: config.organizationPublishableKey,
|
|
3215
3207
|
userToken: config.userToken
|
|
3216
3208
|
});
|
|
3217
3209
|
this.deviceDetector = new DeviceDetector();
|
|
@@ -3232,7 +3224,7 @@ var CloudSignalPWA = class {
|
|
|
3232
3224
|
this.pushNotificationManager = new PushNotificationManager({
|
|
3233
3225
|
serviceUrl: this.serviceUrl,
|
|
3234
3226
|
organizationId: config.organizationId,
|
|
3235
|
-
|
|
3227
|
+
organizationPublishableKey: config.organizationPublishableKey,
|
|
3236
3228
|
userToken: config.userToken,
|
|
3237
3229
|
onTokenExpired: config.onTokenExpired,
|
|
3238
3230
|
serviceId: config.serviceId,
|
|
@@ -3251,7 +3243,7 @@ var CloudSignalPWA = class {
|
|
|
3251
3243
|
this.heartbeatManager = new HeartbeatManager({
|
|
3252
3244
|
serviceUrl: this.serviceUrl,
|
|
3253
3245
|
organizationId: config.organizationId,
|
|
3254
|
-
|
|
3246
|
+
organizationPublishableKey: config.organizationPublishableKey,
|
|
3255
3247
|
userToken: config.userToken,
|
|
3256
3248
|
onTokenExpired: config.onTokenExpired,
|
|
3257
3249
|
config: config.heartbeat,
|
|
@@ -3340,10 +3332,9 @@ var CloudSignalPWA = class {
|
|
|
3340
3332
|
}
|
|
3341
3333
|
const installState = this.installationManager.getState();
|
|
3342
3334
|
if (installState.isInstalled) {
|
|
3343
|
-
this.log("PWA installation detected, registering
|
|
3335
|
+
this.log("PWA installation detected, registering\u2026");
|
|
3344
3336
|
const installResult = await this.pushNotificationManager.registerInstallation();
|
|
3345
3337
|
if (installResult) {
|
|
3346
|
-
this.log(`Installation registered: ${installResult.registrationId}`);
|
|
3347
3338
|
this.emit("install:registered", { registrationId: installResult.registrationId });
|
|
3348
3339
|
}
|
|
3349
3340
|
}
|