Skip to content

Commit 86db846

Browse files
committed
feat: get-latest flag / update site setup / track download time / tmp use API with published state
1 parent 94108b3 commit 86db846

File tree

2 files changed

+41
-18
lines changed

2 files changed

+41
-18
lines changed

src/commands/lightning/dev/site.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,23 @@ export default class LightningDevSite extends SfCommand<void> {
6060
const selectedSite = new ExperienceSite(org, siteName);
6161
let siteZip: string | undefined;
6262

63-
// TODO if locally cached site is 252 site, we should trigger an update also
63+
// If the site is not setup / is not based on the current release / or get-latest is requested ->
64+
// generate and download a new site bundle from the org based on latest builder metadata
6465
if (!selectedSite.isSiteSetup() || getLatest) {
65-
this.log(`[local-dev] initializing: '${siteName}'`);
66+
const startTime = Date.now();
67+
this.log(`[local-dev] Initializing: ${siteName}`);
6668
this.spinner.start('[local-dev] Downloading site (this may take a few minutes)');
6769
siteZip = await selectedSite.downloadSite();
6870

6971
// delete oldSitePath recursive
70-
this.spinner.status = '[local-dev] cleaning up site cache';
7172
const oldSitePath = selectedSite.getExtractDirectory();
7273
if (fs.existsSync(oldSitePath)) {
7374
fs.rmSync(oldSitePath, { recursive: true });
7475
}
75-
this.spinner.stop('[local-dev] setup complete');
76+
const endTime = Date.now();
77+
const duration = (endTime - startTime) / 1000; // Convert to seconds
78+
this.spinner.stop('done.');
79+
this.log(`[local-dev] Site setup completed in ${duration.toFixed(2)} seconds.`);
7680
}
7781

7882
this.log(`[local-dev] launching browser preview for: ${siteName}`);
@@ -96,11 +100,13 @@ export default class LightningDevSite extends SfCommand<void> {
96100
// Environment variable used to setup the site rather than setup & start server
97101
if (process.env.SETUP_ONLY === 'true') {
98102
await setupDev(startupParams);
103+
this.log('[local-dev] setup complete!');
99104
} else {
100105
await expDev(startupParams);
101106
this.log('[local-dev] watching for file changes... (CTRL-C to stop)');
102107
}
103108
} catch (e) {
109+
this.spinner.stop('failed.');
104110
this.log('Local Development setup failed', e);
105111
}
106112
}

src/shared/experience/expSite.ts

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import axios from 'axios';
1212
export type SiteMetadata = {
1313
bundleName: string;
1414
bundleLastModified: string;
15+
coreVersion: string;
1516
};
1617

1718
export type SiteMetadataCache = {
@@ -97,7 +98,10 @@ export class ExperienceSite {
9798

9899
// Is the site extracted locally
99100
public isSiteSetup(): boolean {
100-
return fs.existsSync(path.join(this.getExtractDirectory(), 'ssr.js'));
101+
if (fs.existsSync(path.join(this.getExtractDirectory(), 'ssr.js'))) {
102+
return this.getLocalMetadata()?.coreVersion === '254';
103+
}
104+
return false;
101105
}
102106

103107
// Is the static resource available on the server
@@ -155,6 +159,7 @@ export class ExperienceSite {
155159
this.metadataCache.remoteMetadata = {
156160
bundleName: staticResource.Name,
157161
bundleLastModified: staticResource.LastModifiedDate,
162+
coreVersion: '254',
158163
};
159164
return this.metadataCache.remoteMetadata;
160165
}
@@ -188,14 +193,15 @@ export class ExperienceSite {
188193
* @returns path of downloaded site zip
189194
*/
190195
public async downloadSite(): Promise<string> {
196+
let retVal;
191197
if (process.env.STATIC_MODE !== 'true') {
192198
// Use sites API to download the site bundle on demand
193-
const retVal = await this.downloadSiteApi();
194-
return retVal;
199+
retVal = await this.downloadSiteApi();
195200
} else {
196-
const retVal = await this.downloadSiteStaticResources();
197-
return retVal;
201+
// This is for testing purposes only now - not an officially supported external path
202+
retVal = await this.downloadSiteStaticResources();
198203
}
204+
return retVal;
199205
}
200206

201207
/**
@@ -219,26 +225,27 @@ export class ExperienceSite {
219225
const metadata = {
220226
bundleName: theSite.Name,
221227
bundleLastModified: theSite.LastModifiedDate,
228+
coreVersion: '254',
222229
};
223230
const siteId = theSite.Id;
224231
const siteIdMinus3 = siteId.substring(0, siteId.length - 3);
225232
const accessToken = conn.accessToken;
226233
const instanceUrl = conn.instanceUrl; // Org URL
227234
if (!accessToken) {
228-
throw new SfError(`Error occurred downloading your site: ${this.siteDisplayName}`);
235+
throw new SfError(`Invalid access token, unable to download site: ${this.siteDisplayName}`);
229236
}
230237
const resourcePath = this.getSiteZipPath(metadata);
231238
try {
232239
// Limit API to published sites for now until we have a patch for the issues with unpublished sites
233-
// TODO use preview api when fixed
234-
const apiUrl = `${instanceUrl}/services/data/v63.0/sites/${siteIdMinus3}/preview`;
240+
// TODO switch api back to preview mode after issues are addressed
241+
const apiUrl = `${instanceUrl}/services/data/v63.0/sites/${siteIdMinus3}/preview?published`;
235242
const response = await axios.get(apiUrl, {
236243
headers: {
237244
Authorization: `Bearer ${accessToken}`,
238245
},
239246
responseType: 'stream',
240247
});
241-
fs.mkdirSync(this.getSiteDirectory(), { recursive: true });
248+
if (response.statusText) fs.mkdirSync(this.getSiteDirectory(), { recursive: true });
242249

243250
const fileStream = fs.createWriteStream(resourcePath);
244251
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
@@ -249,9 +256,20 @@ export class ExperienceSite {
249256
fileStream.on('error', reject);
250257
});
251258
this.saveMetadata(metadata);
252-
} catch (e) {
253-
// eslint-disable-next-line no-console
254-
console.error('failed to download site', e);
259+
} catch (error) {
260+
// Handle axios errors
261+
if (axios.isAxiosError(error)) {
262+
if (error.response) {
263+
// Server responded with non-200 status
264+
throw new SfError(
265+
`Failed to download site: Server responded with status ${error.response.status} - ${error.response.statusText}`
266+
);
267+
} else if (error.request) {
268+
// Request was made but no response received
269+
throw new SfError('Failed to download site: No response received from server');
270+
}
271+
}
272+
throw new SfError(`Failed to download site: ${this.siteDisplayName}`);
255273
}
256274

257275
// Save the site's metadata
@@ -261,7 +279,6 @@ export class ExperienceSite {
261279
// Deprecated. Only used internally now for testing. Customer sites will no longer be stored in static resources
262280
// and are only available via the API.
263281
public async downloadSiteStaticResources(): Promise<string> {
264-
// This is for testing purposes only now - not an officially supported external path
265282
const remoteMetadata = await this.getRemoteMetadata();
266283
if (!remoteMetadata) {
267284
throw new SfError(`No published site found for: ${this.siteDisplayName}`);
@@ -300,7 +317,7 @@ export class ExperienceSite {
300317
}
301318
}
302319

303-
// TODO
320+
// TODO need to get auth tokens for the builder preview also once API issues are addressed
304321
private async getNewSidToken(networkId: string): Promise<string> {
305322
// Get the connection and access token from the org
306323
const conn = this.org.getConnection();

0 commit comments

Comments
 (0)