@salesforce/plugin-lightning-dev 1.0.26-alpha.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/LICENSE.txt +12 -0
- package/README.md +225 -0
- package/lib/commands/lightning/dev/app.d.ts +29 -0
- package/lib/commands/lightning/dev/app.js +288 -0
- package/lib/commands/lightning/dev/app.js.map +1 -0
- package/lib/commands/lightning/dev/site.d.ts +12 -0
- package/lib/commands/lightning/dev/site.js +77 -0
- package/lib/commands/lightning/dev/site.js.map +1 -0
- package/lib/configMeta.d.ts +28 -0
- package/lib/configMeta.js +74 -0
- package/lib/configMeta.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/lwc-dev-server/index.d.ts +7 -0
- package/lib/lwc-dev-server/index.js +102 -0
- package/lib/lwc-dev-server/index.js.map +1 -0
- package/lib/shared/configUtils.d.ts +27 -0
- package/lib/shared/configUtils.js +108 -0
- package/lib/shared/configUtils.js.map +1 -0
- package/lib/shared/experience/expSite.d.ts +70 -0
- package/lib/shared/experience/expSite.js +200 -0
- package/lib/shared/experience/expSite.js.map +1 -0
- package/lib/shared/orgUtils.d.ts +14 -0
- package/lib/shared/orgUtils.js +36 -0
- package/lib/shared/orgUtils.js.map +1 -0
- package/lib/shared/previewUtils.d.ts +126 -0
- package/lib/shared/previewUtils.js +397 -0
- package/lib/shared/previewUtils.js.map +1 -0
- package/lib/shared/prompt.d.ts +4 -0
- package/lib/shared/prompt.js +25 -0
- package/lib/shared/prompt.js.map +1 -0
- package/messages/lightning.dev.app.md +171 -0
- package/messages/lightning.dev.site.md +37 -0
- package/messages/shared.utils.md +27 -0
- package/npm-shrinkwrap.json +29260 -0
- package/oclif.lock +15886 -0
- package/oclif.manifest.json +174 -0
- package/package.json +226 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
// **********************************************************************************************
|
|
8
|
+
// * TODO: When we finalize the implementation for the dev commands and things settle down, *
|
|
9
|
+
// * consider moving most of these into PreviewUtils of lwc-dev-mobile-core instead. *
|
|
10
|
+
// **********************************************************************************************
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import https from 'node:https';
|
|
13
|
+
import os from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { Messages } from '@salesforce/core';
|
|
16
|
+
import { AndroidUtils, CommonUtils, CryptoUtils, IOSUtils, PreviewUtils as LwcDevMobileCorePreviewUtils, Platform, } from '@salesforce/lwc-dev-mobile-core';
|
|
17
|
+
import fetch from 'node-fetch';
|
|
18
|
+
import { ConfigUtils, LOCAL_DEV_SERVER_DEFAULT_HTTP_PORT } from './configUtils.js';
|
|
19
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
20
|
+
const messages = Messages.loadMessages('@salesforce/plugin-lightning-dev', 'lightning.dev.app');
|
|
21
|
+
const DevPreviewAuraMode = 'DEVPREVIEW';
|
|
22
|
+
export class PreviewUtils {
|
|
23
|
+
static generateWebSocketUrlForLocalDevServer(platform, ports, logger) {
|
|
24
|
+
return LwcDevMobileCorePreviewUtils.generateWebSocketUrlForLocalDevServer(platform, ports, logger);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns a pair of port numbers to be used by the local dev server for http and https.
|
|
28
|
+
*
|
|
29
|
+
* It starts by checking whether the user has configured a port in their config file.
|
|
30
|
+
* If so then we are only allowed to use that port, regardless of whether it is in use
|
|
31
|
+
* or not.
|
|
32
|
+
*
|
|
33
|
+
* If the user has not configured a port in their config file then we are free to choose
|
|
34
|
+
* one. We'll start with the default port (8081) and checks to see if it is in use or not.
|
|
35
|
+
* If it is in use then we increment the port number by 2 and check if it is in use or not.
|
|
36
|
+
* This process is repeated until a port that is not in use is found.
|
|
37
|
+
*
|
|
38
|
+
* @returns a pair of port numbers to be used by the local dev server for http and https.
|
|
39
|
+
*/
|
|
40
|
+
static async getNextAvailablePorts() {
|
|
41
|
+
const userConfiguredPorts = await ConfigUtils.getLocalDevServerPorts();
|
|
42
|
+
if (userConfiguredPorts) {
|
|
43
|
+
return Promise.resolve(userConfiguredPorts);
|
|
44
|
+
}
|
|
45
|
+
const httpPort = await this.doGetNextAvailablePort(LOCAL_DEV_SERVER_DEFAULT_HTTP_PORT);
|
|
46
|
+
const httpsPort = await this.doGetNextAvailablePort(httpPort + 1);
|
|
47
|
+
return Promise.resolve({ httpPort, httpsPort });
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Attempts to fetch the targeted mobile device for previewing.
|
|
51
|
+
*
|
|
52
|
+
* @param platform A mobile platform (iOS or Android)
|
|
53
|
+
* @param deviceId An optional device identifier (such as name or UDID)
|
|
54
|
+
* @param logger An optional logger to be used for logging
|
|
55
|
+
* @returns The iOS or Android device, or `undefined` if not found
|
|
56
|
+
*/
|
|
57
|
+
static async getMobileDevice(platform, deviceId, logger) {
|
|
58
|
+
let device;
|
|
59
|
+
logger?.debug(`Attempting to get mobile device for platform ${platform}`);
|
|
60
|
+
if (deviceId) {
|
|
61
|
+
logger?.debug(`Attempting to get device ${deviceId}`);
|
|
62
|
+
device =
|
|
63
|
+
platform === Platform.ios
|
|
64
|
+
? (await IOSUtils.getSimulator(deviceId, logger)) ?? undefined
|
|
65
|
+
: await AndroidUtils.fetchEmulator(deviceId, logger);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
logger?.debug('No particular device was targeted by the user... fetching the first available device.');
|
|
69
|
+
const devices = platform === Platform.ios
|
|
70
|
+
? await IOSUtils.getSupportedSimulators(logger)
|
|
71
|
+
: await AndroidUtils.fetchEmulators(logger);
|
|
72
|
+
if (devices && devices.length > 0) {
|
|
73
|
+
device = devices[0];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return Promise.resolve(device);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Attempts to boot a device.
|
|
80
|
+
*
|
|
81
|
+
* @param platform A mobile platform (iOS or Android)
|
|
82
|
+
* @param deviceId The identifier (such as name or UDID) of the target device
|
|
83
|
+
* @param logger An optional logger to be used for logging
|
|
84
|
+
* @returns For Android devices returns the emulator port number. For iOS devices returns `undefined`
|
|
85
|
+
*/
|
|
86
|
+
static async bootMobileDevice(platform, deviceId, logger) {
|
|
87
|
+
logger?.debug(`Booting device ${deviceId}`);
|
|
88
|
+
let emulatorPort;
|
|
89
|
+
if (platform === Platform.ios) {
|
|
90
|
+
await IOSUtils.bootDevice(deviceId, true, logger); // will be no-op if already booted
|
|
91
|
+
await IOSUtils.launchSimulatorApp(logger);
|
|
92
|
+
logger?.debug('Device booted');
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
emulatorPort = await AndroidUtils.startEmulator(deviceId, false, true, logger); // will be no-op if already booted
|
|
96
|
+
logger?.debug(`Device booted on port ${emulatorPort}`);
|
|
97
|
+
}
|
|
98
|
+
return Promise.resolve(emulatorPort);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Generates the proper set of arguments to be used for launching desktop browser and navigating to the right location.
|
|
102
|
+
*
|
|
103
|
+
* @param ldpServerUrl The URL for the local dev server
|
|
104
|
+
* @param entityId Record ID for the identity token
|
|
105
|
+
* @param appId An optional app id for a targeted LEX app
|
|
106
|
+
* @param targetOrg An optional org id
|
|
107
|
+
* @param auraMode An optional Aura Mode (defaults to DEVPREVIEW)
|
|
108
|
+
* @returns Array of arguments to be used by Org:Open command for launching desktop browser
|
|
109
|
+
*/
|
|
110
|
+
static generateDesktopPreviewLaunchArguments(ldpServerUrl, entityId, appId, targetOrg, auraMode = DevPreviewAuraMode) {
|
|
111
|
+
// appPath will resolve to one of the following:
|
|
112
|
+
//
|
|
113
|
+
// lightning/app/<appId> => when the user is targeting a specific LEX app
|
|
114
|
+
// lightning => when the user is not targeting a specific LEX app
|
|
115
|
+
//
|
|
116
|
+
const appPath = appId ? `lightning/app/${appId}` : 'lightning';
|
|
117
|
+
// we prepend a '0.' to all of the params to ensure they will persist across browser redirects
|
|
118
|
+
const launchArguments = [
|
|
119
|
+
'--path',
|
|
120
|
+
`${appPath}?0.aura.ldpServerUrl=${ldpServerUrl}&0.aura.ldpServerId=${entityId}&0.aura.mode=${auraMode}`,
|
|
121
|
+
];
|
|
122
|
+
if (targetOrg) {
|
|
123
|
+
launchArguments.push('--target-org', targetOrg);
|
|
124
|
+
}
|
|
125
|
+
return launchArguments;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Generates the proper set of arguments to be used for launching a mobile app with custom launch arguments.
|
|
129
|
+
*
|
|
130
|
+
* @param ldpServerUrl The URL for the local dev server
|
|
131
|
+
* @param entityId Record ID for the identity token
|
|
132
|
+
* @param appName An optional app name for a targeted LEX app
|
|
133
|
+
* @param appId An optional app id for a targeted LEX app
|
|
134
|
+
* @param auraMode An optional Aura Mode (defaults to DEVPREVIEW)
|
|
135
|
+
* @returns Array of arguments to be used as custom launch arguments when launching a mobile app.
|
|
136
|
+
*/
|
|
137
|
+
static generateMobileAppPreviewLaunchArguments(ldpServerUrl, entityId, appName, appId, auraMode = DevPreviewAuraMode) {
|
|
138
|
+
const launchArguments = [];
|
|
139
|
+
if (appName) {
|
|
140
|
+
launchArguments.push({ name: 'LightningExperienceAppName', value: appName });
|
|
141
|
+
}
|
|
142
|
+
if (appId) {
|
|
143
|
+
launchArguments.push({ name: 'LightningExperienceAppID', value: appId });
|
|
144
|
+
}
|
|
145
|
+
launchArguments.push({ name: 'aura.ldpServerUrl', value: ldpServerUrl });
|
|
146
|
+
launchArguments.push({ name: 'aura.mode', value: auraMode });
|
|
147
|
+
launchArguments.push({ name: 'aura.ldpServerId', value: entityId });
|
|
148
|
+
return launchArguments;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Generates a self-signed certificate and saves it to a file at the specified location.
|
|
152
|
+
*
|
|
153
|
+
* @param platform A mobile platform (iOS or Android)
|
|
154
|
+
* @param saveLocation Path to a folder where the generated certificated will be saved to (defaults to the current working directory)
|
|
155
|
+
* @returns Path to the generated certificate file and the certificate data
|
|
156
|
+
*/
|
|
157
|
+
static async generateSelfSignedCert(platform, saveLocation = '.') {
|
|
158
|
+
// See if we have previously generated cert data which is stored in the global config.
|
|
159
|
+
// If so then use that data otherwise generate new cert data and store it in the global config.
|
|
160
|
+
let data = await ConfigUtils.getCertData();
|
|
161
|
+
if (!data) {
|
|
162
|
+
data = CryptoUtils.generateSelfSignedCert('localhost', 2048, 820);
|
|
163
|
+
await ConfigUtils.writeCertData(data);
|
|
164
|
+
}
|
|
165
|
+
const basePath = path.resolve(CommonUtils.resolveUserHomePath(saveLocation));
|
|
166
|
+
const targetFile = platform === Platform.ios ? path.join(basePath, 'localhost.der') : path.join(basePath, 'localhost.pem');
|
|
167
|
+
// save to file
|
|
168
|
+
if (platform === Platform.ios) {
|
|
169
|
+
fs.writeFileSync(targetFile, data.derCertificate);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
fs.writeFileSync(targetFile, data.pemCertificate);
|
|
173
|
+
}
|
|
174
|
+
return { certData: data, certFilePath: targetFile };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Launches the specified mobile app on the specified device.
|
|
178
|
+
*
|
|
179
|
+
* @param platform A mobile platform (iOS or Android)
|
|
180
|
+
* @param deviceId The identifier (such as name or UDID) of the target device
|
|
181
|
+
* @param appConfig The app configuration containing info about the mobile app to be launched
|
|
182
|
+
* @param emulatorPort Optional - only needed when platform is Android and specifies the ADB port of the booted Android virtual device
|
|
183
|
+
* @param logger An optional logger to be used for logging
|
|
184
|
+
*/
|
|
185
|
+
static async launchMobileApp(platform, appConfig, deviceId, emulatorPort, appBundlePath, logger) {
|
|
186
|
+
logger?.debug(`Attempting to launch mobile app ${appConfig.name}`);
|
|
187
|
+
// If appBundlePath is provided then the app will be installed from
|
|
188
|
+
// the bundle first then will be launched. Otherwise the assumption
|
|
189
|
+
// is that app is already installed.
|
|
190
|
+
if (platform === Platform.ios) {
|
|
191
|
+
await IOSUtils.launchAppInBootedSimulator(deviceId, appBundlePath, appConfig.id, appConfig.launch_arguments ?? [], logger);
|
|
192
|
+
}
|
|
193
|
+
else if (emulatorPort) {
|
|
194
|
+
// for Android, emulatorPort is required
|
|
195
|
+
await AndroidUtils.launchAppInBootedEmulator(appBundlePath, appConfig.id, appConfig.launch_arguments ?? [], appConfig.activity, emulatorPort, logger);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Verifies whether a particular app is installed on a mobile device.
|
|
200
|
+
*
|
|
201
|
+
* @param platform A mobile platform (iOS or Android)
|
|
202
|
+
* @param appConfig The app configuration containing info about the mobile app such as name and bundle/package id
|
|
203
|
+
* @param deviceId The identifier (such as name or UDID) of the target device
|
|
204
|
+
* @param emulatorPort Optional - only needed when platform is Android and specifies the ADB port of the booted Android virtual device
|
|
205
|
+
* @param logger An optional logger to be used for logging
|
|
206
|
+
* @returns `true` if app is installed, `false` otherwise
|
|
207
|
+
*/
|
|
208
|
+
static async verifyMobileAppInstalled(platform, appConfig, deviceId, emulatorPort, logger) {
|
|
209
|
+
logger?.debug(`Checking if ${appConfig.id} is installed on device ${deviceId}`);
|
|
210
|
+
let result = '';
|
|
211
|
+
try {
|
|
212
|
+
if (platform === Platform.ios) {
|
|
213
|
+
result = CommonUtils.executeCommandSync(`xcrun simctl listapps ${deviceId} | grep "${appConfig.id}"`, undefined, logger);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
217
|
+
const resolvedEmulatorPort = emulatorPort;
|
|
218
|
+
result = await AndroidUtils.executeAdbCommand(`shell pm list packages | grep "${appConfig.id}"`, resolvedEmulatorPort, logger);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
/* ignore and continue */
|
|
223
|
+
}
|
|
224
|
+
return Promise.resolve(result ? true : false);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Downloads the Salesforce Mobile App into a temp folder and returns the path to downloaded file.
|
|
228
|
+
*
|
|
229
|
+
* @param platform A mobile platform (iOS or Android)
|
|
230
|
+
* @param logger An optional logger to be used for logging
|
|
231
|
+
* @param progress An optional spinner indicator for reporting messages
|
|
232
|
+
* @param progress An optional progress indicator for reporting progress
|
|
233
|
+
* @returns The path to downloaded file.
|
|
234
|
+
*/
|
|
235
|
+
static async downloadSalesforceMobileAppBundle(platform, logger, spinner, progress) {
|
|
236
|
+
const sfdcUrl = platform === Platform.ios
|
|
237
|
+
? 'https://sfdc.co/salesforce-mobile-app-ios-simulator'
|
|
238
|
+
: 'https://sfdc.co/salesforce-mobile-app-android-emulator';
|
|
239
|
+
let fullUrl = '';
|
|
240
|
+
try {
|
|
241
|
+
spinner?.start(messages.getMessage('spinner.download.preparing'));
|
|
242
|
+
logger?.debug(`Attempting to resolve full url from ${sfdcUrl}`);
|
|
243
|
+
fullUrl = await this.fetchFullUrlFromSfdc(sfdcUrl);
|
|
244
|
+
logger?.debug(`Full url is ${fullUrl}`);
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
spinner?.stop();
|
|
248
|
+
}
|
|
249
|
+
const parsedUrl = new URL(fullUrl);
|
|
250
|
+
const pathname = parsedUrl.pathname;
|
|
251
|
+
const filename = path.basename(pathname);
|
|
252
|
+
const tempDir = os.tmpdir();
|
|
253
|
+
const downloadedFilePath = path.join(tempDir, filename);
|
|
254
|
+
if (fs.existsSync(downloadedFilePath)) {
|
|
255
|
+
logger?.debug(`Skip downloading because already downloaded to ${downloadedFilePath}`);
|
|
256
|
+
return Promise.resolve(downloadedFilePath);
|
|
257
|
+
}
|
|
258
|
+
logger?.debug(`Attempting to download from ${fullUrl} to ${downloadedFilePath}`);
|
|
259
|
+
const response = await fetch(fullUrl, { redirect: 'follow' });
|
|
260
|
+
if (!response.ok) {
|
|
261
|
+
return Promise.reject(new Error(response.statusText));
|
|
262
|
+
}
|
|
263
|
+
const totalSize = parseInt(response.headers.get('content-length') ?? '0', 10);
|
|
264
|
+
let downloadedSize = 0;
|
|
265
|
+
// Create a write stream to save the file
|
|
266
|
+
const fileStream = fs.createWriteStream(downloadedFilePath);
|
|
267
|
+
// If we can determine the expected total size then we can report progress
|
|
268
|
+
if (totalSize) {
|
|
269
|
+
progress?.start(100, undefined, {
|
|
270
|
+
title: messages.getMessage('spinner.downloading'),
|
|
271
|
+
format: '%s | {bar} | {percentage}%',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
spinner?.start(messages.getMessage('spinner.downloading'));
|
|
276
|
+
}
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
if (progress && totalSize) {
|
|
279
|
+
response.body?.on('data', (chunk) => {
|
|
280
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
281
|
+
downloadedSize += chunk.length;
|
|
282
|
+
const percentage = parseFloat(Math.min((downloadedSize / totalSize) * 100, 100).toFixed(1));
|
|
283
|
+
progress.update(percentage);
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
response.body?.pipe(fileStream);
|
|
287
|
+
response.body?.on('error', (err) => {
|
|
288
|
+
// on error, delete the partially downloaded file
|
|
289
|
+
try {
|
|
290
|
+
fs.rmSync(downloadedFilePath);
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
/* ignore and continue */
|
|
294
|
+
}
|
|
295
|
+
progress?.stop();
|
|
296
|
+
spinner?.stop();
|
|
297
|
+
reject(err);
|
|
298
|
+
});
|
|
299
|
+
fileStream.on('finish', () => {
|
|
300
|
+
progress?.finish();
|
|
301
|
+
spinner?.stop();
|
|
302
|
+
resolve(downloadedFilePath);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Given an sfdc.co shortened url it returns the actual/full url that this will redirect to.
|
|
308
|
+
*
|
|
309
|
+
* @param httpsUrl The sfdc.co shortened url
|
|
310
|
+
* @returns The actual/full url
|
|
311
|
+
*/
|
|
312
|
+
static async fetchFullUrlFromSfdc(httpsUrl) {
|
|
313
|
+
return new Promise((resolve, reject) => {
|
|
314
|
+
https
|
|
315
|
+
.get(httpsUrl, (response) => {
|
|
316
|
+
let data = '';
|
|
317
|
+
response.on('data', (chunk) => {
|
|
318
|
+
data += chunk;
|
|
319
|
+
});
|
|
320
|
+
response.on('end', () => {
|
|
321
|
+
// sfdc.co urls will lead to an html page where, among other elements, there would be
|
|
322
|
+
// an element with id='full-url' and whose value would be the url to redirect to, eg:
|
|
323
|
+
// <h2 class="home-heading" style="word-wrap:break-word;" id="full-url">
|
|
324
|
+
// https://developer.salesforce.com/files/sfmobiletools/SalesforceApp-Simulator-248.061-iOS.zip
|
|
325
|
+
// </h2>
|
|
326
|
+
const regex = /<[^>]*id\s*=\s*["']full-url["'][^>]*>(.*?)<\/[^>]*>/i;
|
|
327
|
+
const match = data.match(regex);
|
|
328
|
+
if (match?.[1]) {
|
|
329
|
+
resolve(match[1]);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
resolve('');
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
})
|
|
336
|
+
.on('error)', (error) => {
|
|
337
|
+
reject(error);
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Extracts a ZIP archive to an output directory.
|
|
343
|
+
*
|
|
344
|
+
* @param zipFilePath The path to the ZIP archive
|
|
345
|
+
* @param outputDir An optional output directory - if omitted then defaults to the same directory as the ZIP file
|
|
346
|
+
* @param logger An optional logger to be used for logging
|
|
347
|
+
*/
|
|
348
|
+
static async extractZIPArchive(zipFilePath, outputDir, logger) {
|
|
349
|
+
let archive = path.resolve(CommonUtils.resolveUserHomePath(zipFilePath));
|
|
350
|
+
let outDir = outputDir ? path.resolve(CommonUtils.resolveUserHomePath(outputDir)) : path.dirname(archive);
|
|
351
|
+
archive = CommonUtils.convertToUnixPath(archive);
|
|
352
|
+
outDir = CommonUtils.convertToUnixPath(outDir);
|
|
353
|
+
const cmd = process.platform === 'win32'
|
|
354
|
+
? `powershell -Command "$ProgressPreference = 'SilentlyContinue'; Expand-Archive -Path \\"${archive}\\" -DestinationPath \\"${outDir}\\" -Force"`
|
|
355
|
+
: `unzip -o -qq ${archive} -d ${outDir}`;
|
|
356
|
+
logger?.debug(`Extracting archive ${zipFilePath}`);
|
|
357
|
+
await CommonUtils.executeCommandAsync(cmd, logger);
|
|
358
|
+
}
|
|
359
|
+
static async getEntityId(username) {
|
|
360
|
+
const identityData = await ConfigUtils.getIdentityData();
|
|
361
|
+
let entityId;
|
|
362
|
+
if (!identityData) {
|
|
363
|
+
return Promise.reject(new Error(messages.getMessage('error.identitydata')));
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
entityId = identityData.usernameToServerEntityIdMap[username];
|
|
367
|
+
if (!entityId) {
|
|
368
|
+
return Promise.reject(new Error(messages.getMessage('error.identitydata.entityid')));
|
|
369
|
+
}
|
|
370
|
+
return entityId;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
static async doGetNextAvailablePort(startingPort) {
|
|
374
|
+
let port = startingPort;
|
|
375
|
+
let done = false;
|
|
376
|
+
while (!done) {
|
|
377
|
+
const cmd = process.platform === 'win32' ? `netstat -an | find "LISTENING" | find ":${port}"` : `lsof -i :${port}`;
|
|
378
|
+
try {
|
|
379
|
+
const result = CommonUtils.executeCommandSync(cmd);
|
|
380
|
+
if (result.trim()) {
|
|
381
|
+
port = port + 2; // that port is in use so try another
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
done = true;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch (error) {
|
|
388
|
+
// On some platforms (like mac) if the command doesn't produce
|
|
389
|
+
// any results then that is considered an error but in our case
|
|
390
|
+
// that means the port is not in use and is ready for us to use.
|
|
391
|
+
done = true;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return Promise.resolve(port);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
//# sourceMappingURL=previewUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewUtils.js","sourceRoot":"","sources":["../../src/shared/previewUtils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,iGAAiG;AACjG,6FAA6F;AAC7F,iGAAiG;AACjG,iGAAiG;AAEjG,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAU,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAEL,YAAY,EAEZ,WAAW,EACX,WAAW,EAGX,QAAQ,EAER,YAAY,IAAI,4BAA4B,EAC5C,QAAQ,GAET,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAC;AAEnF,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,kCAAkC,EAAE,mBAAmB,CAAC,CAAC;AAChG,MAAM,kBAAkB,GAAG,YAAY,CAAC;AAExC,MAAM,OAAO,YAAY;IAChB,MAAM,CAAC,qCAAqC,CACjD,QAAgB,EAChB,KAA8C,EAC9C,MAAe;QAEf,OAAO,4BAA4B,CAAC,qCAAqC,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACrG,CAAC;IAED;;;;;;;;;;;;;OAaG;IACI,MAAM,CAAC,KAAK,CAAC,qBAAqB;QACvC,MAAM,mBAAmB,GAAG,MAAM,WAAW,CAAC,sBAAsB,EAAE,CAAC;QAEvE,IAAI,mBAAmB,EAAE,CAAC;YACxB,OAAO,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,kCAAkC,CAAC,CAAC;QACvF,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAElE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAClD,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,KAAK,CAAC,eAAe,CACjC,QAAyC,EACzC,QAAiB,EACjB,MAAe;QAEf,IAAI,MAA6D,CAAC;QAElE,MAAM,EAAE,KAAK,CAAC,gDAAgD,QAAQ,EAAE,CAAC,CAAC;QAE1E,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,EAAE,KAAK,CAAC,4BAA4B,QAAQ,EAAE,CAAC,CAAC;YACtD,MAAM;gBACJ,QAAQ,KAAK,QAAQ,CAAC,GAAG;oBACvB,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,SAAS;oBAC9D,CAAC,CAAC,MAAM,YAAY,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,KAAK,CAAC,wFAAwF,CAAC,CAAC;YACxG,MAAM,OAAO,GACX,QAAQ,KAAK,QAAQ,CAAC,GAAG;gBACvB,CAAC,CAAC,MAAM,QAAQ,CAAC,sBAAsB,CAAC,MAAM,CAAC;gBAC/C,CAAC,CAAC,MAAM,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;YAChD,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAClC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;OAOG;IACI,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAClC,QAAyC,EACzC,QAAgB,EAChB,MAAe;QAEf,MAAM,EAAE,KAAK,CAAC,kBAAkB,QAAQ,EAAE,CAAC,CAAC;QAE5C,IAAI,YAAgC,CAAC;QAErC,IAAI,QAAQ,KAAK,QAAQ,CAAC,GAAG,EAAE,CAAC;YAC9B,MAAM,QAAQ,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,kCAAkC;YACrF,MAAM,QAAQ,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,kCAAkC;YAClH,MAAM,EAAE,KAAK,CAAC,yBAAyB,YAAY,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;;;;OASG;IACI,MAAM,CAAC,qCAAqC,CACjD,YAAoB,EACpB,QAAgB,EAChB,KAAc,EACd,SAAkB,EAClB,QAAQ,GAAG,kBAAkB;QAE7B,gDAAgD;QAChD,EAAE;QACF,2EAA2E;QAC3E,+EAA+E;QAC/E,EAAE;QACF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,iBAAiB,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;QAE/D,8FAA8F;QAC9F,MAAM,eAAe,GAAG;YACtB,QAAQ;YACR,GAAG,OAAO,wBAAwB,YAAY,uBAAuB,QAAQ,gBAAgB,QAAQ,EAAE;SACxG,CAAC;QAEF,IAAI,SAAS,EAAE,CAAC;YACd,eAAe,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QAClD,CAAC;QAED,OAAO,eAAe,CAAC;IACzB,CAAC;IAED;;;;;;;;;OASG;IACI,MAAM,CAAC,uCAAuC,CACnD,YAAoB,EACpB,QAAgB,EAChB,OAAgB,EAChB,KAAc,EACd,QAAQ,GAAG,kBAAkB;QAE7B,MAAM,eAAe,GAAqB,EAAE,CAAC;QAE7C,IAAI,OAAO,EAAE,CAAC;YACZ,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,4BAA4B,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACV,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QAEzE,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAE7D,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEpE,OAAO,eAAe,CAAC;IACzB,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,KAAK,CAAC,sBAAsB,CACxC,QAAyC,EACzC,YAAY,GAAG,GAAG;QAElB,sFAAsF;QACtF,+FAA+F;QAC/F,IAAI,IAAI,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,WAAW,CAAC,sBAAsB,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YAClE,MAAM,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC;QAE7E,MAAM,UAAU,GACd,QAAQ,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QAE1G,eAAe;QACf,IAAI,QAAQ,KAAK,QAAQ,CAAC,GAAG,EAAE,CAAC;YAC9B,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACtD,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,CAAC,eAAe,CACjC,QAAyC,EACzC,SAAwD,EACxD,QAAgB,EAChB,YAAqB,EACrB,aAAsB,EACtB,MAAe;QAEf,MAAM,EAAE,KAAK,CAAC,mCAAmC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;QAEnE,mEAAmE;QACnE,mEAAmE;QACnE,oCAAoC;QACpC,IAAI,QAAQ,KAAK,QAAQ,CAAC,GAAG,EAAE,CAAC;YAC9B,MAAM,QAAQ,CAAC,0BAA0B,CACvC,QAAQ,EACR,aAAa,EACb,SAAS,CAAC,EAAE,EACZ,SAAS,CAAC,gBAAgB,IAAI,EAAE,EAChC,MAAM,CACP,CAAC;QACJ,CAAC;aAAM,IAAI,YAAY,EAAE,CAAC;YACxB,wCAAwC;YACxC,MAAM,YAAY,CAAC,yBAAyB,CAC1C,aAAa,EACb,SAAS,CAAC,EAAE,EACZ,SAAS,CAAC,gBAAgB,IAAI,EAAE,EAC/B,SAAqC,CAAC,QAAQ,EAC/C,YAAY,EACZ,MAAM,CACP,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;;;;OASG;IACI,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAC1C,QAAyC,EACzC,SAAwD,EACxD,QAAgB,EAChB,YAAqB,EACrB,MAAe;QAEf,MAAM,EAAE,KAAK,CAAC,eAAe,SAAS,CAAC,EAAE,2BAA2B,QAAQ,EAAE,CAAC,CAAC;QAChF,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,IAAI,QAAQ,KAAK,QAAQ,CAAC,GAAG,EAAE,CAAC;gBAC9B,MAAM,GAAG,WAAW,CAAC,kBAAkB,CACrC,yBAAyB,QAAQ,YAAY,SAAS,CAAC,EAAE,GAAG,EAC5D,SAAS,EACT,MAAM,CACP,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,oEAAoE;gBACpE,MAAM,oBAAoB,GAAG,YAAa,CAAC;gBAC3C,MAAM,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAC3C,kCAAkC,SAAS,CAAC,EAAE,GAAG,EACjD,oBAAoB,EACpB,MAAM,CACP,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAED;;;;;;;;OAQG;IACI,MAAM,CAAC,KAAK,CAAC,iCAAiC,CACnD,QAAyC,EACzC,MAAe,EACf,OAAiB,EACjB,QAAmB;QAEnB,MAAM,OAAO,GACX,QAAQ,KAAK,QAAQ,CAAC,GAAG;YACvB,CAAC,CAAC,qDAAqD;YACvD,CAAC,CAAC,wDAAwD,CAAC;QAE/D,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,4BAA4B,CAAC,CAAC,CAAC;YAClE,MAAM,EAAE,KAAK,CAAC,uCAAuC,OAAO,EAAE,CAAC,CAAC;YAChE,OAAO,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;YACnD,MAAM,EAAE,KAAK,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;QAC1C,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,kBAAkB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAExD,IAAI,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACtC,MAAM,EAAE,KAAK,CAAC,kDAAkD,kBAAkB,EAAE,CAAC,CAAC;YACtF,OAAO,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,EAAE,KAAK,CAAC,+BAA+B,OAAO,OAAO,kBAAkB,EAAE,CAAC,CAAC;QACjF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC;QAC9E,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,yCAAyC;QACzC,MAAM,UAAU,GAAG,EAAE,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;QAE5D,0EAA0E;QAC1E,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE;gBAC9B,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,qBAAqB,CAAC;gBACjD,MAAM,EAAE,4BAA4B;aACrC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAC1B,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBAClC,sEAAsE;oBACtE,cAAc,IAAI,KAAK,CAAC,MAAM,CAAC;oBAC/B,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,cAAc,GAAG,SAAS,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC5F,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAC;YACL,CAAC;YAED,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YAEhC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACjC,iDAAiD;gBACjD,IAAI,CAAC;oBACH,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;gBAChC,CAAC;gBAAC,MAAM,CAAC;oBACP,yBAAyB;gBAC3B,CAAC;gBACD,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACjB,OAAO,EAAE,IAAI,EAAE,CAAC;gBAChB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;gBAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;gBACnB,OAAO,EAAE,IAAI,EAAE,CAAC;gBAChB,OAAO,CAAC,kBAAkB,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,QAAgB;QACvD,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC7C,KAAK;iBACF,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE;gBAC1B,IAAI,IAAI,GAAG,EAAE,CAAC;gBACd,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBAC5B,IAAI,IAAI,KAAK,CAAC;gBAChB,CAAC,CAAC,CAAC;gBACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACtB,qFAAqF;oBACrF,qFAAqF;oBACrF,wEAAwE;oBACxE,oGAAoG;oBACpG,QAAQ;oBACR,MAAM,KAAK,GAAG,sDAAsD,CAAC;oBACrE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBAChC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBACpB,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,EAAE,CAAC,CAAC;oBACd,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CAAC;iBACD,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBACtB,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACI,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,WAAmB,EAAE,SAAkB,EAAE,MAAe;QAC5F,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC,CAAC;QACzE,IAAI,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAE1G,OAAO,GAAG,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,GAAG,WAAW,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAE/C,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC1B,CAAC,CAAC,0FAA0F,OAAO,2BAA2B,MAAM,aAAa;YACjJ,CAAC,CAAC,gBAAgB,OAAO,OAAO,MAAM,EAAE,CAAC;QAE7C,MAAM,EAAE,KAAK,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAC;QACnD,MAAM,WAAW,CAAC,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,QAAgB;QAC9C,MAAM,YAAY,GAAG,MAAM,WAAW,CAAC,eAAe,EAAE,CAAC;QACzD,IAAI,QAA4B,CAAC;QACjC,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;QAC9E,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,YAAY,CAAC,2BAA2B,CAAC,QAAQ,CAAC,CAAC;YAC9D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,6BAA6B,CAAC,CAAC,CAAC,CAAC;YACvF,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,YAAoB;QAC9D,IAAI,IAAI,GAAG,YAAY,CAAC;QACxB,IAAI,IAAI,GAAG,KAAK,CAAC;QAEjB,OAAO,CAAC,IAAI,EAAE,CAAC;YACb,MAAM,GAAG,GACP,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,2CAA2C,IAAI,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAC;YAEzG,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,WAAW,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;gBACnD,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;oBAClB,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,qCAAqC;gBACxD,CAAC;qBAAM,CAAC;oBACN,IAAI,GAAG,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,8DAA8D;gBAC9D,+DAA+D;gBAC/D,gEAAgE;gBAChE,IAAI,GAAG,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024, salesforce.com, inc.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
import select from '@inquirer/select';
|
|
8
|
+
import { confirm } from '@inquirer/prompts';
|
|
9
|
+
export class PromptUtils {
|
|
10
|
+
static async promptUserToSelectSite(sites) {
|
|
11
|
+
const choices = sites.map((site) => ({ value: site }));
|
|
12
|
+
const response = await select({
|
|
13
|
+
message: 'Select a site:',
|
|
14
|
+
choices,
|
|
15
|
+
});
|
|
16
|
+
return response;
|
|
17
|
+
}
|
|
18
|
+
static async promptUserToConfirmUpdate(siteName) {
|
|
19
|
+
return confirm({
|
|
20
|
+
message: `An updated site bundle is available for "${siteName}". Would you like to download and apply the update?`,
|
|
21
|
+
default: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/shared/prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,MAAM,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,MAAM,OAAO,WAAW;IACf,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,KAAe;QACxD,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC;YAC5B,OAAO,EAAE,gBAAgB;YACzB,OAAO;SACR,CAAC,CAAC;QAEH,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEM,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,QAAgB;QAC5D,OAAO,OAAO,CAAC;YACb,OAAO,EAAE,4CAA4C,QAAQ,qDAAqD;YAClH,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# summary
|
|
2
|
+
|
|
3
|
+
Preview a Lightning Experience app locally and in real-time, without deploying it.
|
|
4
|
+
|
|
5
|
+
# description
|
|
6
|
+
|
|
7
|
+
Use Local Dev (Beta) to see local changes to your app in a real-time preview that you don't have to deploy or manually refresh. To let you quickly iterate on your Lightning web components (LWCs) and pages, your app preview automatically refreshes when Local Dev detects source code changes.
|
|
8
|
+
|
|
9
|
+
When you edit these local files with Local Dev enabled, your org automatically reflects these changes.
|
|
10
|
+
|
|
11
|
+
- Basic HTML and CSS edits to LWCs
|
|
12
|
+
- JavaScript changes to LWCs that don't affect the component's public API
|
|
13
|
+
- Importing new custom LWCs
|
|
14
|
+
- Importing another instance of an existing LWC
|
|
15
|
+
|
|
16
|
+
To apply any other local changes not listed above, you must deploy them to your org using the `sf project deploy start` command.
|
|
17
|
+
|
|
18
|
+
When you make changes directly in your org (like saving new component properties), they're automatically deployed to your live app. To update your local version of the app with those changes, you must retrieve them from your org using the `sf project retrieve start` command.
|
|
19
|
+
|
|
20
|
+
To learn more about Local Dev enablement, considerations, and limitations, see the Lightning Web Components Developer Guide.
|
|
21
|
+
|
|
22
|
+
# flags.name.summary
|
|
23
|
+
|
|
24
|
+
Name of the Lightning Experience app to preview.
|
|
25
|
+
|
|
26
|
+
# flags.target-org.summary
|
|
27
|
+
|
|
28
|
+
Username or alias of the target org. Not required if the `target-org` configuration variable is already set.
|
|
29
|
+
|
|
30
|
+
# flags.device-type.summary
|
|
31
|
+
|
|
32
|
+
Type of device to display the app preview.
|
|
33
|
+
|
|
34
|
+
# flags.device-id.summary
|
|
35
|
+
|
|
36
|
+
ID of the mobile device to display the preview if device type is set to `ios` or `android`. The default value is the ID of the first available mobile device.
|
|
37
|
+
|
|
38
|
+
# error.username
|
|
39
|
+
|
|
40
|
+
Org must have a valid user
|
|
41
|
+
|
|
42
|
+
# error.identitydata
|
|
43
|
+
|
|
44
|
+
Couldn't find identity data while generating preview arguments
|
|
45
|
+
|
|
46
|
+
# error.identitydata.entityid
|
|
47
|
+
|
|
48
|
+
Couldn't find entity ID while generating preview arguments
|
|
49
|
+
|
|
50
|
+
# error.no-project
|
|
51
|
+
|
|
52
|
+
This command is required to run from within a Salesforce project directory. %s
|
|
53
|
+
|
|
54
|
+
# error.fetching.app-id
|
|
55
|
+
|
|
56
|
+
Unable to determine App Id for %s
|
|
57
|
+
|
|
58
|
+
# error.device.notfound
|
|
59
|
+
|
|
60
|
+
Unable to find device %s
|
|
61
|
+
|
|
62
|
+
# spinner.device.boot
|
|
63
|
+
|
|
64
|
+
Booting device %s
|
|
65
|
+
|
|
66
|
+
# spinner.cert.gen
|
|
67
|
+
|
|
68
|
+
Generating self-signed certificate
|
|
69
|
+
|
|
70
|
+
# spinner.extract.archive
|
|
71
|
+
|
|
72
|
+
Extracting archive
|
|
73
|
+
|
|
74
|
+
# spinner.download.preparing
|
|
75
|
+
|
|
76
|
+
Preparing to download
|
|
77
|
+
|
|
78
|
+
# spinner.downloading
|
|
79
|
+
|
|
80
|
+
Downloading
|
|
81
|
+
|
|
82
|
+
# trust.local.dev.server
|
|
83
|
+
|
|
84
|
+
Note: Your desktop browser requires additional configuration to trust the local development server. See the documentation for more details.
|
|
85
|
+
|
|
86
|
+
# certificate.installation.notice
|
|
87
|
+
|
|
88
|
+
To use local preview on your device, you have to install a self-signed certificate on it. If you previously set up a certificate for your device, you can skip this step.
|
|
89
|
+
|
|
90
|
+
# certificate.installation.skip.message
|
|
91
|
+
|
|
92
|
+
Do you want to skip this step
|
|
93
|
+
|
|
94
|
+
# certificate.installation.description
|
|
95
|
+
|
|
96
|
+
Before proceeding, install the self-signed certificate on your device. The certificate file is located at
|
|
97
|
+
|
|
98
|
+
`%s`
|
|
99
|
+
|
|
100
|
+
To install the certificate, follow these steps:
|
|
101
|
+
|
|
102
|
+
%s
|
|
103
|
+
|
|
104
|
+
# certificate.installation.steps.ios
|
|
105
|
+
|
|
106
|
+
1. Drag and drop the file onto your booted simulator.
|
|
107
|
+
2. Click `Allow` to proceed with downloading the configuration file.
|
|
108
|
+
3. Click `Close` and navigate to `Settings > General > VPN & Device Management > localhost`.
|
|
109
|
+
4. Click `Install` in the title bar, in the warning window, and on the install button.
|
|
110
|
+
5. In the `Profile Installed` view, confirm that the profile displays `Verified` and then click `Done`.
|
|
111
|
+
6. Navigate to `Settings > General > About > Certificate Trust Settings`.
|
|
112
|
+
7. Enable full trust for `localhost`.
|
|
113
|
+
8. In the resulting warning pop-up, click `Continue`.
|
|
114
|
+
|
|
115
|
+
# certificate.installation.steps.android
|
|
116
|
+
|
|
117
|
+
1. Drag and drop the file onto your booted emulator.
|
|
118
|
+
2. %s
|
|
119
|
+
3. Navigate to the certificate file from step 1. (It's usually located in `/sdcard/download`).
|
|
120
|
+
4. Follow the on-screen instructions to install it.
|
|
121
|
+
5. Click `User credentials` under `Credential storage` and verify that your certificate is listed there.
|
|
122
|
+
6. Click `Trusted credentials` under `Credential storage`. Then click `USER` and verify that page lists your certificate.
|
|
123
|
+
|
|
124
|
+
# certificate.installation.steps.android.nav-target-api-24-25
|
|
125
|
+
|
|
126
|
+
Navigate to `Settings > Security` and click `Install from SD card` under `Credential storage`.
|
|
127
|
+
|
|
128
|
+
# certificate.installation.steps.android.nav-target-api-26-27
|
|
129
|
+
|
|
130
|
+
Navigate to `Settings > Security & Location > Encryption & credentials` and click `Install from SD card` under `Credential storage`.
|
|
131
|
+
|
|
132
|
+
# certificate.installation.steps.android.nav-target-api-28
|
|
133
|
+
|
|
134
|
+
Navigate to `Settings > Security & Location > Advanced > Encryption & credentials` and click `Install from SD card` under `Credential storage`.
|
|
135
|
+
|
|
136
|
+
# certificate.installation.steps.android.nav-target-api-29
|
|
137
|
+
|
|
138
|
+
Navigate to `Settings > Security > Encryption & credentials` and click `Install from SD card` under `Credential storage`.
|
|
139
|
+
|
|
140
|
+
# certificate.installation.steps.android.nav-target-api-30-32
|
|
141
|
+
|
|
142
|
+
Navigate to `Settings > Security > Encryption & credentials` and click `Install a certificate` under `Credential storage`. Click `CA certificate`, and then click `Install anyway`.
|
|
143
|
+
|
|
144
|
+
# certificate.installation.steps.android.nav-target-api-33
|
|
145
|
+
|
|
146
|
+
Navigate to `Settings > Security > More security settings > Encryption & credentials` and click `Install a certificate` under `Credential storage`. Click `CA certificate`, and then click `Install anyway`.
|
|
147
|
+
|
|
148
|
+
# certificate.installation.steps.android.nav-target-api-34-up
|
|
149
|
+
|
|
150
|
+
Navigate to `Settings > Security & Privacy > More security & privacy > Encryption & credentials` and click `Install a certificate` under `Credential storage`. Click `CA certificate`, and then click `Install anyway`.
|
|
151
|
+
|
|
152
|
+
# certificate.waiting
|
|
153
|
+
|
|
154
|
+
After you install the certificate, press any key to continue...
|
|
155
|
+
|
|
156
|
+
# mobileapp.notfound
|
|
157
|
+
|
|
158
|
+
%s isn't installed on your device.
|
|
159
|
+
|
|
160
|
+
# mobileapp.download
|
|
161
|
+
|
|
162
|
+
%s isn't installed on your device. Do you want to download and install it?
|
|
163
|
+
|
|
164
|
+
# examples
|
|
165
|
+
|
|
166
|
+
- Preview the default app for the target org "myOrg" in a desktop environment:
|
|
167
|
+
<%= config.bin %> <%= command.id %> --target-org myOrg
|
|
168
|
+
- Preview the app "myApp" for the target org "myOrg" in a desktop environment:
|
|
169
|
+
<%= config.bin %> <%= command.id %> --name MyApp --target-org myOrg --device-type desktop
|
|
170
|
+
- Preview the default app for target org "myOrg" on an iOS device:
|
|
171
|
+
<%= config.bin %> <%= command.id %> --target-org myOrg --device-type ios --device-id "iPhone 15 Pro Max"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# summary
|
|
2
|
+
|
|
3
|
+
Preview an Experience Builder site locally and in real-time, without deploying it.
|
|
4
|
+
|
|
5
|
+
# description
|
|
6
|
+
|
|
7
|
+
Enable Local Dev to see local changes to your site in a real-time preview that you don't have to deploy or manually refresh. To let you quickly iterate on your Lightning web components (LWCs) and pages, your site preview automatically refreshes when Local Dev detects source code changes.
|
|
8
|
+
|
|
9
|
+
When you edit these local files with Local Dev enabled, your org automatically reflects these changes.
|
|
10
|
+
|
|
11
|
+
- Basic HTML and CSS edits to LWCs
|
|
12
|
+
- JavaScript changes to LWCs that don't affect the component's public API
|
|
13
|
+
- Importing new custom LWCs
|
|
14
|
+
- Importing another instance of an existing LWC
|
|
15
|
+
|
|
16
|
+
To apply any other local changes not listed above, you must deploy them to your org using the `sf project deploy start` command. Then republish your site and restart the server for the Local Dev experience.
|
|
17
|
+
|
|
18
|
+
For more considerations and limitations, see the Lightning Web Components Developer Guide.
|
|
19
|
+
|
|
20
|
+
# flags.name.summary
|
|
21
|
+
|
|
22
|
+
Name of the Experience Builder site to preview. It has to match a site name from the current org.
|
|
23
|
+
|
|
24
|
+
# flags.target-org.summary
|
|
25
|
+
|
|
26
|
+
Username or alias of the target org. Not required if the `target-org` configuration variable is already set.
|
|
27
|
+
|
|
28
|
+
# flags.debug.summary
|
|
29
|
+
|
|
30
|
+
Enable Node Inspector to debug server-side rendering.
|
|
31
|
+
|
|
32
|
+
# examples
|
|
33
|
+
|
|
34
|
+
- Preview the site "Partner Central" from the org "myOrg":
|
|
35
|
+
<%= config.bin %> <%= command.id %> --name "Partner Central" --target-org myOrg
|
|
36
|
+
- Preview the site "Partner Central" from the org "myOrg" with Node Inspector enabled:
|
|
37
|
+
<%= config.bin %> <%= command.id %> --name "Partner Central" --target-org myOrg --debug
|